如果你下載別人的開源代碼,你會發現很多人的項目中有個CMakeLists.txt。其實這是因為他們用cmake這個軟件來編譯整個項目。
為何要用cmake?
如果不用cmake的話那么我們一般會用visual studio這種軟件來編譯運行整個項目。但是這里有個問題我visual studio2010的項目很可能vs2017打不開。這就很麻煩。於是人們開始想我能不能有個軟件,我們寫好各個模塊的依賴關系,以及如何編譯。把這些信息寫成一個文件形式,然后這個軟件能根據這個文件編譯整個項目。並且最好能跨平台編譯,比如我下載的代碼要求既能在win10上編譯也要能在win7上編譯還得在linux上編譯。並且編譯后的可執行文件能兼容當前操作系統。沒錯。cmake都能做到。如果你下載的某個開源軟件不兼容你的操作系統,最好的辦法就是你下載它的源代碼,然后在你的操作系統上重新編譯運行一遍。
案例1:cmake入門
1.1 創建文件
首先當然得安裝cmake這個網上教程多如牛毛就不講了。
然后在當前目錄下創建這兩個文件(如下所示CMakeLists.txt這個文件名是固定的而且大小寫不要錯了,main.c是我們寫的c語言代碼):
.
├── CMakeLists.txt
└── main.c
上述兩個文件的內容分別如下:
<文件CMakeLists.txt的內容>
PROJECT(HELLO)
AUX_SOURCE_DIRECTORY(. DIR_SRCS)
ADD_EXECUTABLE(hello ${DIR_SRCS})
注意:PROJECT()
它是指定當前這個項目的名字,你可以隨便寫的沒關系的。AUX_SOURCE_DIRECTORY()
中的第一個參數是指定源文件所在文件夾(在本例子中是當前目錄,就是一個點),第二個參數是把源文件夾所有源文件名存到DIR_SRCS
這個變量中。ADD_EXECUTABLE()
它指定的是把哪些源文件編譯成目標文件。以及目標文件名叫啥。這這個例子中的目標文件名叫做hello
你可以隨便寫的沒關系的。但是后面那個源文件地址${DIR_SRCS}
這個不能隨便寫,它的意思是讀取DIR_SRCS
這個變量的值(在本例子中這個變量值是源文件名)。
<文件main.c的內容>
#include<stdio.h>
int main()
{
printf("hello world! my first cmake");
return 0;
}
1.2 編譯
- 把命令行的工作目錄切換到在當前有CMakeLists.txt的這個目錄下,
- 然后輸入
cmake ./
,注意后面那是兩個符號“點+斜杠”表示編譯當前目錄。你會發現你當前目錄下多了很多文件。 - 然后輸入
make
產生目標可執行文件。然后你會發現當前文件夾下面多了一個可執行文件hello
。你可以試試./hello
運行這個可執行文件。
$ make
Scanning dependencies of target hello
[ 50%] Building C object CMakeFiles/hello.dir/main.c.o
[100%] Linking C executable hello
[100%] Built target hello
到這里就完全入門了cmake,是不是很簡單。但是你會發現源代碼和目標文件以及編譯的中間代碼都在一個文件夾里面,這個就非常煩人。一般處理方式就是把源代碼和目標文件分開。接下來就是介紹如何將源代碼和目標文件分開編譯。
案例2:cmake工程化
我們把源代碼放在src
這個文件夾內,bin
目錄暫時為空到時候把編譯后的文件全放到bin
文件夾中。記得在當前目錄和src
目錄下面兩個目錄都要創建CMakeLists.txt
.
├── bin
├── CMakeLists.txt
└── src
└── main.c
├── CMakeLists.txt
當然當前目錄下的CMakeLists.txt內容也需要變化(src目錄下的CMakeLists.txt內容為空):
PROJECT(HELLO)
ADD_SUBDIRECTORY(src)
AUX_SOURCE_DIRECTORY(./src DIR_SRCS)
ADD_EXECUTABLE(hello ${DIR_SRCS}
你會發現多了一行ADD_SUBDIRECTORY(src )
,其中ADD_SUBDIRECTORY()
的參數是源代碼存放的文件夾。
然后我們執行編譯命令:cmake .
,然后你會發現bin
這個文件夾里面多了很多內容。接下來我們只需要進入到bin
這個文件夾執行make
命令來生成可執行文件。
案例3:cmake使用頭文件等外部依賴
現在我們在案例2的基礎上在src
目錄下增加一a.h
頭文件。
.
├── bin
├── CMakeLists.txt
└── src
└── main.c
├── a.h
├── CMakeLists.txt
然后src/CMakeLists.txt
這個文件此時需要增加內容了:
AUX_SOURCE_DIRECTORY(. LIB_FILES) # 這個表示獲取當前src目錄下所有文件名並存入LIB_FILES這個變量中
ADD_LIBRARY(LIBS ${LIB_FILES}) # 這個表示將${LIB_FILES}這些文件加入庫中,然后並且復制一份到LIBS這個變量中
項目根目錄下的CMakeLists.txt的文件內容也需要改動:
PROJECT(HELLO)
AUX_SOURCE_DIRECTORY(./src DIR_SRCS)
ADD_EXECUTABLE(hello ${DIR_SRCS})
TARGET_LINK_LIBRARIES(hello ${LIBS}) # 向可執行文件hello提供鏈接庫LIBS是前面提到的變量
cmake編譯生成中間代碼,以及make編譯生成目標可執行文件和前面的操作一樣。都是回到項目根目錄下:
輸入:
$ cmake .
$ make
參考文獻:
[1] https://www.ibm.com/developerworks/cn/linux/l-cn-cmake/