看完這篇文章,我終於搞懂了 CMake,真香!-基礎篇-

今天我們就從頭到尾,用最簡單的大白話,把 CMake 的用法講清楚!看完這篇文章,你一定會覺得:“CMake 原來這麼簡單!”

在正式開始之前,先通過一張思維導圖,幫你快速瞭解 CMake 的全貌,這樣你心裏會更有底:

基礎篇

1. 什麼是 CMake?爲什麼用它?

CMake 是一個跨平臺的項目構建工具,通俗點說,它會幫你生成 Makefile 或其他編譯系統需要的構建文件。

用 CMake 的好處:

簡單來說,CMake = 省心 + 高效

2. CMake 的基本使用流程

2.1 基本流程

學習 CMake,就像學做飯,只有幾個簡單步驟:

  1. 寫菜單:創建一個CMakeLists.txt 文件,告訴 CMake 要編譯哪些源文件。

  2. 配置廚房:運行 CMake,生成構建文件(比如 Makefile)。

  3. 開火做飯:用生成的構建文件開始編譯,得到程序。

以下是CMake 與Makefile 的構建流程,幫助你更直觀地理解這些步驟:

項目源碼
   │
   └──► [CMakeLists.txt]  # 編寫 CMake 構建文件
           │
           ▼
         cmake (命令)  # 運行 CMake 命令生成 Makefile
           │
           ▼
      [Makefile]      # 自動生成的 Makefile
           │
           ▼
         make (命令)  # 使用 Makefile 構建目標
           │
           ▼
       目標文件        # 編譯生成的目標文件(如可執行程序或庫)

2.2 關鍵命令

假設你的代碼放在項目目錄my_project/ 下,使用 CMake 的流程如下:

mkdir build           # 創建編譯目錄(推薦在項目外部)
cd build              # 進入編譯目錄
cmake ..              # 生成 Makefile
make                  # 開始編譯
./hello               # 運行可執行文件

3. 第一個簡單的 CMake 項目

3.1 文件結構

我們寫一個最簡單的項目,只有一個main.cpp 文件:

my_project/
├── main.cpp
├── CMakeLists.txt

main.cpp

#include <iostream>
int main() {
    std::cout << "Hello, CMake!" << std::endl;
    return 0;
}

3.2 編寫 CMakeLists.txt

在項目根目錄下,新建一個名爲CMakeLists.txt 的文件,內容如下:

# 指定 CMake 的最低版本
cmake_minimum_required(VERSION 3.10)

# 設置項目名稱
project(HelloCMake)

# 添加可執行文件
add_executable(hello main.cpp)

解釋:

3.3 編譯運行

1、在項目根目錄下新建build 文件夾,並進入:

mkdir build
cd build
  1. 運行 CMake 配置命令:
cmake ..

此時,CMake 會生成Makefile

  1. 執行make 開始編譯:
make
  1. 運行生成的程序:
./hello

你會看到輸出:

Hello, CMake!

恭喜你,第一個簡單的CMake 項目完成了!

4. 支持多源文件和目錄

當你的項目越來越大,源代碼文件越來越多時,你一定會覺得直接在CMakeLists.txt 中寫一堆文件名特別麻煩。別擔心,CMake 給你提供了更優雅的解決方案,讓代碼管理更簡單!

4.1 添加多個源文件

如果你的項目中有多個源文件,像main.cpp 和utils.cpp,你可以直接把它們放到add_executable() 中:

add_executable(hello main.cpp utils.cpp)

這樣,CMake 就會把這些文件一起編譯成一個可執行文件hello。簡單明瞭,對吧?

4.2 使用變量管理源文件

但當源文件越來越多時,手動列出每個文件就顯得很麻煩。這時候,我們可以用變量來管理這些文件,CMake 會幫你搞定。

set(SOURCES main.cpp utils.cpp)
add_executable(hello ${SOURCES})

通過這種方式,你可以輕鬆管理文件列表,未來如果需要增加或刪除文件,只需要修改這個變量,就能一勞永逸。

是不是很方便?

除了自己定義的變量,CMake 還可以訪問系統環境變量。例如,獲取當前用戶的HOME 目錄:

set(MY_PATH $ENV{HOME})

CMake 提供了$ENV{ }語法,用於訪問系統的環境變量,通過$ENV{HOME},CMake 會自動讀取你係統中的HOME 環境變量,把它的值賦給MY_PATH 變量。

4.3 多目錄管理

隨着項目逐漸變大,你的代碼可能會分散到多個目錄中。比如,你可能會有一個src/ 目錄存放核心代碼,一個include/ 目錄存放頭文件,還有一個libs/ 目錄存放外部庫的文件。

到了這個階段,你可能不希望將所有文件都寫在一個 CMakeLists.txt 文件裏了。沒錯,CMake 完全支持這種方式,允許你輕鬆管理多個目錄的代碼。

