CMAKE_LINK_LIBRARY_USING_<FEATURE>¶
在 3.24 版本加入.
当使用 LINK_LIBRARY 生成器表达式时,此变量定义如何为指定的 <FEATURE> 链接库或框架。要使此变量生效,必须同时满足以下两个条件:
关联的
CMAKE_LINK_LIBRARY_USING_<FEATURE>_SUPPORTED变量必须设置为 true。对于相同的
<FEATURE>没有特定于语言的定义。这意味着CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>_SUPPORTED对于为其评估LINK_LIBRARY生成器表达式的目标使用的链接语言不能为真。
功能名称区分大小写,并且只能包含字母、数字和下划线。以全大写形式定义的功能名称保留给 CMake 自己的内置功能(请参阅下面的“预定义功能”)。
特征定义¶
库特征定义是一个包含一个或三个元素的列表:
[<PREFIX>] <LIBRARY_EXPRESSION> [<SUFFIX>]
当指定 <PREFIX> 和 <SUFFIX> 时,它们分别位于 LINK_LIBRARY 表达式中指定的整个库列表之前和之后,而不是单独的每个库项目。但是,不能保证指定库的列表将保持分组在一起,因此如果库列表由 CMake 重新组织以满足其他要求,<PREFIX> 和``<SUFFIX>`` 可能会出现不止一次约束。这意味着 GNU ld 链接器支持的``--start-group`` 和``--end-group`` 等构造不能以这种方式使用。 LINK_GROUP 生成器表达式应该用于此类构造。
<LIBRARY_EXPRESSION> 用于指定在链接器命令行上为每个库构造相应片段的模式。表达式中可以使用以下占位符:
<LIBRARY>扩展为 CMake 目标库的完整路径,或者扩展为基于项目的平台特定值(与 Windows 上的<LINK_ITEM>或库库相同)其他平台的名称)。<LINK_ITEM>被扩展为通常如何在链接器命令行上链接库。<LIB_ITEM>扩展为 CMake 目标库的完整路径,或者完全按照<LIBRARY_EXPRESSION>中指定的项目本身展开。
除了上述之外,还可以有一种模式用于路径(CMake 目标和外部库指定文件路径),另一种模式用于仅通过名称指定的其他项目。 PATH{} 和 NAME{} 包装器可分别用于为这两种情况提供扩展。使用包装器时,两者都必须存在。例如:
set(CMAKE_LINK_LIBRARY_USING_weak_library
"PATH{-weak_library <LIBRARY>}NAME{LINKER:-weak-l<LIB_ITEM>}"
)
对于此变量的所有三个元素(<PREFIX>、<LIBRARY_EXPRESSION> 和``<SUFFIX>``),可以使用``LINKER:`` 前缀。
为了将选项传递给链接器工具,每个编译器驱动程序都有自己的语法。 LINKER: 前缀和 , 分隔符可用于以可移植的方式指定要传递给链接器工具的选项。 LINKER: 被适当的驱动程序选项和 , 替换为适当的驱动程序分隔符。驱动程序前缀和驱动程序分隔符由 CMAKE_<LANG>_LINKER_WRAPPER_FLAG 和 CMAKE_<LANG>_LINKER_WRAPPER_FLAG_SEP 变量的值给出。
例如,"LINKER:-z,defs" 变成``-Xlinker -z -Xlinker defs`` 对于``Clang`` 和``-Wl,-z,defs`` 对于``GNU GCC ``。
LINKER: 前缀可以指定为 SHELL: 前缀表达式的一部分。
作为一种替代语法,LINKER: 前缀支持使用``SHELL:`` 前缀和空格作为分隔符的参数规范。前面的例子变成了``"LINKER:SHELL:-z defs"``。
备注
不支持在 LINKER: 前缀以外的任何地方指定 SHELL: 前缀。
例子¶
加载整个静态库¶
一个常见的需求是防止链接器丢弃静态库中的任何符号。不同的链接器使用不同的语法来实现这一点。以下示例显示了如何为某些链接器实现这一点。请注意,这仅用于说明目的。项目应该改用内置的“WHOLE_ARCHIVE”功能(请参阅“预定义功能”_),它提供了此功能的更完整和更强大的实现。
set(CMAKE_C_LINK_LIBRARY_USING_load_archive_SUPPORTED TRUE)
if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang")
set(CMAKE_C_LINK_LIBRARY_USING_load_archive "-force_load <LIB_ITEM>")
elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(CMAKE_C_LINK_LIBRARY_USING_load_archive
"LINKER:--push-state,--whole-archive"
"<LINK_ITEM>"
"LINKER:--pop-state"
)
elseif(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
set(CMAKE_C_LINK_LIBRARY_USING_load_archive "/WHOLEARCHIVE:<LIBRARY>")
else()
# feature not yet supported for the other environments
set(CMAKE_C_LINK_LIBRARY_USING_load_archive_SUPPORTED FALSE)
endif()
add_library(lib1 STATIC ...)
add_library(lib2 SHARED ...)
if(CMAKE_C_LINK_LIBRARY_USING_load_archive_SUPPORTED)
# The -force_load Apple linker option requires a file name
set(external_lib
"$<IF:$<LINK_LANG_AND_ID:C,AppleClang>,libexternal.a,external>"
)
target_link_libraries(lib2 PRIVATE
"$<LINK_LIBRARY:load_archive,lib1,${external_lib}>"
)
else()
target_link_libraries(lib2 PRIVATE lib1 external)
endif()
CMake 将生成以下链接表达式:
Apple Clang:-force_load /path/to/lib1.a -force_load lib external.aGNU:-Wl,--push-state,--whole-archive /path/to/lib1.a -lexternal -Wl,--pop-stateMSVC:/WHOLEARCHIVE:/path/to/lib1.lib /WHOLEARCHIVE:external.lib
将库链接为弱¶
在 macOS 上,可以在弱模式下链接库(库和所有引用都标记为弱导入)。与名称指定的库相比,文件路径指定的库必须使用不同的标志。这个约束可以使用 PATH{} 和 NAME{} 包装器来解决。同样,以下示例显示了如何为某些链接器实现这一点,但它仅用于说明目的。项目应该使用内置的 WEAK_FRAMEWORK 或 WEAK_LIBRARY 功能(参见 Predefined Features),它们提供了更完整和更强大的功能实现。
if (CMAKE_C_COMPILER_ID STREQUAL "AppleClang")
set(CMAKE_LINK_LIBRARY_USING_weak_library
"PATH{-weak_library <LIBRARY>}NAME{LINKER:-weak-l<LIB_ITEM>}"
)
set(CMAKE_LINK_LIBRARY_USING_weak_library_SUPPORTED TRUE)
endif()
add_library(lib SHARED ...)
add_executable(main ...)
if(CMAKE_LINK_LIBRARY_USING_weak_library_SUPPORTED)
target_link_libraries(main PRIVATE "$<LINK_LIBRARY:weak_library,lib,external>")
else()
target_link_libraries(main PRIVATE lib external)
endif()
当使用 AppleClang 工具链链接 main 时,CMake 将生成以下链接器命令行片段:
-weak_library /path/to/lib -Xlinker -weak-lexternal。
预定义功能¶
以下内置库功能由 CMake 预定义:
默认此功能对应于标准链接,本质上相当于根本不使用任何功能。它通常只与
LINK_LIBRARY_OVERRIDE和LINK_LIBRARY_OVERRIDE_<LIBRARY>目标属性一起使用。WHOLE_ARCHIVE强制包含静态库的所有成员。仅以下平台支持此功能,但有如下限制:
Linux。
所有 BSD 变体。
太阳操作系统。
所有 Apple 变体。库必须指定为 CMake 目标名称、库文件名(例如
libfoo.a)或库文件路径(例如/path/to/libfoo.a)。由于 Apple 链接器的限制,它不能被指定为像foo这样的普通库名称,其中foo不是 CMake 目标。视窗。使用 MSVC 或类似 MSVC 的工具链时,MSVC 版本必须大于 1900。
西格温。
系统。
框架此选项告诉链接器使用“-framework”链接器选项搜索指定的框架。它只能在 Apple 平台上使用,并且只能与理解所用选项的链接器一起使用(即 Xcode 提供的链接器,或与之兼容的链接器)。
框架可以指定为 CMake 框架目标、裸框架名称或文件路径。如果给出了目标,则该目标必须将
FRAMEWORK目标属性设置为 true。对于文件路径,如果它包含目录部分,则该目录将被添加为框架搜索路径。add_library(lib SHARED ...) target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:FRAMEWORK,/path/to/my_framework>") # The constructed linker command line will contain: # -F/path/to -framework my_framework
文件路径必须符合以下模式之一(
*为通配符,可选部分显示为``[...]``):[/path/to/]FwName[.framework][/path/to/]FwName.framework/FwName[后缀][/path/to/]FwName.framework/Versions/*/FwName[后缀]
请注意,即使不使用
$<LINK_LIBRARY:FRAMEWORK,...>表达式,CMake 也会识别并自动处理框架目标。如果项目想要对其进行明确说明,生成器表达式仍然可以与 CMake 目标一起使用,但这不是必需的。链接器命令行使用与不使用生成器表达式可能会有一些差异,但最终结果应该是一样的。另一方面,如果给定文件路径,CMake 会自动识别某些路径,但不是所有情况。该项目可能希望使用$<LINK_LIBRARY:FRAMEWORK,...>作为文件路径,以便明确预期的行为。在 3.25 版本加入:
FRAMEWORK功能现在支持FRAMEWORK_MULTI_CONFIG_POSTFIX_<CONFIG>目标属性以及框架库名称的suffix。NEEDED_FRAMEWORK这类似于
FRAMEWORK功能,除了它强制链接器与框架链接,即使没有使用它的符号。它使用“-needed_framework”选项,并具有与“FRAMEWORK”相同的链接器约束。REEXPORT_FRAMEWORK这类似于
FRAMEWORK特性,除了它告诉链接器框架应该对链接到正在创建的库的客户端可用。它使用“-reexport_framework”选项,并具有与“FRAMEWORK”相同的链接器约束。弱框架这类似于
FRAMEWORK特性,除了它强制链接器将框架和所有对它的引用标记为弱导入。它使用“-weak_framework”选项,并具有与“FRAMEWORK”相同的链接器约束。NEEDED_LIBRARY这类似于
NEEDED_FRAMEWORK功能,除了它用于非框架目标或库(仅限 Apple 平台)。它根据需要使用“-needed_library”或“-needed-l”选项,并具有与“NEEDED_FRAMEWORK”相同的链接器约束。REEXPORT_LIBRARY这类似于 REEXPORT_FRAMEWORK 功能,除了它用于非框架目标或库(仅限 Apple 平台)。它根据需要使用“-reexport_library”或“-reexport-l”选项,并具有与“REEXPORT_FRAMEWORK”相同的链接器约束。
WEAK_LIBRARY这类似于
WEAK_FRAMEWORK特性,除了它用于非框架目标或库(仅限 Apple 平台)。它根据需要使用“-weak_library”或“-weak-l”选项,并具有与“WEAK_FRAMEWORK”相同的链接器约束。