CMAKE - Debug / Crossbuild? - c++

Ok im using CMake to build C++ under Linux, for an ARM target. I have a #DEFINE in one of my .h files called DEBUG. If set, I would like for various methods for tracing over serial will be added into the build. I would like to be able to do this by doing e.g. "make debug" to build with this #DEFINE set, and have normal "make" build without setting it. Is this possible?
Also, it it possible to be able to specify a target to CMake? As I have 2 CMakeLists.txt right now, one for x86, and one for Armel (with different options such as to build with debug information on x86, compared to the ARM, which wants a stripped, size-optimised binary).

It seems you have two questions. One about debug, you can use CMAKE_BUILD_TYPE to separate your debug/release setting, and use $ cmake --build . --config Release or $ cmake --build . --config Debug to compile.
For the second, about cross build, it's possible. You can do like these:
According to this guide write configure files for arm and x86 respectively to set compiler, archiver, etc.. Suppose name the one of x86 as *config_x86.cmake* and *config_arm.cmake* for arm.
Define a cmake macro, such as *MY_TARGET*. And add the following code before the project command,
if (${MY_TARGET} STREQUAL "x86")
include(config_x86.cmake REQUIRED)
elseif (${MY_TARGET} STREQUAL "arm")
include(config_arm.cmake REQUIRED)
endif ()
Then generate your project files like this
$ cmake -DMY_TARGET=x86 "your code dir"

Debug and release builds are supported out of the box by CMake.
Say the top level CMakeLists.txt for your project is in ~/project/foobar, you can create separate debug and a release builds by doing this:
mkdir ~/project/build
mkdir ~/project/build/foobar-debug
cd ~/project/build/foobar-debug
cmake -DCMAKE_BUILD_TYPE:STRING=Debug ~/project/foobar
mkdir ~/project/build/foobar-rel
cd ~/project/build/foobar-rel
cmake -DCMAKE_BUILD_TYPE:STRING=Release ~/project/foobar
What's even better is that CMake supports not just the standard debug/release targets you're probably used to, but it supports minimum sized release, as well as release with debug info. See the other options for CMAKE_BUILD_TYPE at:
http://cmake.org/Wiki/CMake_Useful_Variables

Regarding definitions, you can do what you want like this in your CMakeLists.txt files:
if( CMAKE_BUILD_TYPE MATCHES "[Dd][Ee][Bb][Uu][Gg]" )
message( "INFO: DEBUG BUILD" )
# for debug type builds, turn on verbose makefiles
SET(CMAKE_VERBOSE_MAKEFILE ON)
# Tell other CMake files that we're doing a debug build
SET( DEBUG_BUILD 1 )
# Tell C/C++ that we're doing a debug build
ADD_DEFINITIONS( -DDEBUG )
endif()
if( CMAKE_BUILD_TYPE MATCHES "[Rr][Ee][Ll][Ee][Aa][Ss][Ee]" )
message( "INFO: RELEASE BUILD" )
endif()
CMake does not like supporting two targets, in other words two toolchains, in the same build tree. There's really no need for this anyway. Definitely use out-of-tree builds with one build tree for each of your possible targets. Something like this:
cd /path/to/x86_build
cmake /path/to/src/x86/CMakeLists.txt
cd /path/to/Armel_build
cmake /path/to/src/Armel/CMakeLists.txt

Related

How to properly build configuration without debug info in Cmake? | Cmake is ignoring CMAKE_BUILD_TYPE=RELEASE

I am trying to cross-compile a "Release" version of C++ based application using cmake and make. Its for Makefile based generators. But, somehow passing the command -DCMAKE_BUILD_TYPE=RELEASE is ignored by the cmake. I have also added below commands to CMakeLists.txt file.
add_compile_options(
$<$<CONFIG:DEBUG>:-g3>
$<$<CONFIG:DEBUG>:-Og>
$<$<CONFIG:RELEASE>:-O3>
)
add_compile_definitions(
$<$<CONFIG:RELEASE>:RELEASE>
)
add_link_options($<$<CONFIG:RELEASE>:RELEASE>)
In the CMakeCache.txt file I could see CMAKE_BUILD_TYPE:STRING=RELEASE is set. I am calling below commands to cross-compile:
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=RELEASE ..
make
Configuration is successful and make is also successful. But generated file is with debug info. I want to generate without debug info(Release config)
ELF 32-bit LSB shared object, ARM, EABI5 version 1 (GNU/Linux), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, BuildID[sha1]=cc8fff.., for GNU/Linux 3.2.0, with debug_info, not stripped
My goal is to strip this debug info.
I also tried with add_custom_commands to strip binary as part of POST_BUILD using CMAKE_STRIP. In the CMakeLists.txt
add_custom_command(
TARGET "${TARGET_NAME}" POST_BUILD
DEPENDS "${TARGET_NAME}"
COMMAND $<$<CONFIG:RELEASE>:${CMAKE_STRIP}>
ARGS --strip-all $<TARGET_FILE:${TARGET}>
)
This is added after add_executable section. But while configuration I am getting below error from cmake
add_custom_command Wrong syntax. A TARGET and OUTPUT can not both be specified.
Can anyone please let me know what is the correct way to generate Release version of binary using cmake?
Your help will be much appreciated.
Thanks in advance.
P.S: I am working on Ubuntu machine. Please let me know if any info is missing here.

