1. 程式人生 > >cmake簡單使用及編譯專案打包成so檔案

cmake簡單使用及編譯專案打包成so檔案

簡介

CMake是一個跨平臺的編譯自動配置工具,它使用一個名為CMakeLists.txt的檔案來描述構建過程,可以產生標準的構建檔案。它可以用簡單的語句來描述所有平臺的安裝(編譯過程)。它能夠輸出各種各樣的makefile或者project檔案,能測試編譯器所支援的C++特性,類似UNIX下的automake。CMake並不直接建構出最終的軟體,而是產生標準的建構檔(如Unix的Makefile或Windows Visual C++的projects/workspaces),然後再依一般的建構方式使用。

CMake可以編譯原始碼、製作程式庫、產生介面卡(wrapper)、還可以用任意的順序建構執行檔。CMake支援in-place建構(二進檔和原始碼在同一個目錄樹中)和out-of-place建構(二進檔在別的目錄裡),因此可以很容易從同一個原始碼目錄樹中建構出多個二進檔。CMake也支援靜態與動態程式庫的建構。CMake是一個比make更高階的編譯配置工具。

         CMake的組態檔取名為CMakeLists.txt。組態檔是用一種建構軟體專用的特殊程式語言寫的CMake指令碼。檔案CMakeLists.txt需要手工編寫,也可以通過編寫指令碼進行半自動的生成。通過編寫CMakeLists.txt,可以控制生成的Makefile,從而控制編譯過程。

CMake主要特點:

(1)、開放原始碼,使用類BSD許可釋出;

(2)、跨平臺,並可生成native編譯配置檔案,在Linux/Unix平臺,生成makefile;在蘋果平臺,可以生成xcode;在windows平臺,可以生成msvc的工程檔案

(3)、能夠管理大型專案;

(4)、簡化編譯構建過程和編譯過程,CMake的工具鏈非常簡單:cmake+make

(5)、高效率;

(6)、可擴充套件,可以為cmake編寫特定功能的模組,擴充cmake功能。

檢視Ubuntu14.0464位機上是否安裝了CMake及版本號,可通過執行一下語句來驗證:

cmake --version  

 

Linux下安裝cmake

1、從官網下載cmake安裝包,輸入指令解壓縮

sudo tar -zxvf cmake-3.8.2.tar.gz 
2、進入解壓縮後的資料夾中,依次輸入

  1. sudo ./bootstrap
  2. sudo make
  3. sudo make install

或者直接命令安裝:

apt-get install cmake

3、安裝檢查:輸入命令,

cmake --version

若出現對應cmake的版本,則說明安裝成功,一般預設安裝在 /usr/local/bin 目錄下。

簡單使用

a、新建目錄hello, 依次建立檔案main.c, CMakeLists.txt, build目錄

b、main.c 檔案程式碼如下

#include <stdio.h>
int main(void)
{
    printf("Hello\n");
	return 0;
}

c、CMakeLists.txt 檔案程式碼如下

CMAKE_MINIMUM_REQUIRED(VERSION 3.8) #cmake最低版本需求,不加入此行會受到警告資訊
PROJECT(HELLO) #專案名稱  
AUX_SOURCE_DIRECTORY(. SRC_LIST) #把當前目錄(.)下所有原始碼檔案和標頭檔案加入變數SRC_LIST
ADD_EXECUTABLE(hello ${SRC_LIST}) #生成應用程式 hello (在windows下會自動生成hello.exe)

d、進入build 目錄,依次輸入

cmake ..
make
./hello

沒錯,就這麼簡單。

過程如下:

 

常用命令介紹

CMakeLists.txt的語法比較簡單,由命令註釋空格組成,其中命令是不區分大小寫的,引數和變數是大小寫相關的,但,推薦全部使用大寫指令。符號”#”後面的內容被認為是註釋。命令由命令名稱、小括號和引數組成,引數之間使用空格或分號進行間隔。變數使用${xxx}引用。

 

1)project 命令

命令語法:project(<projectname> [languageName1 languageName2 … ] )

命令簡述:用於指定專案的名稱

使用範例:project(Main)

2)cmake_minimum_required命令

命令語法:cmake_minimum_required(VERSION major[.minor[.patch[.tweak]]][FATAL_ERROR])

命令簡述:用於指定需要的 CMake 的最低版本

使用範例:cmake_minimum_required(VERSION 2.8)

3)aux_source_directory命令

命令語法:aux_source_directory(<dir> <variable>)

命令簡述:用於將 dir 目錄下的所有原始檔的名字儲存在變數 variable 中,該命令會把引數<dir>中所有的原始檔(不包括標頭檔案)名稱賦值給引數<variable>;

