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:指定指令預期産生的檔案。
#必須設定然後再使用