CMake provides variables such as CMAKE_<LANG>_FLAGS_INIT to allow you to set compiler flags in a toolchain file, but I don't know of an equivalent for setting preprocessor definitions. In fact, CMake doesn't really seem to distinguish between preprocessor flags an compiler flags.
What is the "correct", or "supported" way to set preprocessor macro definitions in a toolchain file? Is it acceptable to call add_compile_definitions(), should I include them in CMAKE_C_FLAGS_INIT, or does it go against some CMake philosophy to even set them in the toolchain file at all?
Can I call add_compile_definitions in a toolchain file?
Sure, it's equivalent to string(APPEND CMAKE_C_FLAGS.
What is the "correct", or "supported" way to set preprocessor macro definitions in a toolchain file? Is it acceptable to call add_compile_definitions(), should I include them in CMAKE_C_FLAGS_INIT, or does it go against some CMake philosophy to even set them in the toolchain file at all?
It's best to set *_INIT variables from toolchain file, and also put there any definitions that you want. It's in the doc
https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_FLAGS_INIT.html :
This variable is meant to be set by a toolchain file
In practice, use:
string(APPEND CMAKE_${lang}_FLAGS_INIT " your_flag")
Examples from cmake:
$ cd /usr/share/cmake/Modules
$ grep _FLAGS_INIT -r .
./Compiler/ARMCC.cmake: string(APPEND CMAKE_${lang}_FLAGS_INIT " ")
./Compiler/ARMClang.cmake: string(APPEND CMAKE_${lang}_FLAGS_INIT " -march=${CMAKE_SYSTEM_ARCH}")
./Compiler/ARMClang.cmake: string(APPEND CMAKE_${lang}_FLAGS_INIT " -mcpu=${CMAKE_SYSTEM_PROCESSOR}")
./Compiler/Absoft-Fortran.cmake:string(APPEND CMAKE_Fortran_FLAGS_INIT " ")
./Compiler/Bruce-C.cmake:string(APPEND CMAKE_C_FLAGS_INIT " -D__CLASSIC_C__")
./Compiler/Fujitsu.cmake: string(APPEND CMAKE_${lang}_FLAGS_INIT " ")
./Platform/Android-Common.cmake: string(APPEND CMAKE_${lang}_FLAGS_INIT " -stdlib=libstdc++")
./Platform/Android-Common.cmake: string(APPEND CMAKE_${lang}_FLAGS_INIT " -stdlib=libc++")
./Platform/Android-Common.cmake: string(APPEND CMAKE_${lang}_FLAGS_INIT " -stdlib=libc++")
./Platform/ARTOS-GNU-C.cmake:string(APPEND CMAKE_C_FLAGS_INIT " -DARTOS -Xp -+")
....
See the Bruce-C.cmake example above.
The toolchain files usually set up the environment and the flags needed for a specific target. So it is acceptable to add compile definitions required for such targets.
Related
I am using the arm-linux-androideabi-g++ compiler. When I try to compile a simple "Hello, World!" program it compiles fine. When I test it by adding a simple exception handling in that code it works too (after adding -fexceptions .. I guess it is disabled by default).
This is for an Android device, and I only want to use CMake, not ndk-build.
For example - first.cpp
#include <iostream>
using namespace std;
int main()
{
try
{
}
catch (...)
{
}
return 0;
}
./arm-linux-androideadi-g++ -o first-test first.cpp -fexceptions
It works with no problem...
The problem ... I am trying to compile the file with a CMake file.
I want to add the -fexceptions as a flag. I tried with
set (CMAKE_EXE_LINKER_FLAGS -fexceptions ) or set (CMAKE_EXE_LINKER_FLAGS "fexceptions" )
and
set ( CMAKE_C_FLAGS "fexceptions")
It still displays an error.
Note: Given CMake evolution since this was answer was written in 2012, most of the suggestions here are now outdated/deprecated and have better alternatives.
Suppose you want to add those flags (better to declare them in a constant):
SET(GCC_COVERAGE_COMPILE_FLAGS "-fprofile-arcs -ftest-coverage")
SET(GCC_COVERAGE_LINK_FLAGS "-lgcov")
There are several ways to add them:
The easiest one (not clean, but easy and convenient, and works only for compile flags, C & C++ at once):
add_definitions(${GCC_COVERAGE_COMPILE_FLAGS})
Appending to corresponding CMake variables:
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}")
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}")
Using target properties, cf. doc CMake compile flag target property and need to know the target name.
get_target_property(TEMP ${THE_TARGET} COMPILE_FLAGS)
if(TEMP STREQUAL "TEMP-NOTFOUND")
SET(TEMP "") # Set to empty string
else()
SET(TEMP "${TEMP} ") # A space to cleanly separate from existing content
endif()
# Append our values
SET(TEMP "${TEMP}${GCC_COVERAGE_COMPILE_FLAGS}" )
set_target_properties(${THE_TARGET} PROPERTIES COMPILE_FLAGS ${TEMP} )
Right now I use method 2.
In newer versions of CMake you can set compiler and linker flags for a single target with target_compile_options and target_link_libraries respectively (yes, the latter sets linker options too):
target_compile_options(first-test PRIVATE -fexceptions)
The advantage of this method is that you can control propagation of options to other targets that depend on this one via PUBLIC and PRIVATE.
As of CMake 3.13 you can also use target_link_options to add linker options which makes the intent more clear.
Try setting the variable CMAKE_CXX_FLAGS instead of CMAKE_C_FLAGS:
set (CMAKE_CXX_FLAGS "-fexceptions")
The variable CMAKE_C_FLAGS only affects the C compiler, but you are compiling C++ code.
Adding the flag to CMAKE_EXE_LINKER_FLAGS is redundant.
The preferred way to specify toolchain-specific options is using CMake's toolchain facility. This ensures that there is a clean division between:
instructions on how to organise source files into targets -- expressed in CMakeLists.txt files, entirely toolchain-agnostic; and
details of how certain toolchains should be configured -- separated into CMake script files, extensible by future users of your project, scalable.
Ideally, there should be no compiler/linker flags in your CMakeLists.txt files -- even within if/endif blocks. And your program should build for the native platform with the default toolchain (e.g. GCC on GNU/Linux or MSVC on Windows) without any additional flags.
Steps to add a toolchain:
Create a file, e.g. arm-linux-androideadi-gcc.cmake with global toolchain settings:
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
set(CMAKE_CXX_FLAGS_INIT "-fexceptions")
(You can find an example Linux cross-compiling toolchain file here.)
When you want to generate a build system with this toolchain, specify the CMAKE_TOOLCHAIN_FILE parameter on the command line:
mkdir android-arm-build && cd android-arm-build
cmake -DCMAKE_TOOLCHAIN_FILE=$(pwd)/../arm-linux-androideadi-gcc.cmake ..
(Note: you cannot use a relative path.)
Build as normal:
cmake --build .
Toolchain files make cross-compilation easier, but they have other uses:
Hardened diagnostics for your unit tests.
set(CMAKE_CXX_FLAGS_INIT "-Werror -Wall -Wextra -Wpedantic")
Tricky-to-configure development tools.
# toolchain file for use with gcov
set(CMAKE_CXX_FLAGS_INIT "--coverage -fno-exceptions -g")
Enhanced safety checks.
# toolchain file for use with gdb
set(CMAKE_CXX_FLAGS_DEBUG_INIT "-fsanitize=address,undefined -fsanitize-undefined-trap-on-error")
set(CMAKE_EXE_LINKER_FLAGS_INIT "-fsanitize=address,undefined -static-libasan")
You can also add linker flags to a specific target using the LINK_FLAGS property:
set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS " ${flag}")
If you want to propagate this change to other targets, you can create a dummy target to link to.
This worked for me when I needed a precompile definition named "NO_DEBUG":
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -DNO_DEBUG")
Then from code
#ifdef NO_DEBUG
.....
With CMake 3.4+, APPEND can be used with the string command to add flags.
string(APPEND CMAKE_EXE_LINKER_FLAGS " -fexceptions")
I am using the arm-linux-androideabi-g++ compiler. When I try to compile a simple "Hello, World!" program it compiles fine. When I test it by adding a simple exception handling in that code it works too (after adding -fexceptions .. I guess it is disabled by default).
This is for an Android device, and I only want to use CMake, not ndk-build.
For example - first.cpp
#include <iostream>
using namespace std;
int main()
{
try
{
}
catch (...)
{
}
return 0;
}
./arm-linux-androideadi-g++ -o first-test first.cpp -fexceptions
It works with no problem...
The problem ... I am trying to compile the file with a CMake file.
I want to add the -fexceptions as a flag. I tried with
set (CMAKE_EXE_LINKER_FLAGS -fexceptions ) or set (CMAKE_EXE_LINKER_FLAGS "fexceptions" )
and
set ( CMAKE_C_FLAGS "fexceptions")
It still displays an error.
Note: Given CMake evolution since this was answer was written in 2012, most of the suggestions here are now outdated/deprecated and have better alternatives.
Suppose you want to add those flags (better to declare them in a constant):
SET(GCC_COVERAGE_COMPILE_FLAGS "-fprofile-arcs -ftest-coverage")
SET(GCC_COVERAGE_LINK_FLAGS "-lgcov")
There are several ways to add them:
The easiest one (not clean, but easy and convenient, and works only for compile flags, C & C++ at once):
add_definitions(${GCC_COVERAGE_COMPILE_FLAGS})
Appending to corresponding CMake variables:
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}")
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}")
Using target properties, cf. doc CMake compile flag target property and need to know the target name.
get_target_property(TEMP ${THE_TARGET} COMPILE_FLAGS)
if(TEMP STREQUAL "TEMP-NOTFOUND")
SET(TEMP "") # Set to empty string
else()
SET(TEMP "${TEMP} ") # A space to cleanly separate from existing content
endif()
# Append our values
SET(TEMP "${TEMP}${GCC_COVERAGE_COMPILE_FLAGS}" )
set_target_properties(${THE_TARGET} PROPERTIES COMPILE_FLAGS ${TEMP} )
Right now I use method 2.
In newer versions of CMake you can set compiler and linker flags for a single target with target_compile_options and target_link_libraries respectively (yes, the latter sets linker options too):
target_compile_options(first-test PRIVATE -fexceptions)
The advantage of this method is that you can control propagation of options to other targets that depend on this one via PUBLIC and PRIVATE.
As of CMake 3.13 you can also use target_link_options to add linker options which makes the intent more clear.
Try setting the variable CMAKE_CXX_FLAGS instead of CMAKE_C_FLAGS:
set (CMAKE_CXX_FLAGS "-fexceptions")
The variable CMAKE_C_FLAGS only affects the C compiler, but you are compiling C++ code.
Adding the flag to CMAKE_EXE_LINKER_FLAGS is redundant.
The preferred way to specify toolchain-specific options is using CMake's toolchain facility. This ensures that there is a clean division between:
instructions on how to organise source files into targets -- expressed in CMakeLists.txt files, entirely toolchain-agnostic; and
details of how certain toolchains should be configured -- separated into CMake script files, extensible by future users of your project, scalable.
Ideally, there should be no compiler/linker flags in your CMakeLists.txt files -- even within if/endif blocks. And your program should build for the native platform with the default toolchain (e.g. GCC on GNU/Linux or MSVC on Windows) without any additional flags.
Steps to add a toolchain:
Create a file, e.g. arm-linux-androideadi-gcc.cmake with global toolchain settings:
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
set(CMAKE_CXX_FLAGS_INIT "-fexceptions")
(You can find an example Linux cross-compiling toolchain file here.)
When you want to generate a build system with this toolchain, specify the CMAKE_TOOLCHAIN_FILE parameter on the command line:
mkdir android-arm-build && cd android-arm-build
cmake -DCMAKE_TOOLCHAIN_FILE=$(pwd)/../arm-linux-androideadi-gcc.cmake ..
(Note: you cannot use a relative path.)
Build as normal:
cmake --build .
Toolchain files make cross-compilation easier, but they have other uses:
Hardened diagnostics for your unit tests.
set(CMAKE_CXX_FLAGS_INIT "-Werror -Wall -Wextra -Wpedantic")
Tricky-to-configure development tools.
# toolchain file for use with gcov
set(CMAKE_CXX_FLAGS_INIT "--coverage -fno-exceptions -g")
Enhanced safety checks.
# toolchain file for use with gdb
set(CMAKE_CXX_FLAGS_DEBUG_INIT "-fsanitize=address,undefined -fsanitize-undefined-trap-on-error")
set(CMAKE_EXE_LINKER_FLAGS_INIT "-fsanitize=address,undefined -static-libasan")
You can also add linker flags to a specific target using the LINK_FLAGS property:
set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS " ${flag}")
If you want to propagate this change to other targets, you can create a dummy target to link to.
This worked for me when I needed a precompile definition named "NO_DEBUG":
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -DNO_DEBUG")
Then from code
#ifdef NO_DEBUG
.....
With CMake 3.4+, APPEND can be used with the string command to add flags.
string(APPEND CMAKE_EXE_LINKER_FLAGS " -fexceptions")
I want to use a variable, defined in a bitbake local.conf file, in the cpp source file as preprocessor variable. First, I try to print it with CMake message but the variable is always empty. It is also not in environment variables of CMake.
It is possible to pass variables using TARGET_CXXFLAGS =+ "-DSW_VERSION=${SW_VERSION}" but I want to avoid editing the receipe file if it is possible.
For example, let's say I want to print SW_VERSION variable in local.conf file.
SW_VERSION="1.0.0-56"
CMakeLists.txt:
message(STATUS "SW_VERSION: "$ENV{SW_VERSION})
message(STATUS "SW_VERSION: "${SW_VERSION})
I run bitbake with -v option to print cmake messages.
How can I pass a variable from bitbake conf file to CMake?
I want to add a cmake custom command that is only executed when the custom target is build in the Debug configuration while using the Visual Studio multi-config generator. Is there a clean way to do this?
In order to implement this, I first tried wrapping the whole command list in a generator expression like this.
add_custom_command(
...
COMMAND $<$<CONFIG:Debug>:cmake;-E;echo;foo>
)
But this gives me a syntax error when the command is executed. After some trial-and-error I got the following hacky solution to work. This wraps each word of the command list in a generator expression like this.
add_custom_command(
...
COMMAND $<IF:$<CONFIG:Debug>,cmake,echo>;$<IF:$<CONFIG:Debug>,-E, >;$<IF:$<CONFIG:Debug>,echo, >;$<IF:$<CONFIG:Debug>,foo, >
)
This executes the cmake -E echo foo command when compiling the Debug configuration and the dummy command echo " " " " " " for all other configurations.
This is quite ugly and the dummy command must be changed depending on the host system. On Linux it could be ":" ":" ":" ":". So Is there a cleaner way to do this?
Thank you for your time!
Here is my piece of code (tested on several single- and multi-configuration platforms):
CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(DebugEchoFoo NONE)
string(
APPEND _cmd
"$<IF:$<CONFIG:Debug>,"
"${CMAKE_COMMAND};-E;echo;foo,"
"${CMAKE_COMMAND};-E;echo_append"
">"
)
add_custom_target(
${PROJECT_NAME}
ALL
COMMAND "${_cmd}"
COMMAND_EXPAND_LISTS
)
Note: COMMAND_EXPAND_LISTS is keyword is only available with CMake version >= 3.8
Reference
Modern way to set compiler flags in cross-platform cmake project
I'm trying to use cmake to simplify distributing my OpenCL program. I have a kernel file which includes several headers and other source files, and I want to have a single self contained executable.
My plan is to have cmake run the C preprocessor on the kernel source, turning the cl file and its includes into a single unit which is easier to work with.
I can use add_custom_command to do it by calling gcc/clang with -E, but then I don't get the flags to include the right directories to find the various header files in the command, and I don't see an easy way to find all current include directories to use in the custom call to the compiler.
Is there a way to run only the C preprocessor on a file with the current cmake environment?
CMake automatically generates make targets for preprocessing files. For each foo.c in your project there's a foo.i make target that will run only the preprocessor (with all the relevant -D and -I flags etc.). Run make help to see all other potentially useful targets that CMake generates in your makefiles.
BTW, I can't see how this "single unit" will be easier to work with for you.
This worked ok so far:
function(add_c_preprocessor_command)
# Add custom command to run C preprocessor.
#
# Arguments
# OUTPUT output file
# SOURCE input file
# TARGET CMake target to inherit compile definitions, include directories, and compile options
# EXTRA_C_FLAGS extra compiler flags added after all flags inherited from the TARGET
set(one_value_args TARGET SOURCE OUTPUT)
set(multi_value_args EXTRA_C_FLAGS)
cmake_parse_arguments(CPP "" "${one_value_args}" "${multi_value_args}" ${ARGN})
string(TOUPPER ${CMAKE_BUILD_TYPE} build_type)
string(REPLACE " " ";" c_flags "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${build_type}}")
add_custom_command(
OUTPUT ${CPP_OUTPUT}
COMMAND ${CMAKE_C_COMPILER}
"-D$<JOIN:$<TARGET_PROPERTY:${CPP_TARGET},COMPILE_DEFINITIONS>,;-D>"
"-I$<JOIN:$<TARGET_PROPERTY:${CPP_TARGET},INCLUDE_DIRECTORIES>,;-I>"
${c_flags}
$<TARGET_PROPERTY:${CPP_TARGET},COMPILE_OPTIONS>
${CPP_EXTRA_C_FLAGS}
-E ${CPP_SOURCE} -o ${CPP_OUTPUT}
COMMAND_EXPAND_LISTS VERBATIM
IMPLICIT_DEPENDS C ${CPP_SOURCE}
DEPENDS ${CPP_SOURCE})
endfunction()
This will be a crude hack, but you can abuse add_definition for that, as "This command can be used to add any flags, but it was originally intended to add preprocessor definitions."
Alternatively you could just set the COMPILE_FLAGS property of the target to "-E", which will achieve the same effect but be local to that target.
I would suggest a different approach.
Build your kernel into a binary (example for ATI Stream: http://developer.amd.com/support/KnowledgeBase/Lists/KnowledgeBase/DispForm.aspx?ID=115 )
Compile this binary data into your program (as a char[] blob) and load it when your program starts.
With cmake and custom targets this should be quite simple.