天天看點

cmake終極奧秘

cmake集中開源,跨平台,能夠管理大型項目,簡化編譯建構過程和編譯過程,高效率,可擴充于一體,簡單而強大的項目建構工具

一般不需要安裝,cmake目前已經成為各大linux發行版提供的元件,是以,需要自己動手安裝的可能性很小。如果你使用的作業系統(比如windows或者某些linux版本)沒有提供cmake或者包含的版本較舊,建議你直接從cmake官方網站下載下傳安裝。 cmake官網:https://cmake.org/download/

hello world,世界 你好

一個最簡單的例子helloworld來演練一下cmake的完整建構過程

1、準備工作:

本節對應的源代碼所在目錄:demo1。

建立一個 demo1 檔案,目錄結構如下

所有的cmake練習都會放在/root/cmake的子目錄下

在demo1目錄建立main.c和cmakelists.txt (注意檔案名大小寫):

main.c

cmakelists.txt

cmakelists.txt 的文法比較簡單,由指令、注釋和空格組成,其中指令是不區分大小寫的。符号 <code>#</code> 後面的内容被認為是注釋。指令由指令名稱、小括号和參數組成,參數之間使用空格進行間隔。

對于上面的 cmakelists.txt 檔案,依次出現了幾個指令:

<code>cmake_minimum_required</code>:指定運作此配置檔案所需的 cmake 的最低版本;

<code>project</code>:參數值是 <code>demo1</code>,該指令表示項目的名稱是 <code>demo1</code> 。

<code>add_executable</code>: 将名為 main.c 的源檔案編譯成一個名稱為 demo 的可執行檔案

2、開始建構

所有的檔案建立完成後,demo1目錄中應該存在main.c和cmakelists.txt兩個檔案,如下所示

編譯項目

之後,在 demo1 目錄執行 <code>cmake .</code> ,得到 makefile 後再使用 <code>make</code> 指令編譯得到 demo1 可執行檔案。

3、清理工程:

跟經典的autotools系列工具一樣,運作:

make clean

即可對建構結果進行清理

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

對于cmake,内部編譯上面已經示範過了,它生成了一些無法自動删除的中間檔案,是以,引出了我們對外部編譯的探讨,外部編譯的過程如下:

(1)、建立build目錄

(2)、進入build目錄,運作 <code>cmake ..</code> (注意,…代表父目錄)檢視一下build目錄,就會發現了生成了編譯需要的makefile以及其他的中間檔案。

(3)、運作make建構工程,就會在目前目錄(build目錄)中獲得目标檔案demo。

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

本節對應的源代碼所在目錄:demo2。

先看下目錄結構,代碼是makefile裡面的測試檔案,簡單的調用加減乘除函數

這個時候,cmakelists.txt 可以改成如下的形式:

唯一的改動隻是在 <code>add_executable</code> 指令中增加了一個 <code>dir_srcs</code> 變量。這樣寫的好處就是如果源檔案很多,把所有源檔案的名字都加進去将是一件煩人的工作。更省事的方法是使用 <code>aux_source_directory</code> 指令,該指令會查找指定目錄下的所有源檔案,然後将結果存進指定變量名。其文法如下:

這樣,cmake 會将目前目錄所有源檔案的檔案名指派給變量 <code>dir_srcs</code> ,再訓示變量 <code>dir_srcs</code> 中的源檔案需要編譯成一個名稱為 demo 的可執行檔案。

我們還是使用外部編譯

運作profect完美,簡單又強大。

本節對應的源代碼所在目錄:demo3。

目錄建構如下

對于這種情況,需要分别在項目根目錄 demo3 和 src 目錄裡各編寫一個 cmakelists.txt 檔案。

為了友善,我們可以先将 src 目錄裡的檔案編譯成靜态庫或者動态庫再由 main 函數調用

根目錄makefile

該檔案添加了下面的内容:

第10行,定義變量 <code>use_mycalc</code>,預設為<code>on</code>

第18行,使用指令 <code>add_subdirectory</code> 指明本項目包含一個子目錄 math,這樣 math 目錄下的 cmakelists.txt 檔案和源代碼也會被處理 。

第28行,使用指令 <code>target_link_libraries</code> 指明可執行檔案 demo 需要連接配接一個名為 calc 的連結庫 。

子目錄中的 cmakelists.txt

同樣,我們還是使用外部編譯

使用ldd檢視連結庫的位置,發現<code>libcalc.so</code>在我們指定的<code>lib</code>目錄。

