Home CMake教學系列三建立CMake專案
Post
Cancel

CMake教學系列三建立CMake專案

下載範例

下面指令將會下載本文所需的範例

1
2
git clone https://gitlab.com/CLIUtils/modern-cmake.git
cd modern-cmake/examples/simple-project/

CMakeLists.txt解說

  • 在第29行add_library(MyLibExample simple_lib.cpp simple_lib.hpp)增加了一個名為MyLibExampletarget並且將會編譯一個MyLibExamplelibrary
  • 第34行增加了一個add_executable(MyExample simple_example.cpp)增加了一個名為MyExampletarget並且將會編譯一個MyExample的執行檔
  • 第38行target_link_libraries(MyExample PRIVATE MyLibExample)連接了MyLibExampleMyExample這兩個target,注意你必須先製作target才能夠連接他們

建置專案、編譯

接下來你可以用以下指令建置專案並且編譯。CMake會產生一個build資料夾,在裡面你應該會看到libMyLibExample.alibrary和MyExample執行檔。你可以查看CMakeCache.txt看有哪些cache variable,接下來用./build/MyExample執行MyExample執行檔

1
2
cmake -S . -B build
cmake --build build -j 8

常見錯誤

路徑中有空白

1
set(VAR a b v)

這個寫法會讓VAR變成一個list,並且擁有a b c三個元素,因此如果你的路徑像這樣,你的路徑就會被拆成兩段。

1
2
set(MY_DIR "/path/with spaces/")
target_include_directories(target PRIVATE ${MY_DIR})

解決方法就是在${MY_DIR}外面再包一個引號

1
2
set(MY_DIR "/path/with spaces/")
target_include_directories(target PRIVATE "${MY_DIR}")

除錯

印出變數

雖然message指令也可以印出變數,不過你有更好的選擇,cmake_print_propertiescmake_print_variables,記得要先include(CMakePrintHelpers)。如此一來你可以更加容易的印出target的屬性

1
2
3
4
5
6
include(CMakePrintHelpers)
cmake_print_variables(MY_VARIABLE)
cmake_print_properties(
    TARGETS my_target
    PROPERTIES POSITION_INDEPENDENT_CODE
)

–trace-source 和 –trace-expand

--trace-source讓你可以指定只要看你想看的CMakeLists.txt--trace-expand變數全部展開,例如原本是

1
add_library(simple_lib ${SOURCES} ${HEADERS} )

加了--trace-expand變成

1
add_library(simple_lib simple_lib.c simple_lib.h )

下載這個範例,並且試看看cmake -S . -B build --trace-source=CMakeLists.txtcmake -S . -B build --trace-source=CMakeLists.txt --trace-expand有什麼不一樣

1
2
git clone git@github.com:hsf-training/hsf-training-cmake-webpage.git
cd hsf-training-cmake-webpage/code/04-debug

除錯CMake的find_…模組

沿用上面的範例,在這個範例你可以看到第16行有一個find_library(MATH_LIBRARY m)

1
2
git clone git@github.com:hsf-training/hsf-training-cmake-webpage.git
cd hsf-training-cmake-webpage/code/04-debug

試看看cmake -S . -B build --debug-find。記得要先清除build資料夾否會出現debug訊息。你也可以用CMAKE_FIND_DEBUG_MODE來針對你想要debug的find_…模組來除錯

1
2
3
set(CMAKE_FIND_DEBUG_MODE TRUE)
find_program(...)
set(CMAKE_FIND_DEBUG_MODE FALSE)

設定build types

如果你想要執行C++ debugger,你會需要設定很多flag,CMake提供四種build types來幫你設定這些flag。

  • CMAKE_BUILD_TYPE=Debug : 輸出所有除錯訊息
  • CMAKE_BUILD_TYPE=RelWithDebInfo : release build 不過有一些額外的除錯訊息
  • CMAKE_BUILD_TYPE=Release : 最佳化release build
  • CMAKE_BUILD_TYPE=MinSizeRel : minimum size release 下面範例示範如何用CMake的Debug模式編譯,並且用GDB除錯
    1
    2
    3
    4
    
    cd hsf-training-cmake-webpage/code/04-debug
    cmake -S . -B build-debug -DCMAKE_BUILD_TYPE=Debug
    cmake --build build-debug
    gdb build-debug/simple_example
    

    GDB指令

    1
    2
    3
    4
    5
    
    # GDB                
    break my_sin         
    r       
    watch sign   
    c             
    

尋找套件

1
find_package(MyPackage 1.2)

這個命令會首先尋找CMAKE_MODULE_PATH這份路徑清單,在這些路徑底下尋找FindMyPackage.cmake這個檔案,注意他是直接把find_package第一個參數MyPackage產生出FindMyPackage.cmake這個搜尋目標,所以如果我們寫成find_package(OpenCV 3),那搜尋目標就是FindOpenCV.cmake
如果找不到FindMyPackage.cmake他就會接著尋找MyPackageConfig.cmake,如果MyPackage_DIR存在的話也會搜尋這個路徑。 在CMake3.12+之後,如果你的套件不是安裝在系統預設路徑,你可以設定環境變數<PackageName>_ROOT讓CMake搜尋。以下以Bash命令設定環境變數為例

1
export HDF5_ROOT=$HOME/software/hdf5-1.12.0

或者是設定CMAKE環境變數,以下以Bash命令設定環境變數為例

1
export CMAKE_PREFIX_PATH=$HOME/software/hdf5-1.12.0:$HOME/software/boost-1.74.0:$CMAKE_PREFIX_PATH

FindPackage.cmake

這是舊方法(MODULE方法),這裡有CMake提供的FindPackage清單

PackageConfig

這是由package開發者所提供,簡而言之如果你是package開發者,你應該提供<package>Config.cmake並且自行維護。

CMake結合PkgConfig

參考:
https://hsf-training.github.io/hsf-training-cmake-webpage/08-debugging/index.html

https://hsf-training.github.io/hsf-training-cmake-webpage/09-findingpackages/index.html

現代CMake觀念 https://pabloariasal.github.io/2018/02/19/its-time-to-do-cmake-right/

CMake結合PkgConfig https://stackoverflow.com/a/74038236

This post is licensed under CC BY 4.0 by the author.

CMake教學系列二 CMake的觀念

實作yolov1