連結: Day 10 - Colab
今天來講一下有哪些 target shorthands 能用來設定 compiler flags 和 linker flags 能用
由於本系列不會介紹 C++, compiler 或是 linker 的原理, 如果有興趣可以參考 John Levine 的 Linkers and Loaders
在本系列中, 只需要知道 compiler 和 linker 在 build process 中扮演什麼角色即可
CMake 已經將 compiler 和 linker flags 抽象出來, 讓我們在 build target 的時候, 這些 flags 不會 直接直接傳給 CMake 呼叫的 compiler 或是 linker, 而是會先經過一些處理, 比如去重複 (De-duplicating)
所以在執行 compiler 或 linker 的指令可能和預期的不一樣, 後面會說明
在開始介紹 flags 之前, 先來講一下 target 中很重要的部分: Scope Keywords
Day 8 有介紹過可以透過設定 Target Properties 來控制 CMake 如何處理這個 target (ex. executable, library, etc.)
CMake 也可以將某些 target properties 在處理後傳給 compiler 和 linker, 而這些 properteis 是可以被繼承的!
CMake 提供以下幾種 scope keywords 來控制繼承的範圍
PRIVATE
PUBLIC
INTERFACE
所以在設定 compiler 或是 linker flags 前, 要先想想該 flags 是否需要讓 consuming targets 套用相同設定
好啦, 有了這個概念後, 我們來看看 CMake 提供了哪些 compiler 和 linker 相關的 target properties 吧
CMake 將 compiler flags 分為以下幾種類別
這裡會以 gcc
為例, 介紹如何設定 target 的 compiler flags
Note: gcc
flags 可以參考 GNU Compiler Collections
比如我們很常用到的 -O
和 -g
target_include_directories(targetName [AFTER|BEFORE] [SYSTEM]
<PRIVATE|PUBLIC|INTERFACE> dir1 [dir2 ...]
[<PRIVATE|PUBLIC|INTERFACE> dir3 [dir4 ...]]
...
)
AFTER
, BEFORE
include
directories 的路徑順序在後面還是前面SYSTEM
PRIVATE
, PUBLIC
, INTERFACE
target_compile_definitions(targetName
<PRIVATE|PUBLIC|INTERFACE> item1 [item2 ...]
[<PRIVATE|PUBLIC|INTERFACE> item3 [item4 ...]]
...
)
VAR
或是 VAR=VALUE
target_compile_options(targetName [BEFORE]
<PRIVATE|PUBLIC|INTERFACE> item1 [item2 ...]
[<PRIVATE|PUBLIC|INTERFACE> item3 [item4 ...]]
...
)
和 Compiler flags 類似, CMake 將 linker flags 分為以下幾種
target_link_libraries(targetName
<PRIVATE|PUBLIC|INTERFACE> item1 [item2 ...]
[<PRIVATE|PUBLIC|INTERFACE> item3 [item4 ...]]
...
)
item#
target_link_options(targetName [BEFORE]
<PRIVATE|PUBLIC|INTERFACE> item1 [item2 ...]
[<PRIVATE|PUBLIC|INTERFACE> item3 [item4 ...]]
...
)
target_link_libraries
已經做掉了STATIC_LIBRARY_OPTIONS
propertyset_property(STATIC_LIBRARY_OPTIONS)
能用gcc
: Wl,...
clang
: -Xlinker ...
LINKER:
prefix 讓 CMake 能把 linker flags 根據 compiler 轉成對應的 option (希望不會太繞口:p)target_link_options(MyApp PRIVATE
"LINKER:-stats"
)
和 compiler flags 和 linker flags 不同, 他沒有 target property shorthand 能用😭😭😭
所以只能用 set_property()
, 比如
set_property(TARGET TestLib_Greeting PROPERTY
STATIC_LIBRARY_OPTIONS "--thin"
)
會得到
[ 50%] Linking CXX static library libTestLib_Greeting.a
cd /content/cmake-example/cmake-example/cmake-example/build/lib && /usr/local/lib/python3.10/dist-packages/cmake/data/bin/cmake -P CMakeFiles/TestLib_Greeting.dir/cmake_clean_target.cmake
cd /content/cmake-example/cmake-example/cmake-example/build/lib && /usr/local/lib/python3.10/dist-packages/cmake/data/bin/cmake -E cmake_link_script CMakeFiles/TestLib_Greeting.dir/link.txt --verbose=1
/usr/bin/ar qc libTestLib_Greeting.a --thin CMakeFiles/TestLib_Greeting.dir/greeting.cpp.o
/usr/bin/ranlib libTestLib_Greeting.a
gmake[2]: Leaving directory '/content/cmake-example/cmake-example/cmake-example/build'
CMake 會在把 options 傳給 compiler, linker 之前, 先把重複的 options 幹掉, 舉個例子
這在 gcc
沒什麼問題, 但如果今天是用 clang
的話就會壞掉, 因為就像上面提到的, clang
會需要把每個 options 都加上 Xlinker
target_link_options(MyTarget PRIVATE
"LINKER:-stats"
"LINKER:-z,defs"
)
而為了不同 linker 有不同 options 的問題而加的 LINKER:
prefix, 不會受到 de-duplicate 的影響, 但後面的 defs
還是會被刪掉
變成 -Xlinker,-stats -Xlinker,-z,defs
compiler 也會有一樣的狀況
# This won't work as expected either
target_compile_options(MyTarget PRIVATE
-Xassembler --keep-locals
-Xassembler --warn
)
會變成 -Xassembler --keep-locals --warn
[ 75%] Building CXX object CMakeFiles/Main.dir/main.cpp.o
/usr/bin/c++ -I/content/cmake-example/include -std=c++11 -Xassembler --keep --no_esc -MD -MT CMakeFiles/Main.dir/main.cpp.o -MF CMakeFiles/Main.dir/main.cpp.o.d -o CMakeFiles/Main.dir/main.cpp.o -c /content/cmake-example/main.cpp 👈
可以在 option 加上 prefix SHELL:
, 加上之後 CMake 會把 options 合併成空白分隔的 single quoted string, 就不會被 split
來修改上面的例子看看
target_link_options(SomeTarget PRIVATE
"LINKER:SHELL:-stats"
"LINKER:SHELL:-z,defs"
)
linker options 會變成 -Xlinker -stats -Xlinker -z -Xlinker defs
(clang
compiler 的話)
target_compile_options(SomeTarget PRIVATE
"SHELL:-Xassembler --keep-locals"
"SHELL:-Xassembler --warn"
)
compiler options 會變成 -Xassembler --keep-locals -Xassembler --warn
就正常啦!
target_...()
系列的 property command 都可以用 SHELL:
來避免被 de-duplicate
要注意的是, STATIC_LIBRARY_OPTIONS
不支援 LINKER:
下一篇會回頭介紹 Day 8 有大概介紹過幾種的 Library 類型, 但更深入討論, 並附上範例 code~