add_library

使用指定源文件向项目添加库。

正常库

add_library(<name> [<type>] [EXCLUDE_FROM_ALL] <sources>...)

添加一个库目标,命名为 <name>,用在命令调用中所列的源文件进行构建。

可选的 <type> 指定要创建的库的类型

STATIC

对象文件的存档,供链接其他目标时使用。

SHARED

动态库;其他目标可以在链接时使用,并在运行时进行加载。

MODULE

插件;其他目标不能通过此形式链接,但在运行时可以使用类似 dlopen 的功能动态加载。

如果没有给出 <type>,则默认值为 STATICSHARED,具体取决于 BUILD_SHARED_LIBS 变量的值。

选项如下:

EXCLUDE_FROM_ALL

自动设置 EXCLUDE_FROM_ALL 目标属性。有关详细信息,请参见该目标属性的文档。

<name> 对应的是逻辑目标名称,在项目中必须是全局唯一的。所构建库的实际文件名是根据本机平台的约定(如 lib<name>.a<name>.lib)构造的。

3.1 版添加: add_library 的源参数可以使用语法为 $<...> 的“生成器表达式”。有关可用表达式,请参见 cmake-generator-expressions(7) 手册。

3.11 版添加: 如果稍后使用 target_sources() 添加源文件,则可以省略源文件。

对于 SHAREDMODULE 库,POSITION_INDEPENDENT_CODE 目标属性会自动设置为 ON。可以使用 FRAMEWORK 目标属性将 SHARED 库标记为 macOS Framework。

3.8 版添加: 可以使用 FRAMEWORK 目标属性将 STATIC 库标记为静态 Framework。

如果库不导出任何符号,则不得将其声明为 SHARED 库。例如,不导出任何非托管符号的 Windows 资源 DLL 或托管 C++/CLI DLL 需要是 MODULE 库。这是因为 CMake 希望 SHARED 库始终在 Windows 上有相关的导入库。

默认情况下,库文件将在与调用该命令的源树目录对应的构建树目录中创建。请参阅文档 ARCHIVE_OUTPUT_DIRECTORYLIBRARY_OUTPUT_DIRECTORYRUNTIME_OUTPUT_DIRECTORY 目标属性以更改此位置。请参阅文档 OUTPUT_NAME 目标属性以更改最终文件名中的 <name> 部分。

请参阅 cmake-buildsystem(7) 手册以了解更多有关定义构建系统属性的信息。

另请参阅 HEADER_FILE_ONLY,了解如果某些源文件经过预处理,且您希望可以通过 IDE 访问原始源文件,该怎么做。

在版本 3.30 中更改:在不支持共享库的平台上,add_library 现在会失败,因为它会调用创建 SHARED 库,而不是像以前那样自动将它们转换为 STATIC 库。请参阅策略 CMP0164

对象库

add_library(<name> OBJECT <sources>...)

添加一个 对象库,以编译源文件,而无需将它们的对象文件存档或链接到库中。

add_libraryadd_executable() 创建的其他目标可以使用目标的表达式作为源文件,其形式为 $<TARGET_OBJECTS:objlib>,其中 objlib 是对象库名称。例如

add_library(... $<TARGET_OBJECTS:objlib> ...)
add_executable(... $<TARGET_OBJECTS:objlib> ...)

会在库和可执行文件中包含 objlib 的对象文件以及从它们自己的源文件编译出来的对象文件。对象库可能只包含可以编译的源文件、头文件以及不会影响普通库链接的其他文件(例如 .txt)。它们可以包含生成此类源文件的自定义命令,但不能包含 PRE_BUILDPRE_LINKPOST_BUILD 命令。某些原生构建系统(例如 Xcode)可能不喜欢只有对象文件的目标,因此请考虑至少向任何引用 $<TARGET_OBJECTS:objlib> 的目标添加一个真实源文件。

在版本 3.12 中添加:可以使用 target_link_libraries() 将对象库与其他链接库关联起来。

接口库

add_library(<name> INTERFACE)

添加一个接口库目标,该目标可能为附属库指定使用要求,但不编译源文件,也不在磁盘上生成库制品。

在生成的构建系统中,不带任何源文件的接口库不会作为目标包含进去。但是,可以对其设置一些属性,还可以对其进行安装和导出。通常,INTERFACE_* 属性利用以下命令填充到接口目标中

然后将其用作target_link_libraries()的参数,就像任何其他目标一样。

在 3.15 版本中添加: 接口库可以具有 PUBLIC_HEADERPRIVATE_HEADER 属性。可以使用 install(TARGETS) 命令安装由这些属性指定的头文件。

