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
。可以使用 FRAMEWORK
目标属性将 SHARED
库标记为 macOS Framework。
3.8 版添加: 可以使用 FRAMEWORK
目标属性将 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>
的 导入的库目标。目标名称可能引用项目中构建的任何目标,除非默认情况下,它仅在创建它的目录及其子目录中可见。<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
的库类型通常仅在 查找模块 的实现中使用。它允许 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
目标不能安装或导出。