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
產生器表達式的目標所使用的連結語言,不能為 true。
功能名稱區分大小寫,且僅可包含字母、數字和底線。全部大寫的功能名稱保留給 CMake 自己的內建功能(請參閱下方的 預定義功能)。
功能行為的某些方面可以由 CMAKE_<LANG>_LINK_LIBRARY_<FEATURE>_ATTRIBUTES
和 CMAKE_LINK_LIBRARY_<FEATURE>_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]
請注意,即使不使用
$<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
具有相同的連結器約束。