CMake學習筆記一:初識cmake


1 cmake簡介

1.1 背景知識

cmake 是 kitware 公司以及一些開源開發者在開發幾個工具套件(VTK)的過程中衍生品,最終形成體系,成為一個獨立的開放源代碼項目。項目的誕生時間是 2001 年。其官方網站是 www.cmake.org,可以通過訪問官方網站獲得更多關於 cmake 的信息。cmake的流行其實要歸功於 KDE4 的開發,在 KDE 開發者使用了近 10 年 autotools之后,他們終於決定為 KDE4 選擇一個新的工程構建工具,其根本原因用 KDE 開發者的話來說就是:只有少數幾個“編譯專家”能夠掌握 KDE 現在的構建體系。在經歷了 unsermake,scons 以及 cmake 的選型和嘗試之后,KDE4 決定使用 cmake 作為自己的構建系統。在遷移過程中,進展異常的順利,並獲得了 cmake 開發者的支持。所以,目前的 KDE4 開發版本已經完全使用 cmake 來進行構建。像 kdesvn,rosegarden 等項目也開始使用 cmake,這也注定了 cmake 必然會成為一個主流的構建體系。

1.2 特點

  a.開放源代碼,使用類 BSD 許可發布。http://cmake.org/HTML/Copyright.html   b.跨平台,並可生成 native 編譯配置文件,在 Linux/Unix 平台,生成 makefile,在蘋果平台,可以生成 xcode,在 Windows 平台,可以生成 MSVC 的工程文件。   c.能夠管理大型項目,KDE4 就是最好的證明。   d.簡化編譯構建過程和編譯過程。Cmake 的工具鏈非常簡單:cmake+make。   e.高效率,按照 KDE 官方說法,CMake 構建 KDE4 的 kdelibs 要比使用 autotools 來構建 KDE3.5.6 的 kdelibs 快 40%,主要是因為 Cmake 在工具鏈中沒有 libtool。

  d.可擴展,可以為 cmake 編寫特定功能的模塊,擴充 cmake 功能。


2 安裝cmake

cmake 目前已經成為各大 Linux 發行版提供的組件,比如 Ubuntu 直接在系統中包含,所以,需要自己動手安裝的可能性很小。如果你使用的操作系統沒有提供 cmake 或者包含的版本較舊,有以下兩種下載方法。

可以直接在命令行下載cmake:

$ sudo apt-get install cmakek

也可以從官網下載最新版本:

http://www.cmake.org/HTML/Download.html

3 最簡單的例子:HelloWorld

下面選擇一個最簡單的例子 Helloworld 來演練一下 cmake 的完整構建過程,並不 會深入的探討 cmake,僅僅展示一個簡單的例子,並加以粗略的解釋。

1,准備工作

首先,在/backup 目錄建立一個 cmake 目錄,用來放置我們學習過程中的所有練習。

$ mkdir -p /backup/cmake

然后在 cmake 建立第一個練習目錄 t1 。

$ cd /backup/cmake
$ mkdir t1
$ cd t1

在 t1 目錄建立 main.c 和 CMakeLists.txt(注意文件名大小寫)。

main.c 文件內容:

#include<stdio.h>
int main()
{
    printf("Hello world!\n");
    return 0;
}

CmakeLists.txt 文件內容:

PROJECT (HELLO)
SET(SRC_LIST main.c)
MESSAGE(STATUS "This is BINARY dir " ${HELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir " ${HELLO_SOURCE_DIR})
ADD_EXECUTABLE(hello ${SRC_LIST})

2,開始構建 

所有的文件創建完成后,t1 目錄中應該存在 main.c 和 CMakeLists.txt 兩個文件。接下來我們來構建這個工程,在這個目錄運行(注意命令后面的點號,代表本目錄):

$ cmake .

輸出大概是這個樣子:

-- Check for working C compiler: /usr/bin/gcc
-- Check for working C compiler: /usr/bin/gcc -- works
-- Check size of void*
-- Check size of void* - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- This is BINARY dir /backup/cmake/t1
-- This is SOURCE dir /backup/cmake/t1
-- Configuring done
-- Generating done
-- Build files have been written to: /backup/cmake/t1

再讓我們看一下目錄中的內容,你會發現,系統自動生成了: CMakeFiles, CMakeCache.txt, cmake_install.cmake 等文件,並且生成了Makefile。

現在不需要理會這些文件的作用,以后你也可以不去理會。最關鍵的是,它自動生成了Makefile.。

然后進行工程的實際構建,在這個目錄輸入 make 命令,大概會得到如下的彩色輸出:

Scanning dependencies of target hello
[100%] Building C object CMakeFiles/hello.dir/main.o
Linking C executable hello
[100%] Built target hello

如果你需要看到 make 構建的詳細過程,可以使用 make VERBOSE=1 或者 VERBOSE=1 make 命令來進行構建。

這時候,我們需要的目標文件 hello 已經構建完成,位於當前目錄,嘗試運行一下:

$ ./hello

得到輸出:

Hello World from Main 

恭喜您,到這里為止您已經完全掌握了 cmake 的使用方法。


3,簡單的解釋 

我們來重新看一下 CMakeLists.txt,這個文件是 cmake 的構建定義文件,文件名是大小寫相關的,如果工程存在多個目錄,需要確保每個要管理的目錄都存在一個CMakeLists.txt。(關於多目錄構建,后面我們會提到,這里不作過多解釋)。

上面例子中的 CMakeLists.txt 文件內容如下:

PROJECT (HELLO)
SET(SRC_LIST main.c)
MESSAGE(STATUS "This is BINARY dir " ${HELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir " ${HELLO_SOURCE_DIR})
ADD_EXECUTABLE(hello ${SRC_LIST})

PROJECT 指令的語法是 :

PROJECT(projectname [CXX] [C] [Java])

你可以用這個指令定義工程名稱,並可指定工程支持的語言,支持的語言列表是可以忽略的,默認情況表示支持所有語言。

這個指令隱式的定義了兩個 cmake 變量: <projectname>_BINARY_DIR 以及<projectname>_SOURCE_DIR,這里就是HELLO_BINARY_DIRHELLO_SOURCE_DIR(所以 CMakeLists.txt 中兩個 MESSAGE指令可以直接使用這兩個變量),因為采用的是內部編譯,兩個變量目前指的都是工程所在路徑/backup/cmake/t1,后面我們會講到外部編譯,兩者所指代的內容會有所不同。

同時 cmake 系統也幫助我們預定義了 PROJECT_BINARY_DIRPROJECT_SOURCE_DIR變量,他們的值分別跟 HELLO_BINARY_DIRHELLO_SOURCE_DIR 一致。為了統一起見,建議以后直接使用PROJECT_BINARY_DIRPROJECT_SOURCE_DIR,即使修改了工程名稱,也不會影響這兩個變量。


SET 指令的語法是 :

SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])

現階段,你只需要了解 SET 指令可以用來顯式的定義變量即可。

比如我們用到的是 SET(SRC_LIST main.c),如果有多個源文件,也可以定義成:

SET(SRC_LIST main.c t1.c t2.c)。


MESSAGE 指令的語法是:

MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] "message to display" ...)

