CMake 核心概念#

参考:CMake 核心概念

许多 CMake 对象,如目标、目录和源文件,都与属性相关联。属性是附加到特定对象上的键值对。访问属性最通用的方式是通过 set_propertyget_property 命令。这些命令允许您从任何具有属性的 CMake 对象中设置或获取属性。请参阅 cmake-properties 手册以获取支持的属性列表。从命令行运行 cmake 命令并使用 --help-property-list 选项,可以获得 CMake 支持的属性完整列表。

CMake 目标#

可能最重要的项目是目标(targets)。目标代表由 CMake 构建的可执行文件、库和实用工具。每个 add_libraryadd_executableadd_custom_target 命令都会创建目标。例如,以下命令将创建名为“foo”的目标,它是静态库,foo1.cfoo2.c 作为源文件。

add_library(foo STATIC foo1.c foo2.c)

名称“foo”现在可以在项目的其他地方用作库名称,并且 CMake 会在需要时知道如何将名称扩展为库。库可以声明为特定类型,如 STATICSHAREDMODULE,或者不声明。STATIC 表示库必须作为静态库构建。同样,SHARED 表示它必须作为共享库构建。MODULE 表示库必须创建,以便可以动态加载到可执行文件中。模块库在许多平台上实现为共享库,但并非所有平台。因此,CMake 不允许其他目标链接到模块。如果未指定这些选项,则表示库可以构建为共享或静态。在这种情况下,CMake 使用变量 BUILD_SHARED_LIBS 的设置来确定库应该是 SHARED 还是 STATIC。如果未设置,则 CMake 默认构建静态库。

同样,可执行文件也有一些选项。默认情况下,可执行文件将是传统的控制台应用程序,具有 main 入口点。可以通过指定 WIN32 选项来请求 Windows 系统上的 WinMain 入口点,同时在非 Windows 系统上保留 main

除了存储类型,目标还跟踪通用属性。这些属性可以使用 set_target_propertiesget_target_property 命令,或更通用的 set_propertyget_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”链接到可执行文件“foobar”中。

使用目标指定优化或调试库#

在 Windows 平台上,用户通常需要将调试库与调试库链接,优化库与优化库链接。CMake 通过 target_link_libraries 命令帮助满足这一要求,该命令接受可选的标记为 debugoptimized 的标志。如果库前面有 debugoptimized,那么该库将仅与适当的配置类型链接。例如:

add_executable(foo foo.c)
target_link_libraries(foo debug libdebug optimized libopt)

在这种情况下,如果选择了调试构建,foo 将链接到 libdebug;如果选择了优化构建,则链接到 libopt

对象库#

大型项目通常将源文件组织成不同的组,可能位于不同的子目录中,每个组需要不同的包含目录和预处理器定义。为此用例,CMake 开发了对象库的概念。

对象库是一组源文件编译成的对象文件集合,这些对象文件不会被链接到库文件或制作成归档文件。相反,由 add_libraryadd_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>)

将包含 AB 对象文件到名为 Combined 的库中。对象库只能包含编译成对象文件的源文件(和头文件)。

源文件#

源文件结构与目标类似。它存储文件名、扩展名以及与源文件相关的若干通用属性。与目标一样,你可以使用 set_source_files_propertiesget_source_file_property 或更通用的版本来设置和获取属性。

目录、测试和属性#

除了目标和源文件,你可能会偶尔处理其他对象,例如目录和测试。通常,这些交互表现为从这些对象中设置或获取属性(例如 set_directory_propertiesset_tests_properties )。