本節對應的源代碼所在目錄:demo4。

cmake 允許為項目增加編譯選項,進而可以根據使用者的環境和需求選擇最合适的編譯方案。

例如,可以将 calc 庫設為一個可選的庫,如果該選項為 <code>on</code> ,就使用該庫定義的函數來進行運算。否則就調用标準庫中的運算符進行操作。

還是之前的代碼,在此基礎上進行增删。

修改 cmakelists 檔案

我們要做的第一步是在頂層的 cmakelists.txt 檔案中添加該選項:

其中:

第10行的 <code>configure_file</code> 指令用于加入一個配置頭檔案 config.h ,這個檔案由 cmake 從 config.h.in 生成,通過這樣的機制,将可以通過預定義一些參數和變量來控制代碼的生成。

第16行的 <code>option</code> 指令添加了一個 <code>use_mycalc</code>選項,并且預設值為 <code>on</code> 。

第20行根據 <code>use_mycalc</code>變量的值來決定是否使用我們自己編寫的 calc庫。

修改 [main.c]檔案,讓其根據 <code>use_mycalc</code> 值來決定是否調用标準庫還是 calc 庫:

編寫 [config.h.in]檔案

上面的程式值得注意的是第2行,這裡引用了一個 config.h 檔案,這個檔案預定義了 <code>use_mycalc</code> 的值。但我們并不直接編寫這個檔案,為了友善從 cmakelists.txt 中導入配置,我們編寫一個 config.h.in 檔案,内容如下:

這樣 cmake 會自動根據 cmakelists 配置檔案中的設定自動生成 config.h 檔案。

同樣使用外部編譯,為了便于互動式的選擇該變量的值,可以使用<code>cmake -i</code> 指令(也可以使用 <code>ccmake</code> 指令,該指令會提供一個會話式的互動式配置界面):

上面是互動指令,有提示讓你輸入選項,回車預設不修改,可設定<code>off</code>和<code>on</code>,

從中可以找到剛剛定義的 <code>use_mycalc</code> 選項,在選項中設定<code>off</code>,make一下運作如下

可以将定義的 <code>use_mycalc</code> 選項,在選項中設定<code>on</code>,重新,make一下運作如下

本節對應的源代碼所在目錄:demo5。

首先先在 子目錄下的cmakelists.txt 檔案裡添加下面兩行:

指明 calc 庫的安裝路徑。之後同樣修改根目錄的 cmakelists 檔案,在末尾添加下面幾行:

通過上面的定制,生成的 demo 檔案和 calc 函數庫 libcalc.so 檔案将會被複制到 <code>/usr/local/bin</code> 中,而 head.h 和生成的 config.h 檔案則會被複制到 <code>/usr/local/include</code> 中。

讓 cmake 支援 gdb 的設定也很容易,隻需要指定 <code>debug</code> 模式下開啟 <code>-g</code> 選項:

之後可以直接對生成的程式使用 gdb 來調試。

另外提一下,<code>cflags</code> 是預先設定的變量。

指令

意義

<code>cflags</code>

c語言編譯器參數。

<code>cxxflags</code>

c++語言編譯器參數。

<code>cppflags</code>

c預處理器參數

<code>ldflags</code>

連結器參數。(如:<code>ld</code> )

​ -dcmake_install_prefix 指定編譯庫安裝路徑

​ -dcmake_system_name 指定系統為linux

​ -dcmake_c_compiler 指定c語言編譯器如交叉編譯器未加入到環境變量,需要使用絕對路徑

​ -dcmake_cxx_compiler 指定c++編譯器

​ -dzlib_include_dir 指定zlib頭檔案目錄

​ -dzlib_library 指定zlib動态庫路徑

​ -dlws_openssl_include_dirs 指定openssl頭檔案目錄

​ -dlws_openssl_libraries 指定openssl動态庫路徑

<code>add_custom_target</code> 的用處:增加一個沒有輸出的目标,使得它總是被建構。

該指令的其他一些參數的含義:

all:表明該目标會被添加到預設的建構目标,使得它每次都被運作;

command:指定要在建構時執行的指令行;

depends:指定指令所依賴的檔案;

comment:在建構時執行指令之前顯示給定消息;

working_directory:使用給定的目前工作目錄執行指令。如果它是相對路徑,它将相對于對應于目前源目錄的建構樹目錄;

byproducts:指定指令預期産生的檔案。

#必須設定然後再使用

繼續閱讀