I am trying to modify compiler flags for all the directories below a certain directory (i.e. for all the current directories subdirectories and all their subdirectories recursively). So I found here there is two ways:
add_directory(dir1)
# ...
add_directory(dirN)
add_compile_options(flag1 flag2 ...)
# or for CMake versions < 3.0 to do something more like:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} flag1 flag2 ...")
The man page for add_compile_options
is very clear in stating that the effect will be "current directory and below" (which is what I want) but for set(CMAKE_CXX_FLAGS ...)
I am not so sure.
Is Cmake set variable recursive?
Set Normal VariableSets the given <variable> in the current function or directory scope. If the PARENT_SCOPE option is given the variable will be set in the scope above the current scope. Each new directory or function() command creates a new scope. A scope can also be created with the block() command.
Options and variables are defined on the CMake command line like this: $ cmake -DVARIABLE=value path/to/source You can set a variable after the initial `CMake` invocation to change its value. You can also undefine a variable: $ cmake -UVARIABLE path/to/source Variables are stored in the `CMake` cache.
You can use the command line to set entries in the Cache with the syntax cmake -D var:type=value , just cmake -D var=value or with cmake -C CMakeInitialCache. cmake .
Add a subdirectory to the build. Adds a subdirectory to the build. The source_dir specifies the directory in which the source CMakeLists.
The short answer is, that each sub-directory has it's own variable scope initialized with a copy of the current variable values at the time of the add_subdirectory()
call.
For the long answer please see What's the CMake syntax to set and use variables?
Directory & Target Properties vs (Global) Variables
There is a difference between how add_compile_options()
and CMAKE_CXX_FLAGS
are processed by CMake:
Everything that you specify with add_compile_options()
is appended to the COMPILE_OPTIONS
directory property. Then "this property is used to initialize the COMPILE_OPTIONS
target property when a target is created" with add_library()
or add_executable()
.
And the current state of directory properties are used to initialize sub-directory properties when the parser gets to a add_subdirectory()
call.
The CMAKE_CXX_FLAGS
is a global cached variable. You can extend/overwrite it by defining a local directory scoped variable (hiding the globally cached one).
Those variable's context is copied into a sub-directories scope on add_subdirectory()
(propagating to sub-directories).
And CMake looks into its value at the end of the each CMakeLists.txt
file and applies this to all targets in the same CMakeLists.txt
(allowing late declarations, see also Complete Formula and Test Code below).
So for CMake versions < 3.0 the equivalent to add_compile_options()
was add_definitions()
. The functionality is still there, but it was strange to mix definitions with compile options. So add_compile_options()
was invented.
The complete Generator-Formula for Compiler Flags
It's in CMake's code (see cmCommonTargetGenerator::GetFlags()
, cmLocalGenerator::AddCompileOptions()
and cmLocalGenerator::AddLanguageFlags()
).
This example shows a DEBUG
build configuration library without exports, not taking into account the feature-based flags or something like CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES
or CMAKE_QUOTE_INCLUDE_PATHS
:
CMAKE_CXX_FLAGS // as set at the end of target's CMakeLists.txt
+ CMAKE_CXX_FLAGS_DEBUG
+ Include Directories // pefixed with CMAKE_INCLUDE_FLAG_CXX/CMAKE_INCLUDE_SYSTEM_FLAG_CXX
(CMAKE_INCLUDE_CURRENT_DIR) ?
+ CMAKE_CURRENT_SOURCE_DIR + CMAKE_CURRENT_BINARY_DIR
+ CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES
+ Target[INCLUDE_DIRECTORIES]
+ DependingTargets[INTERFACE_INCLUDE_DIRECTORIES]
+ Define Flags // compiler flags given with add_definitions()
+ Target[COMPILE_FLAGS] // deprecated
- Filtered by CMAKE_CXX_FLAG_REGEX
+ Target[COMPILE_OPTIONS]
+ DependingTargets[INTERFACE_COMPILE_OPTIONS]
Test Code
For a better understanding here is my code for testing the compiler options and the results I get:
Note: Normally I would use add_definitions()
and target_compile_definitions()
instead of add_compile_options()
and target_compile_options()
to set compiler definitions, but to demonstrate the propagating of compiler options I (mis-)used -D
flags.
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(CxxFlagsTest)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DCXX_FLAG")
add_compile_options("-DCOMPILE_OPTION")
add_subdirectory(lib)
file(WRITE main.cpp "int main() { return 0; }")
add_executable(main main.cpp)
target_link_libraries(main lib)
target_compile_options(main PRIVATE "-DMAIN_COMPILE_OPTION")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DLATE_CXX_FLAG")
get_target_property(_main_compile_options main COMPILE_OPTIONS)
message(STATUS "main COMPILE_OPTIONS: ${_main_compile_options}")
get_directory_property(_root_compile_options COMPILE_OPTIONS)
message(STATUS "root COMPILE_OPTIONS: ${_root_compile_options}")
message(STATUS "root CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}")
lib/CMakeLists.txt
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSUB_CXX_FLAG")
add_compile_options("-DSUB_COMPILE_OPTION")
file(WRITE lib.cpp "")
add_library(lib lib.cpp)
target_compile_options(lib PUBLIC "-DLIB_COMPILE_OPTION")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DLATE_SUB_CXX_FLAG")
get_target_property(_lib_compile_options lib COMPILE_OPTIONS)
message(STATUS "lib COMPILE_OPTIONS: ${_lib_compile_options}")
get_directory_property(_sub_compile_options COMPILE_OPTIONS)
message(STATUS "sub COMPILE_OPTIONS: ${_sub_compile_options}")
message(STATUS "sub CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}")
Would result in the following messages:
-- lib COMPILE_OPTIONS: -DCOMPILE_OPTION;-DSUB_COMPILE_OPTION;-DLIB_COMPILE_OPTION
-- sub COMPILE_OPTIONS: -DCOMPILE_OPTION;-DSUB_COMPILE_OPTION
-- sub CMAKE_CXX_FLAGS: ... -DCXX_FLAG -DSUB_CXX_FLAG -DLATE_SUB_CXX_FLAG
-- main COMPILE_OPTIONS: -DCOMPILE_OPTION;-DMAIN_COMPILE_OPTION
-- root COMPILE_OPTIONS: -DCOMPILE_OPTION
-- root CMAKE_CXX_FLAGS: ... -DCXX_FLAG -DLATE_CXX_FLAG
And the following pre-processor definitions being set:
lib
CXX_FLAG SUB_CXX_FLAG LATE_SUB_CXX_FLAG COMPILE_OPTION SUB_COMPILE_OPTION LIB_COMPILE_OPTION
main
CXX_FLAG LATE_CXX_FLAG COMPILE_OPTION MAIN_COMPILE_OPTION LIB_COMPILE_OPTION
The interesting parts here are the LATE
CXX flags and the LIB
compile option propagated the the linked library.
References
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With