问题描述
我试图修改某个目录下所有目录的编译器标志(即递归地为所有当前目录子目录及其所有子目录)。所以我发现有两种方法:
add_directory(dir1)
#...
add_directory(dirN)
add_compile_options(flag1 flag2 ...)
# CMake版本3.0做一些更像:
set(CMAKE_CXX_FLAGS$ {CMAKE_CXX_FLAGS} flag1 flag2 ...)
add_compile_options
的手册页很清楚地表明效果将是当前目录和下面(这是我想要的),但 set(CMAKE_CXX_FLAGS ...)
我不太确定。
Cmake设置变量递归? strong>
简短的回答是,每个子目录都有自己的变量范围, add_subdirectory()
调用时的值。
对于长的答案,请参阅
目录&目标属性与(全局)变量
和由CMake处理:
-
您将
add_compile_options()
指定的所有内容附加到目录属性。然后此属性用于在创建目标时使用add_library()
或初始化
。COMPILE_OPTIONS
code> add_executable()
目录属性的当前状态用于初始化子目录属性是一个全局缓存变量。您可以通过定义本地目录作用域变量(隐藏全局缓存的变量)来扩展/覆盖它。
这些变量的上下文被复制到
add_subdirectory()
(传播到子目录) 。
CMake会在每个
CMakeLists.txt
的文件,并将其应用于同一CMakeLists.txt
(允许延迟声明,参见完成公式和测试代码 em>下面)。 -
3.0相当于
add_compile_options()
的是。该功能仍然存在,但很奇怪,混合定义与编译选项。
完整的编译器标记生成器公式
这是CMake的代码(参见,和)。
此示例显示了一个没有导出的 DEBUG
构建配置库,不考虑基于功能的标记或某事像 CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES
或 CMAKE_QUOTE_INCLUDE_PATHS
:
code> CMAKE_CXX_FLAGS //如设定为目标的的CMakeLists.txt
+ CMAKE_CXX_FLAGS_DEBUG
月底+包含目录//与CMAKE_INCLUDE_FLAG_CXX / CMAKE_INCLUDE_SYSTEM_FLAG_CXX
pefixed (CMAKE_INCLUDE_CURRENT_DIR)?
+ CMAKE_CURRENT_SOURCE_DIR + CMAKE_CURRENT_BINARY_DIR
+ CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES
+目标[INCLUDE_DIRECTORIES]
+ DependingTargets [INTERFACE_INCLUDE_DIRECTORIES]
+定义与add_definitions给出标志//编译器标志()
+ Target [COMPILE_FLAGS] //已弃用
- 已由CMAKE_CXX_FLAG_REGEX
+ Target筛选[COMPILE_OPTIONS]
+依据目标[INTERFACE_COMPILE_OPTIONS]
测试代码
代码测试编译器选项和结果我得到:
注意:通常我会使用
add_definitions / code>和
target_compile_definitions()
而不是add_compile_options()
和target_compile_options )
来设置编译器定义,但是为了演示编译器选项的传播I(mis-)使用-D
标志。
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
项目(CxxFlagsTest)
组(CMAKE_CXX_FLAGS$ {} CMAKE_CXX_FLAGS -DCXX_FLAG)
add_compile_options( - DCOMPILE_OPTION)
add_subdirectory (lib)
文件(WRITE main.cppint 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主要COMPILE_OPTIONS)
消息(STATUS主要COMPILE_OPTIONS:$ {_ main_compile_options})
get_directory_property(_root_compile_options COMPILE_OPTIONS)
消息(状态root COMPILE_OPTIONS:$ {_ root_compile_options})
消息(状态root CMAKE_CXX_FLAGS:$ {CMAKE_CXX_FLAGS})
lib / CMakeLists.txt
设定(CMAKE_CXX_FLAGS$ {CMAKE_CXX_FLAGS} -DSUB_CXX_FLAG
add_compile_options( - DSUB_COMPILE_OPTION)
文件(WRITE lib.cpp)
add_library(lib lib.cpp)
target_compile_options(LIB PUBLIC-DLIB_COMPILE_OPTION)
组(CMAKE_CXX_FLAGS$ {} CMAKE_CXX_FLAGS -DLATE_SUB_CXX_FLAG)
get_target_property(_lib_compile_options LIB COMPILE_OPTIONS)
消息(STATUS LIB COMPILE_OPTIONS:$ {_ lib_compile_options})
get_directory_property(_sub_compile_options COMPILE_OPTIONS)
消息(STATUS子COMPILE_OPTIONS:$ {_ sub_compile_options})
消息(STATUS子CMAKE_CXX_FLAGS:$ {CMAKE_CXX_FLAGS })
会产生以下消息:
- LIB COMPILE_OPTIONS:-DCOMPILE_OPTION; -DSUB_COMPILE_OPTION; -DLIB_COMPILE_OPTION
- 子COMPILE_OPTIONS:-DCOMPILE_OPTION; -DSUB_COMPILE_OPTION
- 子CMAKE_CXX_FLAGS。 .. -DCXX_FLAG -DSUB_CXX_FLAG -DLATE_SUB_CXX_FLAG
- 主要COMPILE_OPTIONS:-DCOMPILE_OPTION; -DMAIN_COMPILE_OPTION
- 根COMPILE_OPTIONS:-DCOMPILE_OPTION
- 根CMAKE_CXX_FLAGS:... -DCXX_FLAG -DLATE_CXX_FLAG
并设置以下预处理器定义:
lib
这里有趣的部分是
LATE
CXX标志和LIB
$ c>
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 forset(CMAKE_CXX_FLAGS ...)
I am not so sure.Is Cmake set variable recursive?
解决方案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()
andCMAKE_CXX_FLAGS
are processed by CMake:
Everything that you specify with
add_compile_options()
is appended to theCOMPILE_OPTIONS
directory property. Then "this property is used to initialize theCOMPILE_OPTIONS
target property when a target is created" withadd_library()
oradd_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 sameCMakeLists.txt
(allowing late declarations, see also Complete Formula and Test Code below).So for CMake versions < 3.0 the equivalent to
add_compile_options()
wasadd_definitions()
. The functionality is still there, but it was strange to mix definitions with compile options. Soadd_compile_options()
was invented.The complete Generator-Formula for Compiler Flags
It's in CMake's code (see
cmCommonTargetGenerator::GetFlags()
,cmLocalGenerator::AddCompileOptions()
andcmLocalGenerator::AddLanguageFlags()
).This example shows a
DEBUG
build configuration library without exports, not taking into account the feature-based flags or something likeCMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES
orCMAKE_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()
andtarget_compile_definitions()
instead ofadd_compile_options()
andtarget_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
main
The interesting parts here are the
LATE
CXX flags and theLIB
compile option propagated the the linked library.References
- cmake - Global linker flag setting (for all targets in directory)
- What's the CMake syntax to set and use variables?
这篇关于是Cmake设置变量递归吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!