Configure cmake to choose compiler based on environment

My current project directory looks like
myproject
/-build
/-include
/-somefile.h
/-somefile2.h
/-myproject.cpp
/-CMakeLists.txt
and current CMakeLists.txt looks like :
cmake_minimum_required (VERSION 3.1)
project (myproject)
add_executable(myproject myproject.cpp)
set(CMAKE_BINARY_DIR ${CMAKE_SOURCE_DIR}/build)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
set(PROJECT_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include)
include_directories("${PROJECT_INCLUDE_DIR}")
include_directories("${PROJECT_SOURCE_DIR}")
I want to build this project in both x64Windows and x64Linux environment while keeping single cmake file. Currently I have Visual Studio 13 CE in Win and gcc in Linux. Is it possible that Cmake could intelligently choose the correct compiler depending on OS? And what changes should I make to CMakeLists for that?
I'm using normal stuff like STL and vanilla C++ ( no os dependent libraries) if that matters. Thanks
You want to add conditional code for each compiler:
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
# Set the C++ and linker flags to GCC specifics here.
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# Set the C++ and linker flags to VC++ specifics here.
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# Set the C++ and linker flags to Clang specifics here.
elseif()
The right compiler is set automatically at least on linux. On windows I don't know. However you could always overwrite the selected compiler by the environment variables CC and CXX. This changes the cmake configuration. The changes will only affect new build configurations. So don't forget to delete your old one before selecting a new compiler.
Edit: The compiler must be of course in your PATH variable. Otherwise CMake will not find it correctly.

What is the default build configuration of cmake

In this answer, it says Debug is the default cmake build configuration.
But I have a different observation:
I have following in my CMakeLists.txt to choose debug and release versions of a lib according to the current build configuration.
target_link_libraries(MyApp debug Widgets_d)
target_link_libraries(MyApp optimized Widgets)
It seems that when I invoke cmake without sepcifying -DCMAKE_BUILD_TYPE flag, Widgets is used instead of Widgets_d (When I delete Widgets and try to build, make complains that lib is not there). So that means by default the build configuration is optimized, not debug.
So what actually is the default build configuration? If it is debug, what could be wrong with my CMakelists.txt?
target_link_libraries with optimized keyword corresponds to all configurations, which are not debug.
Try adding message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") to your CMakeLists.txt to see the actual build type (I suppose it should be empty).
If depends on whether you are using a single-configuration generator (Makefiles) or a multi-configuration generator (Visual Studio, XCode).
The link cited in the question is about a multi-configuration generator. When using a multi-configuration generator, the configuration variable CMAKE_BUILD_TYPE is ignored. To select the configuration to build, cmake allows the switch --config, and this defaults to Debug. So
cmake --build .
in a multi-configuration project builds a Debug version.
However, when using a single-configuration generator, the switch --config is ignored. Only the configuration variable CMAKE_BUILD_TYPE is used to determine the build type, and this defaults to Release.
More background info on single- and multiconfiguration-generators in this answer.

How to change the executable output directory for Win32 builds, in CMake?

My problem is as such :
I'm developing a small parser using Visual Studio 2010.
I use CMake as a build configuration tool.
But I find the default executable building behaviour, inconvenient.
What I want is, have my final program be located in :
E:/parsec/bin/<exe-name>.<build-type>.exe
rather than
E:/parsec/bin/<build-type>/<exe-name>.exe
How would you do that using CMake ?
There are several options:
Copy the executable after building
Customizing the output-directory for your executable(s)
Copy the executable after building
After a succesful build you can copy the executable (see Beginners answer), but perhaps it is nicer to use an install target:
Use the install command to specify targets (executables, libraries, headers, etc.) which will be copied to the CMAKE_INSTALL_PREFIX directory. You can specify the CMAKE_INSTALL_PREFIX on the commandline of cmake (or in the cmake GUI).
Customizing the output-directory for your executable(s)
Warning: It is not advised to set absolute paths directly in your cmakelists.txt.
Use set_target_properties to customize the RUNTIME_OUTPUT_DIRECTORY
set_target_properties( yourexe PROPERTIES RUNTIME_OUTPUT_DIRECTORY E:/parsec/bin/ )
As an alternative, modifying the CMAKE_RUNTIME_OUTPUT_DIRECTORY allows you to specify this for all targets in the cmake project. Take care that you modify the CMAKE_LIBRARY_OUTPUT_DIRECTORY as well when you build dlls.
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin )
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
Additional info: Take a look at these questions:
In CMake, how do I work around the Debug and Release directories Visual Studio 2010 tries to add?
CMake : Changing name of Visual Studio and Xcode exectuables depending on configuration in a project generated by CMake
How to not add Release or Debug to output path?
Most probably you will need to copy your binaries with a separate custom command which would look similar to this one:
add_custom_command(target your_target_name
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${EXAMPLE_BIN_NAME} ${PROJECT_BINARY_DIR}/.
)

