简述几种方法
CMake是一个跨平台的构建系统,它允许开发者编写一种简单的文件来描述所有平台的构建过程。在CMake中,你可以通过以下方式增加编译参数和预处理指令:
- 添加编译参数:
- 使用
add_compile_options
命令。这个命令将添加到所有的目标上。例如:
add_compile_options(-Wall)
- 使用
target_compile_options
命令。这个命令只会添加到指定的目标上。例如:
target_compile_options(target PRIVATE -Wall)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ...")
是另一种常见的添加编译参数的方法。这种方法直接修改了CMake的全局变量,所以它会影响到所有的目标。
例如,如果你想添加-Wall
编译选项,你可以这样写:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
- 这行代码的意思是,将
-Wall
添加到CMAKE_CXX_FLAGS
变量中。CMAKE_CXX_FLAGS
变量包含了C++编译器的编译选项。
同样的,对于C编译器,你可以使用CMAKE_C_FLAGS
:
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
- 这种方法的一个缺点是,它会影响到所有的目标,而不仅仅是一个特定的目标。如果你只想为一个特定的目标添加编译选项,你应该使用
target_compile_options
命令。
- 添加预处理指令:
- 使用
add_definitions
命令。这个命令将添加到所有的目标上。例如:
add_definitions(-DDEBUG)
- 使用
target_compile_definitions
命令。这个命令只会添加到指定的目标上。例如:
target_compile_definitions(target PRIVATE DEBUG)
- 在上述两个例子中,
DEBUG
是一个预处理指令,它会在编译时被定义。
注意,PRIVATE
、PUBLIC
、INTERFACE
这些关键字的含义:
PRIVATE
:只有目标自己会使用这些编译参数。PUBLIC
:目标自己和其他依赖这个目标的目标都会使用这些编译参数。INTERFACE
:只有其他依赖这个目标的目标会使用这些编译参数。
以上就是在CMake中增加编译参数和预处理指令的所有方法。
add_definitions 解析
根据CMake官方文档,add_definitions
命令用于向源文件的编译中添加-D定义标志。这个命令可以用来添加任何标志,但它主要是用来添加预处理器定义的。
例如,add_definitions(-DFOO -DBAR ...)
会将定义添加到当前目录中的目标的编译器命令行,无论这个命令是在添加目标之前还是之后调用的,以及在此命令调用后添加的子目录中的目标。
然而,这个命令已经被以下的替代方法取代:
- 使用
add_compile_definitions()
来添加预处理器定义。 - 使用
include_directories()
来添加包含目录。 - 使用
add_compile_options()
来添加其他选项。
以-D或/D开头的标志,看起来像预处理器定义的,会自动添加到当前目录的COMPILE_DEFINITIONS目录属性中。具有非平凡值的定义可能会保留在标志集中,而不是被转换,这是出于向后兼容性的考虑。
因此,你的说法是正确的,add_definitions
命令可以用于添加编译器标志,但这并不是它的主要用途,而且在某些情况下可能会导致问题。对于编译器标志,如-Wall和-g,更推荐使用add_compile_options()
命令。
add_compile_options 解析
add_compile_options
命令用于向源文件的编译中添加选项。这些选项会被添加到COMPILE_OPTIONS目录属性中,这些选项在编译当前目录及其子目录中的目标时会被使用。需要注意的是,这些选项在链接时不会被使用,链接时的选项需要使用add_link_options()
命令来添加。
add_compile_options
命令的参数可以使用生成器表达式,最终用于目标的选项集是通过从当前目标和其依赖项的使用要求中累积选项来构造的,选项集会进行去重以避免重复。
例如,你可以在特定的编译器条件下使用这个命令:
if (MSVC) # warning level 4 add_compile_options(/W4) else() # additional warnings add_compile_options(-Wall -Wextra -Wpedantic) endif()
如果你想要为特定的目标添加编译选项,你应该使用target_compile_options
命令。例如,如果你有一个目标叫做my_target
,你可以这样为它添加编译选项:
target_compile_options(my_target PRIVATE -Wall -Wextra -Wpedantic)
在这个例子中,-Wall -Wextra -Wpedantic
这些编译选项只会被添加到my_target
这个目标,而不会影响到其他的目标。
不同用法 的 区别
CMAKE_<LANG>_FLAGS
是用于所有配置时构建语言的全局标志。这些标志将被传递给编译器的所有调用,包括驱动编译和驱动链接的调用。
对于每种语言,如果这个变量没有被定义,它会使用环境变量和CMake的工具链内置默认值进行初始化并存储在缓存中。例如,CMAKE_CXX_FLAGS
会被CXXFLAGS环境变量初始化。
这个值是一个命令行字符串片段,因此,多个选项应该由空格分隔,带有空格的选项应该被引用。
这个变量中的标志将在每个配置的CMAKE_<LANG>_FLAGS_<CONFIG>
变量中的标志之前被传递。在驱动编译的调用中,这两个变量中的标志都会在add_compile_options()
和target_compile_options()
等命令添加的标志之前被传递。在驱动链接的调用中,它们会在add_link_options()
和target_link_options()
等命令添加的标志之前被传递。
因此,add_compile_options
和set(CMAKE_CXX_FLAGS ...)
都可以用来添加编译选项,但是它们的使用场景和影响范围是不同的。add_compile_options
更加灵活,可以在特定条件下添加选项,而set(CMAKE_CXX_FLAGS ...)
则是全局设置,会影响所有的目标。这两个命令可以同时使用,它们的效果是累积的,不会互相覆盖。
结语
在我们的编程学习之旅中,理解是我们迈向更高层次的重要一步。然而,掌握新技能、新理念,始终需要时间和坚持。从心理学的角度看,学习往往伴随着不断的试错和调整,这就像是我们的大脑在逐渐优化其解决问题的“算法”。
这就是为什么当我们遇到错误,我们应该将其视为学习和进步的机会,而不仅仅是困扰。通过理解和解决这些问题,我们不仅可以修复当前的代码,更可以提升我们的编程能力,防止在未来的项目中犯相同的错误。
我鼓励大家积极参与进来,不断提升自己的编程技术。无论你是初学者还是有经验的开发者,我希望我的博客能对你的学习之路有所帮助。如果你觉得这篇文章有用,不妨点击收藏,或者留下你的评论分享你的见解和经验,也欢迎你对我博客的内容提出建议和问题。每一次的点赞、评论、分享和关注都是对我的最大支持,也是对我持续分享和创作的动力。