add_library¶
使用指定源文件向项目添加库。
普通库¶
- add_library(<name> [<type>] [EXCLUDE_FROM_ALL] <sources>...)¶
添加一个名为
<name>的库目标,该目标将从命令调用中列出的源文件构建。可选的
<type>指定要创建的库的类型STATIC一个 静态库:用于链接其他目标的对象文件存档。
SHARED一个 共享库:一个动态库,可以被其他目标链接并在运行时加载。
MODULE一个 模块库:一个插件,不能被其他目标链接,但可以在运行时使用类似 dlopen 的功能动态加载。
如果未给定
<type>,则默认值为STATIC或SHARED,具体取决于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() 添加,则可以省略源文件。
对于 SHARED 和 MODULE 库,POSITION_INDEPENDENT_CODE 目标属性会自动设置为 ON。一个 SHARED 库可以标记 FRAMEWORK 目标属性以创建 macOS 框架。
在版本 3.8 中新增: STATIC 库可以标记 FRAMEWORK 目标属性以创建静态框架。
如果一个库不导出任何符号,则不能将其声明为 SHARED 库。例如,一个不导出任何非托管符号的 Windows 资源 DLL 或托管 C++/CLI DLL 需要是一个 MODULE 库。这是因为 CMake 期望 SHARED 库在 Windows 上总是有一个关联的导入库。
默认情况下,库文件将在与调用命令的源树目录对应的构建树目录中创建。请参阅 ARCHIVE_OUTPUT_DIRECTORY、LIBRARY_OUTPUT_DIRECTORY 和 RUNTIME_OUTPUT_DIRECTORY 目标属性的文档以更改此位置。请参阅 OUTPUT_NAME 目标属性的文档以更改最终文件名的 <name> 部分。
有关定义构建系统属性的更多信息,请参阅 cmake-buildsystem(7) 手册。
另请参阅 HEADER_FILE_ONLY,了解如果某些源文件是预处理过的,并且您希望在 IDE 中访问原始源文件时该怎么做。
在版本 3.30 中更改: 在不支持共享库的平台上,add_library 现在会在创建 SHARED 库的调用时失败,而不是像以前那样自动将其转换为 STATIC 库。请参阅策略 CMP0164。
对象库¶
由 add_library 或 add_executable() 创建的其他目标可以使用 $<TARGET_OBJECTS:objlib> 形式的表达式作为源来引用对象,其中 objlib 是目标库名称。例如
add_library(... $<TARGET_OBJECTS:objlib> ...)
add_executable(... $<TARGET_OBJECTS:objlib> ...)
将 objlib 的目标文件与其自身源文件编译出的目标文件一起包含在一个库和一个可执行文件中。目标库只能包含可编译的源文件、头文件以及不会影响普通库链接的其他文件(例如 .txt)。它们可以包含生成此类源文件的自定义命令,但不能包含 PRE_BUILD、PRE_LINK 或 POST_BUILD 命令。某些原生构建系统(例如 Xcode)可能不喜欢只包含目标文件的目标,因此请考虑向任何引用 $<TARGET_OBJECTS:objlib> 的目标至少添加一个真实的源文件。
在版本 3.12 中新增: 目标库可以使用 target_link_libraries() 进行链接。
接口库¶
- add_library(<name> INTERFACE)¶
添加一个 接口库 目标,该目标可以为依赖项指定使用要求,但不编译源文件,也不在磁盘上生成库工件。
不包含源文件的接口库不作为目标包含在生成的构建系统中。但是,它可以设置属性,并且可以安装和导出。通常,
INTERFACE_*属性使用以下命令填充在接口目标上:然后将其作为参数传递给
target_link_libraries(),就像其他任何目标一样。在版本 3.15 中新增: 接口库可以拥有
PUBLIC_HEADER和PRIVATE_HEADER属性。由这些属性指定的头文件可以使用install(TARGETS)命令安装。
- add_library(<name> INTERFACE [EXCLUDE_FROM_ALL] <sources>...)¶
3.19 版本新增。
添加一个带有源文件(除了
上述签名所述的使用要求和属性之外)的 接口库 目标。源文件可以直接在add_library调用中列出,也可以稍后通过调用带有PRIVATE或PUBLIC关键字的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>的 IMPORTED 库目标。目标名称可以像项目中构建的任何目标一样被引用,但默认情况下,它仅在创建它的目录及其子目录中可见。<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 上特别有用,因为静态库和 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 目标不能安装或导出。