這個指令用於向終端輸出用戶定義的信息,包含了三種類型:

  • SEND_ERROR,產生錯誤,生成過程被跳過。
  • SATUS,輸出前綴為—的信息。
  • FATAL_ERROR,立即終止所有 cmake 過程.

我們在這里使用的是 STATUS 信息輸出,演示了由 PROJECT 指令定義的兩個隱式變量 HELLO_BINARY_DIR 和 HELLO_SOURCE_DIR。


ADD_EXECUTABLE 指令的語法是:

ADD_EXECUTABLE(hello $)

定義了這個工程會生成一個文件名為 hello 的可執行文件,相關的源文件是 SRC_LIST 中定義的源文件列表, 本例中你也可以直接寫成 ADD_EXECUTABLE(hello main.c)。


在本例我們使用了 \({} 來引用變量,這是 cmake 的變量應用方式</span>,但是,有一些例外,比如在 IF 控制語句,變量是直接使用變量名引用,而不需要\)。如果使用了$去應用變量,其實 IF 會去判斷名為$所代表的值的變量,那當然是不存在的了。

將本例改寫成一個最簡化的 CMakeLists.txt:

PROJECT(HELLO)
ADD_EXECUTABLE(hello main.c)

4 基本語法規則

前面提到過,cmake 其實仍然要使用”cmake 語言和語法”去構建,上面的內容就是所謂的”cmake 語言和語法”,最簡單的語法規則是:

  1. 變量使用$方式取值,但是在 IF 控制語句中是直接使用變量名
  2. 指令(參數 1 參數 2... ) 【參數使用括弧括起,參數之間使用空格或分號分開】
  3. 指令是大小寫無關的,參數和變量是大小寫相關的。但推薦你全部使用大寫指令。

5 關於語法的疑惑

cmake 的語法還是比較靈活而且考慮到各種情況,比如

SET(SRC_LIST main.c)也可以寫成 SET(SRC_LIST “main.c”)

是沒有區別的,但是假設一個源文件的文件名是 fu nc.c(文件名中間包含了空格)。這時候就必須使用雙引號,如果寫成了 SET(SRC_LIST fu nc.c),就會出現錯誤,提示你找不到 fu 文件和 nc.c 文件。這種情況,就必須寫成: SET(SRC_LIST “fu nc.c”)


6 清理工程

運行:

make clean

即可對構建結果進行清理。


7 內部構建與外部構建

上面的例子展示的是“內部構建”,相信看到生成的臨時文件比您的代碼文件還要多的時候,估計這輩子你都不希望再使用內部構建。

而外部編譯的過程如下:

  1. 首先,請清除 t1 目錄中除 main.c CmakeLists.txt 之外的所有中間文件,最關鍵的是 CMakeCache.txt。
  2. 在 t1 目錄中建立 build 目錄,當然你也可以在任何地方建立 build 目錄,不一定必須在工程目錄中。
  3. 進入 build 目錄,運行 cmake ..(注意,..代表父目錄,因為父目錄存在我們需要的CMakeLists.txt,如果你在其他地方建立了 build 目錄,需要運行 cmake <工程的全路徑>),查看一下 build 目錄,就會發現了生成了編譯需要的 Makefile 以及其他的中間文件。
  4. 運行 make 構建工程,就會在當前目錄(build 目錄)中獲得目標文件 hello。

上述過程就是所謂的 out-of-source 外部編譯,一個最大的好處是,對於原有的工程沒有任何影響,所有動作全部發生在編譯目錄。通過這一點,也足以說服我們全部采用外部編譯方式構建工程。


8 小結

本小節描述了使用 cmake 構建 Hello World 程序的全部過程,並介紹了三個簡單的指令:PROJECT/MESSAGE/ADD_EXECUTABLE 以及變量調用的方法,同時提及了兩個隱式變量<projectname>_SOURCE_DIR 及<projectname>_BINARY_DIR,演示了變量調用的方法 。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM