分享一次學習cmake基礎的過程。

Cmake的簡單學習歷程,用於記錄與分享,共勉。

 

一、單個文件cmake編譯

  1. 本次使用的是MacOS作爲運行的平臺,CMake是跨平臺的,教程在Linux和Windows應該也是可以工用的。
  2. 打開終端,並且新建一個cmake_test文件夾用於保存測試的cmake例程。

mkdir cmake_test

cd cmake_test

  1. 進入cmake_test文件夾後,新建一個main.c的文件。

touch main.c

  1. 再新建CMakeLisrs.txt文件,我們主要編寫的cmake的命令就是在這個文件裏。

touch CMakeLists.txt

  1. 爲了方便編輯代碼,我們打開vscode編輯器,如果沒有下載vscode可以自行安裝,或者使用其他代碼編輯器也可以。

code .

  1. 新建build文件夾用於保存cmake編譯後產生的文件

mkdir build

  1. 現在當前文件夾中的文件總共有三個

  1. 接下來開始編寫main.c文件打印hello world。

  1. 在CMakeLists.txt文件中輸入以下命令

第一句的意思是要求cmake3.0版本以上,可以根據實際設定最低要求版本。

第二句是設置項目名稱。

第三句是關鍵,意思是使用源代碼main.c文件,最後生成可執行的elf文件爲main。

  1. 文件都準備完成後,進入build文件夾,之所以新建build文件夾,是爲了保存cmake編譯生成的文件,與源代碼分開,這樣會更加清晰。

cd build

  1. 開始編譯cmake。兩個點表示上一級目錄,cmake與..中間必須有一個空格,否則會出錯。

cmake ..

  1. 可以看到cmake編譯完成後,會在build(當前文件夾)生成make文件。

ls

  1. 輸入make編譯生成main文件,可以看到main文件的顏色和其他的顏色不同。

  1. 運行mian。可以看到輸出了hello_world!。

./main

  1. 如果想清除make生成的文件,輸入

make clean

 

二、同一目錄下多個文件cmake編譯

1.在cmke_test文件夾下新建fun1.c和fun1.h文件。

2.填入以下內容,函數fun1的功能是打印輸入的數值。

3.修改main.c文件,調用fun1來打印。

4修改CMakeLists.txt文件。

可以看到我們把fun1.c文件添加在main.c的後面,表示調用的源文件是main.c和fun1.c。

5.運行cmake編譯成make文件,再運行make編譯生成main文件,運行main查看輸出結果。

可以看到調用fun1函數成功打印了test_fun1:10。

6.從以上的實驗可以看出,如果在同一目錄下有多個源文件,那麼只要在add_executable裏把所有源文件都添加進去就可以了。但是如果有很多個源文件,這樣每個添加的方式很不合理,無法體現cmake的優越性,cmake提供了一個命令可以把指定目錄下所有的源文件存儲在一個變量中,這個命令就是 aux_source_directory(dir var)。

第一個參數dir是指定目錄,第二個參數var是用於存放源文件列表的變量。

7.新建fun2.c和fun2.h文件,內容如下:

8.修改mian.c文件調用fun2函數。

9.修改CMakeLists.txt文件,

aux_source_directory把當前目錄下的源文件存放到變量SRC_LIST裏,然後在add_executable裏調用SRC_LIST(注意調用變量時的寫法 ${變量})

10.編譯通過後運行main,可以看到fun1,和fun2都打印了對應的值。

 

三、多個目錄下的不同源文件cmake編譯

一般情況下,我們不同功能的源文件會用單獨的文件夾保存,這樣我們就有在多個目錄下調用不同源文件的需求。

1.在cmake_test文件夾下新建fun1和fun2文件夾,在把之前 fun1和fun2的相關文件移動到對應的文件夾下。整理後的文件夾結構如下:

2.修改CMakeLists.txt,增加include_directories (fun1 fun2)命令,意思是告訴編譯器可以到fun1和fun2找頭文件,多個路徑可以用空格鍵分隔。aux_source_directory命令把兩個文件夾保存到對應的變量中。

add_executable把源代碼都添加進去。

 

四、頭文件和源文件分開放cmake編譯

1.當我們有時候需要把頭文件放在同一個文件,而把源文件放在另一個文件夾時,我們可以新建include文件夾用於存放.h文件,新建src文件夾存放.c文件。整理後結構如下圖所示(.gitignore文件是Git的文件,與實際項目無關,可以忽略)

2.修改CMakeLists.txt的內容,add_subdirectory (src)命令的意思是添加源文件的目錄到工程中,參數src是源文件所在的文件夾名,還有其他參數用於指定外部文件夾在輸出文件夾中的位置等,這裏不需要用到可以忽略。

3.上面指定了src爲源文件的目錄,所以當我們運行cmake命令時,就會查找src目錄下的CMakeLists.txt文件,這樣我們需要在src目錄下新建一個CMakeLists.txt,內容如下:

