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 目标属性自动设置为 ONSHARED 库可以使用 FRAMEWORK 目标属性标记以创建 macOS 框架。

3.8 版本新增: STATIC 库可以使用 FRAMEWORK 目标属性标记以创建静态框架。

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

默认情况下,库文件将在构建树目录中创建,该目录对应于调用命令的源代码树目录。 有关更改此位置的信息,请参阅 ARCHIVE_OUTPUT_DIRECTORYLIBRARY_OUTPUT_DIRECTORYRUNTIME_OUTPUT_DIRECTORY 目标属性的文档。 有关更改最终文件名的 <name> 部分的信息,请参阅 OUTPUT_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> 必须是以下之一

STATIC, SHARED, MODULE, UNKNOWN

引用项目外部的库文件。 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 库类型通常仅在 Find Modules 的实现中使用。 它允许使用导入库的路径(通常使用 find_library() 命令找到),而无需知道它是哪种类型的库。 这在 Windows 上尤其有用,在 Windows 上,静态库和 DLL 的导入库都具有相同的文件扩展名。

OBJECT

引用项目外部的一组对象文件。 IMPORTED_OBJECTS 目标属性(或其按配置变量 IMPORTED_OBJECTS_<CONFIG>)指定磁盘上对象文件的位置。 其他用法要求可以在 INTERFACE_* 属性中指定。

INTERFACE

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

选项有

GLOBAL

使目标名称全局可见。

不会生成用于构建导入目标的规则,并且 IMPORTED 目标属性为 True。 导入库对于从诸如 target_link_libraries() 之类的命令中方便地引用非常有用。

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

别名库

add_library(<name> ALIAS <target>)

创建一个 别名目标,以便可以使用 <name> 在后续命令中引用 <target><name> 不会作为 make 目标出现在生成的构建系统中。 <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 目标可能无法安装或导出。

参见