Debug vs Release in CMake

In a GCC compiled project,
How do I run CMake for each target type (debug/release)?
How do I specify debug and release C/C++ flags using CMake?
How do I express that the main executable will be compiled with g++ and one nested library with gcc?
With CMake, it's generally recommended to do an "out of source" build. Create your CMakeLists.txt in the root of your project. Then from the root of your project:
mkdir Release
cd Release
cmake -DCMAKE_BUILD_TYPE=Release ..
make
And for Debug (again from the root of your project):
mkdir Debug
cd Debug
cmake -DCMAKE_BUILD_TYPE=Debug ..
make
Release / Debug will add the appropriate flags for your compiler. There are also RelWithDebInfo and MinSizeRel build configurations.
You can modify/add to the flags by specifying a toolchain file in which you can add CMAKE_<LANG>_FLAGS_<CONFIG>_INIT variables, e.g.:
set(CMAKE_CXX_FLAGS_DEBUG_INIT "-Wall")
set(CMAKE_CXX_FLAGS_RELEASE_INIT "-Wall")
See CMAKE_BUILD_TYPE for more details.
As for your third question, I'm not sure what you are asking exactly. CMake should automatically detect and use the compiler appropriate for your different source files.
A lot of the answers here are out of date/bad. So I'm going to attempt to answer it better. Granted I'm answering this question in 2020, so it's expected things would change.
How do I run CMake for each target type (debug/release)?
First off Debug/Release are called configurations in cmake (nitpick).
If you are using a single configuration generator (Ninja/Unix-Makefiles) you must specify the CMAKE_BUILD_TYPE.
Like this:
# Configure the build
cmake -S . -B build/ -D CMAKE_BUILD_TYPE=Debug
# Actually build the binaries
cmake --build build/
# Configure a release build
cmake -S . -B build/ -D CMAKE_BUILD_TYPE=Release
# Build release binaries
cmake --build build/
For multi-configuration generators it's slightly different (Ninja Multi-Config, Visual Studio)
# Configure the build
cmake -S . -B build
# Build debug binaries
cmake --build build --config Debug
# Build release binaries
cmake --build build --config Release
If you are wondering why this is necessary it's because cmake isn't a build system. It's a meta-build system (IE a build system that build's build systems). This is basically the result of handling build systems that support multiple-configurations in 1 build. If you'd like a deeper understanding I'd suggest reading a bit about cmake in Craig Scott's book "Professional CMake: A Practical Guide
How do I specify debug and release C/C++ flags using CMake?
The modern practice is to use target's and properties.
Here is an example:
add_library(foobar)
# Add this compile definition for debug builds, this same logic works for
# target_compile_options, target_link_options, etc.
target_compile_definitions(foobar PRIVATE
$<$<CONFIG:Debug>:
FOOBAR_DEBUG=1
>
)
NOTE: How I'm using generator expressions to specify the configuration!
Using CMAKE_BUILD_TYPE will result in bad builds for any multi-configuration generator!
Further more sometimes you need to set things globally and not just for one target.
Use add_compile_definitions, add_compile_options, etc. Those functions support generator expressions. Don't use old style cmake unless you have to (that path is a land of nightmares)
How do I express that the main executable will be compiled with g++ and one nested library with gcc?
Your last question really doesn't make sense.
For debug/release flags, see the CMAKE_BUILD_TYPE variable (you pass it as cmake -DCMAKE_BUILD_TYPE=value). It takes values like Release, Debug, etc.
https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/Useful-Variables#compilers-and-tools
cmake uses the extension to choose the compiler, so just name your files .c.
You can override this with various settings:
For example:
set_source_files_properties(yourfile.c LANGUAGE CXX)
Would compile .c files with g++. The link above also shows how to select a specific compiler for C/C++.
Instead of manipulating the CMAKE_CXX_FLAGS strings directly (which could be done more nicely using string(APPEND CMAKE_CXX_FLAGS_DEBUG " -g3") btw), you can use add_compile_options:
add_compile_options(
"-Wall" "-Wpedantic" "-Wextra" "-fexceptions"
"$<$<CONFIG:DEBUG>:-O0;-g3;-ggdb>"
)
This would add the specified warnings to all build types, but only the given debugging flags to the DEBUG build. Note that compile options are stored as a CMake list, which is just a string separating its elements by semicolons ;.
// CMakeLists.txt : release
set(CMAKE_CONFIGURATION_TYPES "Release" CACHE STRING "" FORCE)
// CMakeLists.txt : debug
set(CMAKE_CONFIGURATION_TYPES "Debug" CACHE STRING "" FORCE)
If you want to build a different configuration without regenerating if using you can also run cmake --build {$PWD} --config <cfg> For multi-configuration tools, choose <cfg> ex. Debug, Release, MinSizeRel, RelWithDebInfo
https://cmake.org/cmake/help/v2.8.11/cmake.html#opt%3a--builddir