CMAKE_LINK_LIBRARY_USING_<FEATURE>¶
在 3.24 版本中添加。
此变量定义了在使用 LINK_LIBRARY
生成器表达式时,如何为指定的 `<FEATURE>
` 链接库或框架。此变量生效必须同时满足以下两个条件:
关联的
CMAKE_LINK_LIBRARY_USING_<FEATURE>_SUPPORTED
变量必须设置为 true。没有针对同一 `
<FEATURE>
` 的语言特定定义。这意味着对于CMAKE_<LANG>_LINK_LIBRARY_<FEATURE>_SUPPORTED
无法为用于求值LINK_LIBRARY
生成器表达式的目标所使用的链接语言为 true。
功能名称区分大小写,并且只能包含字母、数字和下划线。全大写的功能名称保留给 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
变量的值给出。
例如,对于 `Clang
`,`"LINKER:-z,defs"
` 变为 `-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` 相同的链接器约束。