soTest/ ├── CMakeLists.txt # 根配置 ├── so1/ │ ├── CMakeLists.txt │ ├── so1.c │ └── so1.h ├── so2/ │ ├── CMakeLists.txt │ ├── so2.c │ └── so2.h # 依賴 so1 ├── test/ │ ├── CMakeLists.txt │ ├── test.c # 依賴 so2 │ └── test.py # Python 調用 so2 └── build/ # Out-of-source 建構目錄 (不納入版控)
cmake_minimum_required(VERSION 3.0)
project(soTest)
# 統一頭檔搜尋路徑
include_directories(${PROJECT_SOURCE_DIR})
# 庫檔與執行檔輸出目錄統一至 build/libs
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/libs)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/libs)
# 庫檔搜尋路徑優先序
link_directories(${PROJECT_BINARY_DIR}/libs /usr/local/lib /usr/lib)
# 納入子目錄 (各自有 CMakeLists.txt)
add_subdirectory(so1)
add_subdirectory(so2)
add_subdirectory(test)
project(soTest)
set(SO1_SRCS so1.c)
add_library(so1 SHARED ${SO1_SRCS})
project(soTest)
set(SO2_SRCS so2.c)
add_library(so2 SHARED ${SO2_SRCS})
target_link_libraries(so2 so1) # 關鍵:聲明鏈接依賴
project(soTest)
set(TEST_SRCS test.c)
add_executable(st ${TEST_SRCS})
target_link_libraries(st so2 so1) # 遞移依賴自動處理
mkdir build && cd build cmake .. # 生成 Makefile / VS Solution make # 編譯 ./libs/st # 執行測試

| 指令 | 用途 | 備註 |
|---|---|---|
add_library(name SHARED srcs) | 建立動態庫 | 靜態庫用 STATIC,雙模用 BOTH |
target_link_libraries(tgt libs...) | 聲明鏈接依賴 | 現代 CMake 推薦配合 target_include_directories |
set(LIBRARY_OUTPUT_PATH ...) | 指定庫輸出目錄 | 避免散落在各子目錄 |
link_directories(...) | 鏈接器搜尋路徑 | 優先序遞減,建議改用 target_link_directories |
add_subdirectory(dir) | 遞迴處理子目錄 | 子目錄必須有 CMakeLists.txt |
set_target_properties(so1 PROPERTIES VERSION 1.0.0 SOVERSION 1) 生成 libso1.so.1。install(TARGETS so1 so2 st DESTINATION lib/bin) 支援 make install。$<BUILD_INTERFACE:...> / $<INSTALL_INTERFACE:...> 區分建構期/安裝期頭檔路徑。| 平台 | 動態庫前綴/副檔名 | 備註 |
|---|---|---|
| Linux | libxxx.so | soname 機制 |
| Windows | xxx.dll | 需 __declspec(dllexport) 匯出符號 |
| macOS | libxxx.dylib | install_name 機制 |
CMake 會自動處理平台差異,但符號匯出需自行用 #ifdef _WIN32 定義巨集。
CMake 以「宣告式配置 + 原生建構系統生成」解決跨平台構建痛點。本範例展示了**多層庫依賴、統一輸出目錄、Out-of-Source Build** 的最小可行專案結構。實務專案中應善用現代 CMake (3.10+) 的 target_* 族群 API,實現屬性遞移、介面隔離與安裝部署標準化。