iT邦幫忙

2023 iThome 鐵人賽

DAY 12
0
Software Development

30 天 CMake 跨平台之旅系列 第 12

[Day 12] 寫出我的第一個 Library

  • 分享至 

  • xImage
  •  

本日內容

  • Project Layout
  • 以 Link Seams 為例
  • 預告

連結: Day 12 - Colab

Day 8Day 11 都詳細介紹了 CMake 有哪些 library 類型和相關的指令
今天就來動手寫一個 library 吧!

今天會延續昨天結尾介紹的 Link Seams 的設計, 我們來實際依照 Link Seams 的概念來寫寫看
並用昨天提過的 nm, 來看看 INTERFACE_LINK_LIBRARIES_DIRECT 的效果

Project Layout

一樣先來看看今天的專案架構

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 如下圖所示
link_seams.png

以 Link Seams 為例

我們分別看看每個 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 下的 subdirectories

src/lib/CMakeLists.txt

add_subdirectory(middle)
add_subdirectory(seam)
  • 加入 lib 下的 subdirectories

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
)
  • 包含 SeamImpl object library 和 SeamIface interface library
  • 記得 interface library 是不會產生檔案的, 他只是 CMake 中的抽象
    這裡用來將 include 路徑傳給 consuming targets: SeamImpl 和 SeamStub

src/lib/middle/CMakeLists.txt

add_library(Middle STATIC
    middle.cpp
)
target_link_libraries(Middle PRIVATE
    SeamIface
)
  • Middle static library
  • 注意這邊只有 link SeamIface, 並不包含實作

src/lib/bin/CMakeLists.txt

add_executable(Exe1
    exe1.cpp
)
target_link_libraries(Exe1 PRIVATE
    Middle
    SeamImpl
)
  • Exe1 executable
  • SeamIface 的實作是 SeamImpl

src/mock/middle/CMakeLists.txt

add_library(MiddleStub STATIC
    middle_stub.cpp
)
target_link_libraries(MiddleStub PRIVATE
    SeamIface
)
  • Stub object library

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
)
  • TestExe1 executable
  • SeamIface 的實作換成是 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 分別設為 SeamImplSeamStub, 就可以省下一些力氣了

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


上一篇
[Day 11] Library 類型
下一篇
[Day 13] 更多 Library
系列文
30 天 CMake 跨平台之旅30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言