連結: Day 12 - Colab
Day 8 和 Day 11 都詳細介紹了 CMake 有哪些 library 類型和相關的指令
今天就來動手寫一個 library 吧!
今天會延續昨天結尾介紹的 Link Seams 的設計, 我們來實際依照 Link Seams 的概念來寫寫看
並用昨天提過的 nm
, 來看看 INTERFACE_LINK_LIBRARIES_DIRECT
的效果
一樣先來看看今天的專案架構
cmake-example/
├─ src/
│ ├─ lib/
│ │ ├─ seam/
│ │ │ ├─ seam.cpp
│ │ │ ├─ seam_iface.cpp
│ │ │ ├─ CMakeLists.txt
│ │ ├─ middle/
│ │ │ ├─ middle.cpp
│ │ │ ├─ CMakeLists.txt
│ │ ├─ CMakeLists.txt
│ ├─ include/
│ │ ├─ seam/
│ │ │ ├─ seam_iface.h
│ ├─ bin/
│ │ ├─ CMakeLists.txt
│ │ ├─ exe1.cpp
│ ├─ mock/
│ │ ├─ middle/
│ │ │ ├─ middle_stub.cpp
│ │ │ ├─ CMakeLists.txt
│ │ ├─ seam/
│ │ │ ├─ seam_stub.cpp
│ │ │ ├─ CMakeLists.txt
│ ├─ test/
│ │ ├─ test_exe1.cpp
│ │ ├─ CMakeLists.txt
│ ├─ CMakeLists.txt
Link dependency 如下圖所示
我們分別看看每個 CMakeLists.txt
在做什麼src/CMakeLists.txt
cmake_minimum_required(VERSION 3.26)
project(ItHome2023
LANGUAGES C CXX
VERSION 0.1.0
)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
add_subdirectory(bin)
add_subdirectory(lib)
add_subdirectory(mock)
add_subdirectory(test)
CMakeLists.txt
, 通常會用來設定 project-wide 的變數, 並加入 source 下的 subdirectoriessrc/lib/CMakeLists.txt
add_subdirectory(middle)
add_subdirectory(seam)
src/lib/seam/CMakeLists.txt
add_library(SeamImpl OBJECT
seam_impl.cpp
)
add_library(SeamIface INTERFACE)
target_include_directories(SeamIface INTERFACE
${PROJECT_SOURCE_DIR}/include
)
target_link_libraries(SeamImpl PRIVATE
SeamIface
)
src/lib/middle/CMakeLists.txt
add_library(Middle STATIC
middle.cpp
)
target_link_libraries(Middle PRIVATE
SeamIface
)
src/lib/bin/CMakeLists.txt
add_executable(Exe1
exe1.cpp
)
target_link_libraries(Exe1 PRIVATE
Middle
SeamImpl
)
src/mock/middle/CMakeLists.txt
add_library(MiddleStub STATIC
middle_stub.cpp
)
target_link_libraries(MiddleStub PRIVATE
SeamIface
)
src/mock/seam/CMakeLists.txt
add_library(SeamStub OBJECT
seam_stub.cpp
)
target_link_libraries(SeamStub PRIVATE
SeamIface
)
src/test/CMakeLists.txt
add_executable(TestExe1
test_exe1.cpp
)
target_link_libraries(TestExe1 PRIVATE
Middle
SeamStub
)
我們用 nm
來看看 libMiddle.a
的 symbols, 這裡僅節錄部分
build/lib/middle/libMiddle.a(middle.cpp.o):
0000000000000c1c s GCC_except_table36
0000000000000bd0 s GCC_except_table4
0000000000000c2c s GCC_except_table41
0000000000000c04 s GCC_except_table7
U __Unwind_Resume
U __Z10print_seamv 👈
0000000000000000 T __Z12print_middlev
可以看到 print_seam
是 undefined external symbol (U
代表 undefined 或是 unresolved)
正是正確的, 因為 print_seam()
的實作是由最後的 executables 提供
那麼我們接著來看看 executable Exe1 的結果吧 (一樣僅節錄片段)
0000000100003e50 s GCC_except_table36
0000000100003e70 s GCC_except_table36
0000000100003e04 s GCC_except_table4
0000000100003e60 s GCC_except_table41
0000000100003e80 s GCC_except_table41
0000000100003e38 s GCC_except_table7
U __Unwind_Resume
0000000100002a68 T __Z10print_seamv 👈
0000000100003634 T __Z12print_middlev
可以看到 print_seam
這時確實 defined 了!
這樣就大功告成啦!
為了避免重複寫 target_link_libraries(SeamImpl)
, 我們把 Middle 和 MiddleStub 的 INTERFACE_LINK_LIBRARIES_DIRECT
分別設為 SeamImpl
和 SeamStub
, 就可以省下一些力氣了
src/lib/middle/CMakeLists.txt
...
set_target_properties(Middle PROPERTIES
INTERFACE_LINK_LIBRARIES_DIRECT SeamImpl
)
src/mock/middle/CMakeLists.txt
...
set_target_properties(MiddleStub PROPERTIES
INTERFACE_LINK_LIBRARIES_DIRECT SeamStub
)
可以用 nm
再確認一次結果是否和直接 link Middle 或是 MiddleStub 一樣
明天我們會延續今天的 code, 加入更多 libraries