add_library(<name> INTERFACE [EXCLUDE_FROM_ALL] <sources>...)

在 3.19 版本中添加。

添加带有源文件(除上面 签名中记录的使用要求和属性之外)的接口库目标。源文件可以在 add_library 调用中直接列出,或随后通过调用具有 PRIVATEPUBLIC 关键字的target_sources() 来添加。

如果接口库具有源文件(即设置了SOURCES目标属性),或标题集(即设置了HEADER_SETS目标属性),它将作为构建目标出现在生成的构建系统中,很像由add_custom_target()命令定义的目标。它不编译任何源,但确实包含add_custom_command()命令创建的自定义命令的构建规则。

选项如下:

EXCLUDE_FROM_ALL

自动设置EXCLUDE_FROM_ALL目标属性。详情请参阅该目标属性的文档。

注意

INTERFACE关键字出现的命令签名中,列在其之后的项只成为该目标的使用要求的一部分,不属于目标自己的设置。然而,在这个add_library的签名中,INTERFACE关键字只涉及库类型。在 add_library 调用中列在其之后的源对于接口库是 PRIVATE 的,不显示在其INTERFACE_SOURCES目标属性中。

导入的库

add_library(<name> <type> IMPORTED [GLOBAL])

添加名为 <name>导入的库目标。目标名称可能引用项目中构建的任何目标,除非默认情况下,它仅在创建它的目录及其子目录中可见。

<type> 是以下之一:

STATICSHAREDMODULEUNKNOWN

引用位于项目外部的库文件。 IMPORTED_LOCATION 目标属性(或其 IMPORTED_LOCATION_<CONFIG> 结构变体)指定磁盘上主库文件的位置

  • 对于大多数非 Windows 平台上的 SHARED 库,主库文件是链接器和动态加载器使用的 .so.dylib 文件。如果引用的库文件有 SONAME(或在 macOS 上,有从 @rpath/ 开始的 LC_ID_DYLIB),该字段的值应设置在 IMPORTED_SONAME 目标属性中。如果引用的库文件没有 SONAME,但平台支持它,那么应该设置 IMPORTED_NO_SONAME 目标属性。

  • 对于 Windows 上的 SHARED 库, IMPORTED_IMPLIB 目标属性(或其 IMPORTED_IMPLIB_<CONFIG> 结构变体)指定磁盘上的 DLL 导入库文件 (.lib.dll.a) 的位置,而 IMPORTED_LOCATION.dll 运行时库的位置(这是可选的,但 TARGET_RUNTIME_DLLS 生成器表达式需要它)。

附加使用要求可在 INTERFACE_* 属性中指定。

UNKNOWN 的库类型通常仅在 查找模块 的实现中使用。它允许 imported 库的路径(通常使用 find_library() 命令找到)无需知道其库类型即可使用。这在 Windows 上尤其有用,因为静态库和 DLL 的导入库都具有相同的文件扩展名。

OBJECT

引用项目外部的一组对象文件。 IMPORTED_OBJECTS target 属性(或其每个配置的变体 IMPORTED_OBJECTS_<CONFIG>)指定磁盘上对象文件的位置。可以在 INTERFACE_* 属性中指定额外的使用需求。

INTERFACE

不引用磁盘上的任何库或对象文件,但可以在 INTERFACE_* 属性中指定使用需求。

选项如下:

GLOBAL

使目标名全局可见。

不生成任何规则来构建 imported target,且 IMPORTED target 属性为 True。imported 库非常适合从诸如 target_link_libraries() 之类的命令进行便捷引用。

通过设置以 IMPORTED_INTERFACE_ 开头的名称的属性来指定 imported 库的详细信息。有关详细信息,请参阅此类属性的文档。

别名库

add_library(<name> ALIAS <target>)

创建一个 别名目标,以便 <name> 可用于引用后继命令中的 <target><name> 不作为构建目标显示在生成的构建系统中。 <target> 不得是 ALIAS

3.11 中新增:一个 ALIAS 可以定位一个 GLOBAL 导入目标

3.18 中新增:一个 ALIAS 可以定位一个非 GLOBAL 导入目标。此类别名作用于创建它的目录及其子目录。我们可以使用 ALIAS_GLOBAL 目标属性检查别名是否是全局别名。

ALIAS 目标可以用作可链接目标和读取属性的目标。此外,它还可以使用常规 if(TARGET) 子命令测试是否存在。<name> 不能用于修改 <target> 的属性,即不能用作 set_property()set_target_properties()target_link_libraries() 等命令的操作数。ALIAS 目标不能安装或导出。

另请参阅