使用範例:aux_source_directory(.  DIR_SRCS)

4)add_executable 命令

命令語法:add_executable(<name> [WIN32] [MACOSX_BUNDLE][EXCLUDE_FROM_ALL] source1 source2 … sourceN)

命令簡述:用於指定從一組原始檔 source1 source2 … sourceN 編譯出一個可執行檔案且命名為 name

使用範例:add_executable(Main ${DIR_SRCS})

5)add_library 命令

命令語法:add_library([STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] source1source2 … sourceN)

命令簡述:用於指定從一組原始檔 source1 source2 … sourceN 編譯出一個庫檔案且命名為 name

可以設定要生成的連結庫為SHARED或者STATIC,還可以設定MODULE(外掛,可動態呼叫,但不作為其它工程的依賴);

使用範例:add_library(Lib ${DIR_SRCS}) ;add_library(utils SHARED ${utils_dir}) 

6)add_dependencies 命令

命令語法:add_dependencies(target-name depend-target1 depend-target2 …)

命令簡述:用於指定某個目標(可執行檔案或者庫檔案)依賴於其他的目標。這裡的目標必須是 add_executable、add_library、add_custom_target 命令建立的目標

7)add_subdirectory 命令

命令語法:add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

命令簡述:用於新增一個需要進行構建的子目錄

使用範例:add_subdirectory(Lib)

8)target_link_libraries命令

命令語法:target_link_libraries(<target> [item1 [item2 […]]][[debug|optimized|general] ] …)

命令簡述:用於指定 target 需要連結 item1 item2 …。這裡 target 必須已經被建立,連結的 item 可以是已經存在的 target(依賴關係會自動新增)

使用範例:target_link_libraries(Main Lib) ; target_link_libraries(myproj ${OpenCV_LIBS} utils facedetect)

9)set 命令

命令語法:set(<variable> <value> [[CACHE <type><docstring> [FORCE]] | PARENT_SCOPE])

命令簡述:用於設定變數 variable 的值為 value。如果指定了 CACHE 變數將被放入 Cache(快取)中。

使用範例:set(ProjectName Main)

10)unset 命令

命令語法:unset(<variable> [CACHE])

命令簡述:用於移除變數 variable。如果指定了 CACHE 變數將被從 Cache 中移除。

使用範例:unset(VAR CACHE)

11)message 命令

命令語法:message([STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR] “message todisplay”…)

命令簡述:用於輸出資訊

使用範例:message(“Hello World”)

12)include_directories 命令

命令語法:include_directories([AFTER|BEFORE] [SYSTEM] dir1 dir2 …)

命令簡述:用於設定目錄,這些設定的目錄將被編譯器用來查詢 include 檔案

                 指定標頭檔案的搜尋路徑,用來向工程新增多個特定的標頭檔案搜尋路徑,可以多次呼叫以設定多個路徑,相當於指定gcc的-I引數;

使用範例:include_directories(${PROJECT_SOURCE_DIR}/lib),include_directories(facedetect utils)

13)find_path 命令

命令語法:find_path(<VAR> name1 [path1 path2 …])

命令簡述:用於查詢包含檔案 name1 的路徑,如果找到則將路徑儲存在 VAR 中(此路徑為一個絕對路徑),如果沒有找到則結果為 <VAR>-NOTFOUND。預設的情況下,VAR 會被儲存在 Cache 中,這時候我們需要清除 VAR 才可以進行下一次查詢(使用 unset 命令)。

使用範例:

find_path(LUA_INCLUDE_PATH lua.h${LUA_INCLUDE_FIND_PATH})

if(NOT LUA_INCLUDE_PATH)

   message(SEND_ERROR "Header file lua.h not found")

endif()

14)find_library 命令

命令語法:find_library(<VAR> name1 [path1 path2 …])

命令簡述:用於查詢庫檔案 name1 的路徑,如果找到則將路徑儲存在 VAR 中(此路徑為一個絕對路徑),如果沒有找到則結果為 <VAR>-NOTFOUND。一個類似的命令 link_directories 已經不太建議使用了

15)add_definitions 命令

命令語法:add_definitions(-DFOO -DBAR …)

命令簡述:用於新增編譯器命令列標誌(選項),通常的情況下我們使用其來新增前處理器定義

使用範例:add_definitions(-D_UNICODE -DUNICODE)

16)execute_process 命令

命令語法:

