CMAKE_LINK_LIBRARY_USING_<功能>¶
3.24 版中添加。
当使用 LINK_LIBRARY
生成器表达式时,此变量定义了在指定 <功能>
中如何链接库或框架。变量生效需同时具备以下两个条件:
关联的
CMAKE_LINK_LIBRARY_USING_<功能>_SUPPORTED
变量必须设置为真。语言特定的
<功能>
没有定义。这意味着CMAKE_<LANG>_LINK_LIBRARY_USING_<功能>_SUPPORTED
不能为目标(对此目标评估LINK_LIBRARY
生成器表达式)所用的链接语言为真。
功能名称区分大小写,只能包含字母、数字和下划线。以全大写形式指定的功能名称为 CMake 的内置功能保留(请参阅下文的 预定义的功能)。
某些功能行为方面可以通过 CMAKE_<LANG>_LINK_LIBRARY_<功能>_ATTRIBUTES
和 CMAKE_LINK_LIBRARY_<功能>_ATTRIBUTES
变量指定。
功能定义¶
库功能定义是一个包含一个或三个元素的列表
[<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"
对于 Clang
来说变为 -Xlinker -z -Xlinker defs
,对于 GNU GCC
来说变为 -Wl,-z,defs
。
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 将生成以下链接表达式
AppleClang
:-force_load /path/to/lib1.a -force_load libexternal.a
GNU
:-Wl,--push-state,--whole-archive /path/to/lib1.a -lexternal -Wl,--pop-state
MSVC
:/WHOLEARCHIVE:/path/to/lib1.lib /WHOLEARCHIVE:external.lib
将库链接为弱库¶
在 macOS 上,有可能用弱模式链接一个库(库及所有引用标记为弱导入)。与按名称指定库相比,对通过文件路径指定的库必须使用不同的标志。此约束可以用 PATH{}
和 NAME{}
包装器来解决。以下示例再次展示了这如何应用于某些链接器,但它仅用于说明目的。相反,项目应该使用内置 WEAK_FRAMEWORK
或 WEAK_LIBRARY
特征(见 预定义特征),它提供了此功能更完整、更健壮的实现。
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 预定义
DEFAULT
此特征对应于标准链接,基本上等同于根本不使用特征。通常它仅与
LINK_LIBRARY_OVERRIDE
和LINK_LIBRARY_OVERRIDE_<LIBRARY>
目标属性一起使用。WHOLE_ARCHIVE
强制包含静态库的所有成员。此特征仅支持以下平台,附有说明的限制
Linux。
所有 BSD 变体。
SunOS。
所有 Apple 变体。库必须指定为 CMake 目标名称、库文件名(如
libfoo.a
)、或库文件路径(如/path/to/libfoo.a
)。由于 Apple 链接器的限制,它不能指定为像foo
这样的普通库名称,其中foo
不是 CMake 目标。Windows。当使用 MSVC 或类似 MSVC 的工具链时,MSVC 版本必须大于 1900。
Cygwin。
MSYS。
FRAMEWORK
此选项告诉链接器使用
-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[suffix]
[/path/to/]FwName.framework/Versions/*/FwName[suffix]
请注意,CMake 能够识别并自动处理框架目标,即使不用
$<LINK_LIBRARY:FRAMEWORK,...>
表达式。如果项目要明确表达,仍然可以在 CMake 目标中使用生成器表达式,但不是必须的。使用或不使用生成器表达式,链接器命令行可能有些差异,但最终结果应该是一样的。另一方面,如果给定了一个文件路径,CMake 能够自动识别一些路径,但不是所有情况。项目可以用$<LINK_LIBRARY:FRAMEWORK,...>
来获取文件路径,以便预期的行为清晰明了。在 3.25 版本中新增:目标属性
FRAMEWORK_MULTI_CONFIG_POSTFIX_<CONFIG>
以及框架库名称的suffix
现在受FRAMEWORK
特性支持。NEEDED_FRAMEWORK
这与
FRAMEWORK
特性类似,但它强制链接器链接框架,即使没有使用其中任何符号。它使用-needed_framework
选项,并具有和FRAMEWORK
相同的链接器约束。REEXPORT_FRAMEWORK
这与
FRAMEWORK
特性类似,但它告诉链接器框架应可用于链接到正在创建的库的客户端。它使用-reexport_framework
选项,并具有和FRAMEWORK
相同的链接器约束。WEAK_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
链接器约束相同。