CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>¶
在版本 3.24 中添加。
当 LINK_LIBRARY
生成器表达式被使用并且目标的链接语言为 <LANG>
时,该变量定义了如何为指定的 <FEATURE>
链接一个库或框架。此变量要产生任何作用,关联的 CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>_SUPPORTED
变量必须设置为 true。
对于与链接语言无关的特性,应改为定义 CMAKE_LINK_LIBRARY_USING_<FEATURE>
变量。
特性名称区分大小写,并且只能包含字母、数字和下划线。使用全大写定义的特性名称保留给 CMake 自带的特性(请参见 预定义特性)。
可以通过 CMAKE_<LANG>_LINK_LIBRARY_<FEATURE>_ATTRIBUTES
变量和 CMAKE_LINK_LIBRARY_<FEATURE>_ATTRIBUTES
变量定义特性行为的某些方面。
特性定义¶
库特性定义是一个包含一个或三个元素的列表
[<PREFIX>] <LIBRARY_EXPRESSION> [<SUFFIX>]
如果指定了 <PREFIX>
和 <SUFFIX>
,它们将分别位于 LINK_LIBRARY
表达式中指定的所有库列表之前和之后,而不是各个库项目。不过,没有保证指定的库列表将保持组合在一起,因此如果由 CMake 重新组织库列表以满足其他约束,<PREFIX>
和 <SUFFIX>
可能出现不止一次。这意味着 --start-group
和 --end-group
等结构(受 GNU ld
链接器支持)不能以这种方式使用。应该为这类结构使用 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()
链接 main
时,CMake 会使用 AppleClang
工具链生成以下链接器命令行片段
-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 目标。使用 MSVC 或类似 MSVC 的工具链的 Windows。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]
请注意,即便不使用
$<LINK_LIBRARY:FRAMEWORK,...>
表达式,CMake 也会识别和自动处理框架目标。如果项目想要明确声明,则仍可将生成器表达式用于 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
具有相同的链接器约束。