关键概念¶
本章介绍了 CMake 的关键概念。在开始使用 CMake 时,你将遇到各种概念:目标、生成器和命令等。了解这些概念将为你提供创建有效 CMakeLists 文件所需的工作知识。许多 CMake 对象(如目标、目录和源文件)都有与之关联的属性。属性是附加到特定对象上的键值对。访问属性最通用的方法是通过 set_property
和 get_property
命令。借助这些命令,你可以在 CMake 中从具有属性的任何对象中设置或获取属性。有关受支持属性的列表,请参阅 cmake-properties
手册。从命令行可以通过运行 cmake
并带有 --help-property-list
选项,来获取 CMake 中受支持的属性的完整列表。
目标¶
目标可能是最重要的一项。目标表示由 CMake 编译的可执行文件、库和实用程序。每条 add_library
、add_executable
和 add_custom_target
命令都会创建一个目标。例如,以下命令将创建一个名为“foo”的目标,该目标是一个静态库,其中 foo1.c
和 foo2.c
是源文件。
add_library(foo STATIC foo1.c foo2.c)
名称“foo”现可在项目中其他任一位置用作库名称,而 CMake 将知道如何在需要时将名称展开至库中。库可以声明为特定类型,例如 STATIC
、SHARED
、MODULE
,也可以保留其未声明状态。 STATIC
表示库必须构建为静态库。同样,SHARED
表示它必须构建为共享库。 MODULE
表示库必须创建为可以动态加载至可执行文件的形式。模块库在许多(但并非全部)平台上均作为共享库实现。因此,CMake 不允许其他目标链接至模块。如果未指定任何这些选项,则表示可以构建该库为共享库或静态库。在该情况下,CMake 会使用变量 BUILD_SHARED_LIBS
的设置,以确定该库应为 SHARED
还是 STATIC
。如果未设置,则 CMake 默认构建静态库。
同样,可执行文件也有一些选项。默认情况下,可执行文件将是不具备主要入口点的传统控制台应用程序。用户可以指定 WIN32
选项,以请求 Windows 系统使用 WinMain 入口点,同时在非 Windows 系统上保留 main。
除了存储其类型外,目标还跟踪通用属性。可以使用 set_target_properties
和 get_target_property
命令或更通用的 set_property
和 get_property
命令来设置和检索这些属性。一个有用的属性是 LINK_FLAGS
,用于为特定目标指定附加链接标志。目标会存储要链接到的库列表,这些库是使用 target_link_libraries
命令设置的。传递给此命令的名称可以是库、库的完整路径或 add_library
命令中库的名称。目标还会存储链接时的链接目录以及构建后要执行的自定义命令。
用法要求¶
CMake 还会从链接的库目标传播“用法要求”。用法要求会影响和<target> 中的源编译。这些要求由链接目标上定义的属性指定。
例如,若要指定链接到库时需要的包含目录,可以执行以下操作
add_library(foo foo.cxx)
target_include_directories(foo PUBLIC
"${CMAKE_CURRENT_BINARY_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}"
)
现在,任何链接到目标 foo 的内容都会自动将 foo 的二进制文件和源文件作为包含目录。通过“用法要求”引入的包含目录的顺序将与 target_link_libraries
调用中的目标顺序相匹配。
对于创建的每个库或可执行文件,CMake 都会通过 target_link_libraries
命令跟踪该目标依赖的所有库。例如
add_library(foo foo.cxx)
target_link_libraries(foo bar)
add_executable(foobar foobar.cxx)
target_link_libraries(foobar foo)
即使只为可执行文件“foobar”明确指定“foo”,这也会将库“foo”和“bar”链接到可执行文件中。
使用目标来指定优化库或调试库¶
在 Windows 平台上,用户通常需要将调试库与调试库进行链接,将优化库与优化库进行链接。 CMake 有助于使用 target_link_libraries
命令来满足此要求,此命令接受一个标记为 debug
或 optimized
的可选标志。如果库前面带 debug
或 optimized
,则该库只会与适当的配置类型一起进行链接。例如
add_executable(foo foo.c)
target_link_libraries(foo debug libdebug optimized libopt)
在这种情况下,如果选择调试构建,则 foo 将与 libdebug 链接;如果选择优化构建,则 foo 将与 libopt 链接。
对象库¶
大型项目通常会将其源文件组织到组中,可能分散在单独的子目录中,每个子目录都需要不同的头文件目录和预处理器定义。对于此用例,CMake 开发了对象库的概念。
对象库是一组源文件,已编译成对象文件,该文件未链接到库文件中或打包成归档文件。相反,由 add_library
或 add_executable
创建的其他目标可以使用 $<TARGET_OBJECTS:name>
表达式作为源文件,其中“name”是由 add_library
调用创建的目标。例如
add_library(A OBJECT a.cpp)
add_library(B OBJECT b.cpp)
add_library(Combined $<TARGET_OBJECTS:A> $<TARGET_OBJECTS:B>)
会在一个名为“Combined”的库中包括 A 和 B 对象文件。对象库可能只包含编译成对象文件的源文件(和头文件)。
源文件¶
源文件结构在许多方面类似于目标。它存储了文件名、扩展名和与源文件相关的许多通用属性。与目标类似,你可以使用 set_source_files_properties
和 get_source_file_property
或更通用的版本来设置和获取属性。
目录、测试和属性¶
除了目标和源文件,您可能会发现自己偶尔与其他对象(如目录和测试)一起工作。通常,此类交互会采取设置或获取属性(例如 set_directory_properties
或 set_tests_properties
)的形式。