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>
可能會出現多次。這表示像 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
具有相同的連結器約束。