最後一句是set命令,用於定義變量。

第一個參數EXECUTABLE_OUT_PATH

爲cmake自帶的預定義變量,表示目標二進制可執行文件的存放位置。

第二個參數${PROJECT_SOURCE_DIR}/build表示當前工程根目錄下的build文件夾。其中PROJECT_SOURCE_DIR也是cmake自帶的預定義變量,表示工程根目錄。

4.最後工程項目的文件結構如下圖所示:

5.接下來運行cmake .. && make編譯,並且查看生成的文件,可以看到main已經生成,還生成了src文件夾,保存src文件夾下的CMakeLists.txt編譯生成的文件。

6.運行./main,可以看到程序已經可以運行。

五、cmake編譯生成.a靜態庫

1.在cmake_test文件夾下新建lib文件夾,用於保存庫的源文件和頭文件。然後把測試的fun相關的源文件和頭文件放進lib文件夾,並且在lib文件夾下新建CMakeLists.txt文件。最後的結構如下所示。

2.lib下的CMakeLists.txt文件的內容爲:

其中,add_library的功能爲生成動態或靜態庫,第一個參數指定庫的名字,輸出名字時,cmake會自動把庫的前綴和後綴補全,例如此命令會生成名字爲‘liblibFun_static.a’的靜態庫;第二個參數指定是動態庫還是靜態庫,如果沒有指定,默認爲靜態庫,SHARED則指定爲動態庫;第三個參數指定生成庫的源文件。

set_target_properties設置輸出的名稱,如果是動態庫還可以設置版本號等。使用此命令可以把上面命令生成的‘liblibFun_static.a’自動重命名爲‘libfun.a’。

LIBRARY_OUTPUT_PATH:指定庫文件的默認輸出路徑,這裏指定在工程目錄下的lib目錄。

3.開始編譯

cmake .. && make

4.可以看到lib文件夾已經生成了libfun.a的靜態庫。

 

六、cmake鏈接靜態庫

1.在根目錄的CMakeLists.txt文件中添加add_subdirectory (src),表示把告訴cmake去src目錄下執行另一個CMakeLists.txt。

2.在src目錄下添加CMakeLists.txt文件,內容如下:

以上出現了兩個新的命令:

link_directories:告訴cmake要調用的庫的路徑,

target_link_libraries:鏈接目標文件和庫文件。如果不指定全名,默認是鏈接動態庫,由於我們只有靜態庫,所以可以不用設置,如果同時存在動態庫和靜態庫,又只想調用靜態庫,則庫名稱需要寫全名,如target_link_libraries (main libfun.a)

3.爲了測試我們的庫是否調用成功,我們修改main.c文件來變化輸出的內容。將fun1和fun2的輸出值都加1。

4.編譯

cmake .. && make

5.可以使用ls命令查看已經生成main文件,運行./main成功。

 

七、cmake添加編譯選項

有時編譯時需要添加一些編譯選項,如src下有多個項目,有時只需要編譯一個項目即可,但是每次都修改add_executable參數會比較麻煩,所以增加編譯控制選項來修改編譯的項目和生成的名稱。

1.修改根目錄下的CMakeLists.txt文件。

在最前面增加了if邏輯判斷,如果沒有設置PROJ,則參數FATAL_ERROR輸出一個致命性錯誤並且停止後續的編譯,後面的是打印的提示信息,正確的例子:cmake .. -DPROJ=testfun1。如果已經設置了PROJ,則把接收到的PROJ的值打印出來。

project (${PROJ}):設置項目名稱,後面可以直接調用變量PROJECT_NAME表示我們設置項目名稱。

2.在src文件夾下新建testfun1和testfun2文件夾,並且原來src目錄下的main.c文件複製一份後分別移到新建的兩個文件夾中,最終文件夾架構爲:

3.分別修改testfun1和testfun2下的main.c文件。

4.修改src目錄下的CMakeLists.txt文件。

aux_source_directory (${PROJECT_NAME} SRC_LIST):把設置好的項目目錄(src/xxx)添加到變量SRC_LIST中。

add_executable (${PROJECT_NAME} ${SRC_LIST}):設置生成文件爲工程名xxx。

target_link_libraries (${PROJECT_NAME} fun):鏈接庫。

5.開始編譯項目testfun1。並且運行./testfun1。

6.編譯項目testfun2,並且運行./testfun2。

 

八、總結

到此,基礎的cmake操作已經學習完畢,但是還有很多cmake高級的用法沒有學習到,比如其他命令,或者不同的參數的意義等。還是要在實踐中檢驗,cmake作爲跨平臺的編譯工具真的很值得學習,能夠在後續的開發中收益滿滿。

此文是自我學習的記錄與分享,資料參考自網絡,如果文中有不對的地方,請不吝留言指正,感謝大家。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章