execute_process(COMMAND <cmd1>[args1...]]

                  [COMMAND <cmd2>[args2...] [...]]

                  [WORKING_DIRECTORY<directory>]

                  [TIMEOUT <seconds>]

                  [RESULT_VARIABLE<variable>]

                  [OUTPUT_VARIABLE<variable>]

                  [ERROR_VARIABLE<variable>]

                  [INPUT_FILE <file>]

                  [OUTPUT_FILE <file>]

                  [ERROR_FILE <file>]

                  [OUTPUT_QUIET]

                  [ERROR_QUIET]

                 [OUTPUT_STRIP_TRAILING_WHITESPACE]

                 [ERROR_STRIP_TRAILING_WHITESPACE])

命令簡述:用於執行一個或者多個外部命令。每一個命令的標準輸出通過管道轉為下一個命令的標準輸入。WORKING_DIRECTORY 用於指定外部命令的工作目錄,RESULT_VARIABLE 用於指定一個變數儲存外部命令執行的結果,這個結果可能是最後一個執行的外部命令的退出碼或者是一個描述錯誤條件的字串,OUTPUT_VARIABLE 或者 ERROR_VARIABLE 用於指定一個變數儲存標準輸出或者標準錯誤,OUTPUT_QUIET 或者 ERROR_QUIET 用於忽略標準輸出和標準錯誤。

使用範例:execute_process(COMMAND ls)

18)file 命令

命令簡述:此命令提供了豐富的檔案和目錄的相關操作(這裡僅說一下比較常用的)

使用範例:

# 目錄的遍歷

# GLOB 用於產生一個檔案(目錄)路徑列表並儲存在variable 中

# 檔案路徑列表中的每個檔案的檔名都能匹配globbing expressions(非正則表示式,但是類似)

# 如果指定了 RELATIVE 路徑,那麼返回的檔案路徑列表中的路徑為相對於 RELATIVE 的路徑

# file(GLOB variable [RELATIVE path][globbing expressions]...)

 

# 獲取當前目錄下的所有的檔案(目錄)的路徑並儲存到 ALL_FILE_PATH 變數中

file(GLOB ALL_FILE_PATH ./*)

# 獲取當前目錄下的 .h 檔案的檔名並儲存到ALL_H_FILE 變數中

# 這裡的變數CMAKE_CURRENT_LIST_DIR 表示正在處理的 CMakeLists.txt 檔案的所在的目錄的絕對路徑(2.8.3 以及以後版本才支援)

file(GLOB ALL_H_FILE RELATIVE${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}/*.h)

19)find_package(name)

在指定的模組目錄中搜索一個名為Find<name>.cmake(例如,FindOSG.cmake)的CMake指令碼模組檔案,執行其中的內容,意圖搜尋到指定的外部依賴庫標頭檔案和庫檔案位置;

20) include(file):

在當前檔案中包含另一個CMake指令碼檔案的內容,用來載入CMakeLists.txt檔案,也用於載入預定義的cmake模組

21)set_target_properties:

用來設定輸出的名稱,對於動態庫,還可以用來指定動態庫版本和API版本

set_target_properties(utils PROPERTIES output_name "utils")

編譯專案打包成so檔案

1. 藉助CMake打.so包

把目錄hello_make下的檔案打出.so包。

在上述檔案裡,我將build刪除,然後新加了兩個檔案,so_test.h,so_test.c,內容很簡單就是輸出一個test,這裡不貼程式碼了。另外main裡呼叫了下test_so函式。

重新編輯CMakeLists.txt

CMAKE_MINIMUM_REQUIRED(VERSION 3.5)
PROJECT(HELLO) #專案名稱  
AUX_SOURCE_DIRECTORY(. SRC_LIST) #把當前目錄(.)下所有原始碼檔案和標頭檔案加入變數SRC_LIST
ADD_EXECUTABLE(hello ${SRC_LIST}) #生成應用程式 hello (在windows下會自動生成hello.exe)

add_library(utils SHARED ${SRC_LIST})

set_target_properties(utils PROPERTIES output_name "utils")

注意:前面的關鍵字可以大寫也可以小寫,括號內的關鍵字必須大寫。

然後建立build檔案目錄,進去編譯,生成了共享庫libutils.so

當然也可以不建立build直接 cmake . 當前目錄下生成,但是不建議這樣,太亂了。

如下,生成的所有檔案

 

 

cython將py檔案編譯成so檔案

 

 

 

 

 

參考文獻:

1.https://www.cnblogs.com/AbnerShen/p/7399010.html

2.https://blog.csdn.net/wang4959520/article/details/73550923

3.https://blog.csdn.net/flyztek/article/details/73612469

4.http://www.cnblogs.com/zhongjiangfeng/p/7478243.html