使用 cmake 來管理項目,目錄結構一般是這樣

my_project/
├── CMakeLists.txt       # 根目錄的 CMake 配置
├── src/
│   ├── CMakeLists.txt   # src 目錄下的 CMake 配置
│   ├── main.cpp
│   ├── utils.cpp
│   └── helper.cpp
├── libs/
│   ├── CMakeLists.txt   # libs 目錄下的 CMake 配置
│   ├── lib.cpp
│   └── lib.h
├── include/
│   ├── utils.h
│   └── helper.h
└── build/               # 構建目錄(自動創建)

在這個結構中,根目錄下有一個CMakeLists.txt 文件,它負責管理整個項目。而src/ 和libs/ 目錄下分別有各自的CMakeLists.txt 文件,用來管理這些目錄中的源文件和庫。這樣,不僅讓項目更有條理,而且也方便管理。

1、根目錄的 CMakeLists.txt

在根目錄的CMakeLists.txt 文件中,我們通常做一些全局的配置,比如設置項目的名字、指定 CMake 最低版本要求,以及引入子目錄等。

# 根目錄的 CMakeLists.txt

# 設置項目名和 CMake 最低版本
cmake_minimum_required(VERSION 3.10)
project(MyProject)

# 添加 src 和 libs 子目錄
add_subdirectory(src)
add_subdirectory(libs)

這裏做了兩件事:

2、src/ 目錄的 CMakeLists.txt

接下來,在src/ 目錄下的CMakeLists.txt 文件中,負責編譯src/ 目錄下的源文件(比如main.cpp 和utils.cpp)。如果有多個源文件,你可以通過變量來管理這些文件。

# src/CMakeLists.txt

# 設置源文件
set(SOURCES
    main.cpp
    utils.cpp
    helper.cpp
)

# 創建可執行文件
add_executable(hello ${SOURCES})

# 設置頭文件路徑
target_include_directories(hello PRIVATE ${PROJECT_SOURCE_DIR}/include)
# PROJECT_SOURCE_DIR:這是一個 CMake 內置的變量,表示項目的源代碼根目錄。
# 無論你在哪個子目錄中,它都會指向項目的最外層目錄:即 my_project/

# 鏈接庫
target_link_libraries(hello PRIVATE mylib)

這段代碼做了幾件事:

3、libs/ 目錄的 CMakeLists.txt

libs/ 目錄下的CMakeLists.txt 文件類似地負責編譯庫文件。

# libs/CMakeLists.txt

# 設置庫文件源代碼
set(LIB_SOURCES
    lib.cpp
)

# 創建靜態庫
add_library(mylib STATIC ${LIB_SOURCES}) # STATIC 可改爲 SHARED 生成動態庫

# 設置頭文件路徑
target_include_directories(mylib PUBLIC ${PROJECT_SOURCE_DIR}/include)

在這裏:

4、項目根目錄的頭文件(include/)

include/ 目錄下存放了項目的頭文件。需要注意的是,你不需要在src/ 和libs/ 的 CMakeLists.txt 文件中列出這些頭文件。

CMake 會自動知道你從include/ 目錄中包含頭文件,只要你確保src/ 和libs/ 目錄下的 CMakeLists.txt 文件中正確配置了target_include_directories()

my_project/
├── include/
│   ├── utils.h
│   └── helper.h

5、添加build/ 目錄

到這裏,你的代碼管理已經非常清晰了,但接下來,我們需要談一談build/ 目錄。build/ 目錄是構建過程中的輸出目錄,它將存放所有編譯產生的中間文件、目標文件和最終的可執行文件。

通常,在 CMake 構建項目時,我們不會直接在源碼目錄下運行構建命令,而是會創建一個單獨的build/ 目錄,這樣可以保持源碼目錄的整潔,同時也可以更方便地管理構建文件。你可以這樣做:

在項目根目錄下創建一個build/ 目錄:

mkdir build
cd build

然後在build/ 目錄下運行cmake 命令,CMake 會自動查找根目錄下的CMakeLists.txt 文件並配置整個項目。

cmake ..

這樣,CMake 會根據根目錄的CMakeLists.txt 配置生成必要的構建文件。

配置完成後,你可以運行make 或其他構建工具來進行編譯:

make

編譯完成後,所有生成的文件(比如目標文件、可執行文件等)都會被放到build/ 目錄裏。源代碼目錄就不會被任何臨時文件污染了,保持整潔。

小結:

通過這種結構和配置方式,CMake 可以非常有效地管理多個目錄下的源代碼和庫:

這種多目錄的管理方式,會讓你的項目變得更加模塊化、易於擴展,同時也方便多人協作開發。如果以後需要添加新的庫或源文件,只需在對應子目錄的CMakeLists.txt 中做調整,而根目錄只需要引入子目錄即可。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/pREDMNf5Uz489giDey4AJQ