Cmake之CMakeLists.txt
我們知道makefile是在Linux編譯c或者c++程式碼的時候的一種指令碼檔案,但是每一個功能都要寫一個makefile檔案,這樣如果這個工程很大,而且相關性比較強的話,makefile的書寫就會變得相對繁瑣,更要命的是如果以後需要新增新的功能或者是新人需要修改功能的話,看起來就會特別麻煩;因為介於此,cmake的出現就是為了解決這樣的問題,cmake的入門相當容易,而且管理也特別方便簡單,那我們開始吧。
cmake的所有語句都寫在一個CMakeLists.txt的檔案中,CMakeLists.txt檔案確定後,直接使用cmake命令進行執行,但是這個命令要指向CMakeLists.txt所在的目錄,cmake之後就會產生我們想要的makefile檔案,然後再直接make就可以編譯出我們需要的結果了。更簡單的解釋就是cmake是為了生成makefile而存在,這樣我們就不需要再去寫makefile了,只需要寫簡單的CMakeLists.txt即可。
cmake的執行流程很簡單,我們的重點是如何編寫CMakeLists.txt檔案呢,我們通過例子來學習cmake的語法。
例子從這篇文章中學習http://blog.csdn.net/dbzhang800/article/details/6314073,大致如下:
1、一個單檔案的簡單的例子
檔名字為main.c 內容如下:
#include <stdio.h>
int main()
{
printf("Hello World Test!\n");
return 0;
}
CMakeLists.txt檔案內容如下:
project(hello_jelly) set(APP_SRC main.c) add_executable(${PROJECT_NAME} main.c) #print message message(${PROJECT_SOURCE_DIR})
解釋程式碼:
第一個行project不是強制性的,最好加上,這會引入兩個變數:
HELLO_BINARY_DIR, HELLO_SOURCE_DIR
同時也會定義兩個等價的變數:
PROJECT_BINARY_DIR, PROJECT_SOURCE_DIR
外部編譯要時刻區分這兩個變數對應的目錄
可以通過message進行輸出
message(${PROJECT_SOURCE_DIR})
set 命令用來設定變數
add_exectuable 告訴工程生成一個可執行檔案。
add_library 則告訴生成一個庫檔案。
CMakeList.txt 檔案中,命令名字是不區分大小寫的,而引數和變數是大小寫相關的。
然後將以上兩個檔案放在統一目錄下面,注意編譯產生時候分為兩種,一種是直接在當前原始碼目錄執行cmake命令#cmake ./,但是這樣會在當前目錄下產生很多臨時檔案和目錄,另一種方式就是在當前目錄新建一個build目錄,然後我門進入到build目錄,執行命令cmake ../,這樣產生的所有臨時檔案都會生成在build目錄下,而不影響原始碼目錄的程式碼,此處我們採用第二種方法。我們進入到build目錄,執行命令#cmake ../,然後在當前目錄可以看到檔案如下
drwxrwxr-x 3 zqq zqq 4096 9月 28 17:12 CMakeFiles
-rw-rw-r-- 1 zqq zqq 993 9月 28 17:12 cmake_install.cmake
-rw-rw-r-- 1 zqq zqq 5479 9月 28 17:12 Makefile
最後再在此目錄執行make即可生成相應的可執行程式。
2、多個原始檔的操作
hello.h標頭檔案內容如下
#ifndef JELLYHELLO
#define JELLYHELLO
void hello(const char* name);
#endif
hello.c檔案內容
#include <stdio.h>
#include "hello.h"
void hello(const char* name)
{
printf("Hello my name is %s\n",name);
}
main.c檔案內容如下
#include <stdio.h>
#include "hello.h"
int main()
{
printf("Hello World Test!\n");
hello("jelly");
return 0;
}
然後是CMakeLists.txt檔案
project(hello_jelly)
set(APP_SRC main.c hello.c)
add_executable(${PROJECT_NAME} ${SRC_LIST})
#print message
message(${PROJECT_SOURCE_DIR})
然後儲存使用上面的方法進行cmake和make,就可以生成需要的可執行檔案
3、將hello.c生成一個庫來呼叫
如果將hello生成成一個庫來呼叫的話只需要在2的基礎上修改一下CMakeLists.txt檔案再進行編譯即可
修改的CMakeLists.txt如下:
project(hello_jelly)
set(LIB_SRC hello.c)
set(APP_SRC main.c)
add_library(hello ${LIB_SRC})
add_executable(${PROJECT_NAME} ${APP_SRC})
target_link_libraries(${PROJECT_NAME} hello)
#print message
message(${PROJECT_NAME})
相比之下,我們只是添加了一個新的目標hello庫,並將其連結到我們的demo程式
然後同樣的方法進行cmake和make進行編譯
4、工程分類資料夾編譯
在前面,我們成功的使用了庫,但是原始碼都是在同一個路徑下面,這樣如果到時候程式碼量比較大的話,可能就會分類,形成多個資料夾,這樣我們需要把程式碼分開放,此時我們需要些三個CMakeLists.txt檔案,目錄結構如下
drwxrwxr-x 2 zqq zqq 4096 9月 28 17:32 app
drwxrwxr-x 5 zqq zqq 4096 9月 28 17:12 build
-rw-rw-r-- 1 zqq zqq 487 9月 27 14:42 CMakeLists.txt
drwxrwxr-x 2 zqq zqq 4096 9月 28 17:19 libso
我們將main.c程式放在app目錄下面,hello.c hello.h放在libso資料夾下面,然後該資料夾有一個CMakeLists.txt檔案,app和libso資料夾下面也有CMakeLists.txt檔案,這樣就有三個CMakeLists.txt檔案了,那麼我們接下來來編輯這個三個檔案吧。
首先是app資料夾的CMakeLists.txt
project(hello_jelly)
include_directories(${PROJECT_SOURCE_DIR}/../libso)
set(APP_SRC main.c)
add_executable(${PROJECT_NAME} main.c)
target_link_libraries(${PROJECT_NAME} helloso)
message(${PROJECT_SOURCE_DIR})
然後是libso資料夾的CMakeLists.txt,其中SHARED 表示是生成的動態庫,如果把SHARED去掉的話就是生成靜態庫
project(helloso)
set(LIB_SRC hello.c)
add_library(${PROJECT_NAME} SHARED ${LIB_SRC})
最後是外面那個和app在同一目錄下的CMakeLists.txt
cmake_minimum_required (VERSION 3.2)
project(jelly_cmake)
add_subdirectory(./app)
add_subdirectory(./libso)
其表示我們要到./app和./libso資料夾下面去尋找Cmake檔案然後進行編譯
最後我們在build目錄下面去執行上面的命令編譯即可編譯出我們需要的可執行檔案。
#cmake ../
#make
5、Cmake的install簡單使用
我的理解cmake中的install其實就是一個將編譯好的可執行檔案或者是生成的庫檔案將它放到系統對應的位置,比如說可執行檔案直接要放到bin目錄下面,so庫檔案要放在對應的lib目錄下面,我在上面的例子的基礎上修改CMakeLists.txt檔案,編輯完成後編譯的步驟如下,就是多了個install步驟,這樣我們就可以在Linux上面使用該執行檔案,執行檔案會去呼叫so庫。
#cmake ../
#make
#make install
app目錄修改的CMakeLists.txt如下:只是在之前的基礎上加了最後install一行
project(hello_jelly)
include_directories(${PROJECT_SOURCE_DIR}/../libso)
set(APP_SRC main.c)
add_executable(${PROJECT_NAME} main.c)
target_link_libraries(${PROJECT_NAME} helloso)
message(${PROJECT_SOURCE_DIR})
install(TARGETS ${PROJECT_NAME} DESTINATION bin)
libso目錄修改的CMakeLists.txt如下:只是在之前的基礎上加了最後install一行
project(helloso)
set(LIB_SRC hello.c)
add_library(${PROJECT_NAME} SHARED ${LIB_SRC})
install(TARGETS ${PROJECT_NAME} DESTINATION ../lib)
在此需要解釋下這個路徑問題,install(TARGETS ${PROJECT_NAME} DESTINATION bin)這句話的意思是安裝TARGERS hello_jelly這個可執行檔案到${CMAKE_INSTALL_PREFIX}/bin目錄下面,我測試列印我的${CMAKE_INSTALL_PREFIX}路徑是/usr/local路徑,bin前面不能有/,否則會是絕對路徑,它不再會去獲取${CMAKE_INSTALL_PREFIX}路徑,
綜上所述,可執行檔案安裝的路徑是:
/usr/local/bin/
so庫檔案的安裝路徑是:
/usr/local/../lib/
最後執行那三個命令就完了,此時你可以在你的Linux系統裡面的任何目錄執行./hello_jelly
注:如果執行make install的時候出現錯誤,可以加上sudo再次執行試試!!!
相應的原始碼參考連結如下:
如果後續還有其他的理解,我再在此更新!!!