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
相同的連結器約束。