Is Cmake a given variable recursive?

I am trying to change compiler flags for all directories below a specific directory (i.e. for all subdirectories of current directories and all their subdirectories recursively). Thus, I have found here , there are 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 makes it very clear that the effect will be "current directory and below" (this is what I want), but for set(CMAKE_CXX_FLAGS ...) I'm not sure.

Is Cmake a given variable recursive?

+5
source share
1 answer

The short answer is that each subdirectory has its own variable region, initialized by a copy of the current values โ€‹โ€‹of the variables during the call to add_subdirectory() .

For a long answer, see What is CMake syntax for setting and using variables?

Directory properties and targets vs (global) variables

There is a difference between how add_compile_options() and CMAKE_CXX_FLAGS processed using CMake:

  • Everything that you specify with add_compile_options() is added to the COMPILE_OPTIONS directory COMPILE_OPTIONS . Then "this property is used to initialize the target COMPILE_OPTIONS property when creating the target" using add_library() or add_executable() .

    And the current state of directory properties is used to initialize the properties of the subdirectory when the parser receives a call to add_subdirectory() .

  • CMAKE_CXX_FLAGS is a global cached variable. You can extend / overwrite it by specifying a local directory region variable (hiding the globally cached).

    This context variable is copied to the subdirectory area on add_subdirectory() (applies to subdirectories).

    And CMake looks at its value at the end of each CMakeLists.txt file and applies it to all targets in the same CMakeLists.txt (allowing late declarations, see also the full formula and test code below).

  • So, for CMake versions <3.0, the equivalent of add_compile_options() was add_definitions() . Functionality still exists, but it was strange to mix definitions with compilation options. Thus, add_compile_options() was invented.

Complete generator formula for compiler flags

In the CMake code (see cmCommonTargetGenerator::GetFlags() , cmLocalGenerator::AddCompileOptions() and cmLocalGenerator::AddLanguageFlags() ).

This example shows the DEBUG assembly configuration library without export, without considering function-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 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 that I get:

Note: Normally, I should use add_definitions() and target_compile_definitions() instead of add_compile_options() and target_compile_options() to define compiler definitions, but to demonstrate the distribution of compiler options I (incorrectly) use the -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}") 

Library /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}") 

The following messages will appear:

 -- 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 preprocessor definitions are 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 compilation option distributes the linked library.

References

+8
source

Source: https://habr.com/ru/post/1236435/


All Articles