您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關cmake的示例分析的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
什么是cmake
你或許聽過好幾種 Make 工具,例如 GNU Make ,QT 的 qmake ,微軟的 MSnmake,BSD Make(pmake),Makepp,等等。這些 Make 工具遵循著不同的規范和標準,所執行的 Makefile 格式也千差萬別。這樣就帶來了一個嚴峻的問題:如果軟件想跨平臺,必須要保證能夠在不同平臺編譯。而如果使用上面的 Make 工具,就得為每一種標準寫一次 Makefile ,這將是一件讓人抓狂的工作。
CMake CMake附圖 1 CMake就是針對上面問題所設計的工具:它首先允許開發者編寫一種平臺無關的 CMakeList.txt 文件來定制整個編譯流程,然后再根據目標用戶的平臺進一步生成所需的本地化 Makefile 和工程文件,如 Unix 的 Makefile 或 Windows 的 Visual Studio 工程。從而做到“Write once, run everywhere”。顯然,CMake 是一個比上述幾種 make 更高級的編譯配置工具。一些使用 CMake 作為項目架構系統的知名開源項目有 VTK、ITK、KDE、OpenCV、OSG 等。
在 linux 平臺下使用 CMake 生成 Makefile 并編譯的流程如下:
編寫 CMake 配置文件 CMakeLists.txt 。
執行命令 cmake PATH 或者 ccmake PATH 生成 Makefile。其中, PATH 是 CMakeLists.txt 所在的目錄。(ccmake 和 cmake 的區別在于前者提供了一個交互式的界面)
使用 make 命令進行編譯。
入門案例:單個源文件
本節對應的源代碼所在目錄:Demo1。
對于簡單的項目,只需要寫幾行代碼就可以了。例如,假設現在我們的項目中只有一個源文件 main.cc ,該程序的用途是計算一個數的指數冪。
#include <stdio.h> #include <stdlib.h> /** * power - Calculate the power of number. * @param base: Base value. * @param exponent: Exponent value. * * @return base raised to the power exponent. */ double power(double base, int exponent) { int result = base; int i; if (exponent == 0) { return 1; } for(i = 1; i < exponent; ++i){ result = result * base; } return result; } int main(int argc, char *argv[]) { if (argc < 3){ printf("Usage: %s base exponent \n", argv[0]); return 1; } double base = atof(argv[1]); int exponent = atoi(argv[2]); double result = power(base, exponent); printf("%g ^ %d is %g\n", base, exponent, result); return 0; }
編寫 CMakeLists.txt
首先編寫 CMakeLists.txt 文件,并保存在與 main.cc 源文件同個目錄下:
# CMake 最低版本號要求
cmake_minimum_required (VERSION 2.8)
# 項目信息
project (Demo1)
# 指定生成目標
add_executable(Demo main.cc)
CMakeLists.txt 的語法比較簡單,由命令、注釋和空格組成,其中命令是不區分大小寫的。符號 # 后面的內容被認為是注釋。命令由命令名稱、小括號和參數組成,參數之間使用空格進行間隔。
對于上面的 CMakeLists.txt 文件,依次出現了幾個命令:
cmake_minimum_required:指定運行此配置文件所需的 CMake 的最低版本;
project:參數值是 Demo1,該命令表示項目的名稱是 Demo1 。
add_executable: 將名為 main.cc 的源文件編譯成一個名稱為 Demo 的可執行文件。
編譯項目
之后,在當前目錄執行 cmake . ,得到 Makefile 后再使用 make 命令編譯得到 Demo1 可執行文件。
[ehome@xman Demo1]$ cmake . -- The C compiler identification is GNU 4.8.2 -- The CXX compiler identification is GNU 4.8.2 -- Check for working C compiler: /usr/sbin/cc -- Check for working C compiler: /usr/sbin/cc -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Check for working CXX compiler: /usr/sbin/c++ -- Check for working CXX compiler: /usr/sbin/c++ -- works -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Configuring done -- Generating done -- Build files have been written to: /home/ehome/Documents/programming/C/power/Demo1 [ehome@xman Demo1]$ make Scanning dependencies of target Demo [100%] Building C object CMakeFiles/Demo.dir/main.cc.o Linking C executable Demo [100%] Built target Demo [ehome@xman Demo1]$ ./Demo 5 4 5 ^ 4 is 625 [ehome@xman Demo1]$ ./Demo 7 3 7 ^ 3 is 343 [ehome@xman Demo1]$ ./Demo 2 10 2 ^ 10 is 1024
多個源文件
同一目錄,多個源文件
本小節對應的源代碼所在目錄:Demo2。
上面的例子只有單個源文件。現在假如把 power 函數單獨寫進一個名為MathFunctions.c 的源文件里,使得這個工程變成如下的形式:
./Demo2
|
+--- main.cc
|
+--- MathFunctions.cc
|
+--- MathFunctions.h
這個時候,CMakeLists.txt 可以改成如下的形式:
# CMake 最低版本號要求
cmake_minimum_required (VERSION 2.8)
# 項目信息
project (Demo2)
# 指定生成目標
add_executable(Demo main.cc MathFunctions.cc)
唯一的改動只是在 add_executable 命令中增加了一個 MathFunctions.cc 源文件。這樣寫當然沒什么問題,但是如果源文件很多,把所有源文件的名字都加進去將是一件煩人的工作。更省事的方法是使用 aux_source_directory 命令,該命令會查找指定目錄下的所有源文件,然后將結果存進指定變量名。其語法如下:
aux_source_directory(<dir> <variable>)
因此,可以修改 CMakeLists.txt 如下:
# CMake 最低版本號要求
cmake_minimum_required (VERSION 2.8)
# 項目信息
project (Demo2)
# 查找當前目錄下的所有源文件
# 并將名稱保存到 DIR_SRCS 變量
aux_source_directory(. DIR_SRCS)
# 指定生成目標
add_executable(Demo ${DIR_SRCS})
這樣,CMake 會將當前目錄所有源文件的文件名賦值給變量 DIR_SRCS ,再指示變量 DIR_SRCS 中的源文件需要編譯成一個名稱為 Demo 的可執行文件。
多個目錄,多個源文件
本小節對應的源代碼所在目錄:Demo3。
現在進一步將 MathFunctions.h 和 MathFunctions.cc 文件移動到 math 目錄下。
./Demo3
|
+--- main.cc
|
+--- math/
|
+--- MathFunctions.cc
|
+--- MathFunctions.h
對于這種情況,需要分別在項目根目錄 Demo3 和 math 目錄里各編寫一個 CMakeLists.txt 文件。為了方便,我們可以先將 math 目錄里的文件編譯成靜態庫再由 main 函數調用。
根目錄中的 CMakeLists.txt :
# CMake 最低版本號要求
cmake_minimum_required (VERSION 2.8)
# 項目信息
project (Demo3)
# 查找當前目錄下的所有源文件
# 并將名稱保存到 DIR_SRCS 變量
aux_source_directory(. DIR_SRCS)
# 添加 math 子目錄
add_subdirectory(math)
# 指定生成目標
add_executable(Demo main.cc)
# 添加鏈接庫
target_link_libraries(Demo MathFunctions)
該文件添加了下面的內容: 第3行,使用命令 add_subdirectory 指明本項目包含一個子目錄 math,這樣 math 目錄下的 CMakeLists.txt 文件和源代碼也會被處理 。第6行,使用命令 target_link_libraries 指明可執行文件 main 需要連接一個名為 MathFunctions 的鏈接庫 。
子目錄中的 CMakeLists.txt:
# 查找當前目錄下的所有源文件
# 并將名稱保存到 DIR_LIB_SRCS 變量
aux_source_directory(. DIR_LIB_SRCS)
# 生成鏈接庫
add_library (MathFunctions ${DIR_LIB_SRCS})
在該文件中使用命令 add_library 將 src 目錄中的源文件編譯為靜態鏈接庫。
自定義編譯選項
本節對應的源代碼所在目錄:Demo4。
CMake 允許為項目增加編譯選項,從而可以根據用戶的環境和需求選擇最合適的編譯方案。
例如,可以將 MathFunctions 庫設為一個可選的庫,如果該選項為 ON ,就使用該庫定義的數學函數來進行運算。否則就調用標準庫中的數學函數庫。
修改 CMakeLists 文件
我們要做的第一步是在頂層的 CMakeLists.txt 文件中添加該選項:
# CMake 最低版本號要求
cmake_minimum_required (VERSION 2.8)
# 項目信息
project (Demo4)
# 加入一個配置頭文件,用于處理 CMake 對源碼的設置
configure_file (
"${PROJECT_SOURCE_DIR}/config.h.in"
"${PROJECT_BINARY_DIR}/config.h"
)
# 是否使用自己的 MathFunctions 庫
option (USE_MYMATH
"Use provided math implementation" ON)
# 是否加入 MathFunctions 庫
if (USE_MYMATH)
include_directories ("${PROJECT_SOURCE_DIR}/math")
add_subdirectory (math)
set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif (USE_MYMATH)
# 查找當前目錄下的所有源文件
# 并將名稱保存到 DIR_SRCS 變量
aux_source_directory(. DIR_SRCS)
# 指定生成目標
add_executable(Demo ${DIR_SRCS})
target_link_libraries (Demo ${EXTRA_LIBS})
其中:
第7行的 configure_file 命令用于加入一個配置頭文件 config.h ,這個文件由 CMake 從 config.h.in 生成,通過這樣的機制,將可以通過預定義一些參數和變量來控制代碼的生成。
第13行的 option 命令添加了一個 USE_MYMATH 選項,并且默認值為 ON 。
第17行根據 USE_MYMATH 變量的值來決定是否使用我們自己編寫的 MathFunctions 庫。
修改 main.cc 文件
之后修改 main.cc 文件,讓其根據 USE_MYMATH 的預定義值來決定是否調用標準庫還是 MathFunctions 庫:
#include #include #include "config.h" #ifdef USE_MYMATH #include "math/MathFunctions.h" #else #include #endif int main(int argc, char *argv[]) { if (argc < 3){ printf("Usage: %s base exponent \n", argv[0]); return 1; } double base = atof(argv[1]); int exponent = atoi(argv[2]); #ifdef USE_MYMATH printf("Now we use our own Math library. \n"); double result = power(base, exponent); #else printf("Now we use the standard library. \n"); double result = pow(base, exponent); #endif printf("%g ^ %d is %g\n", base, exponent, result); return 0; }
編寫 config.h.in 文件
上面的程序值得注意的是第2行,這里引用了一個 config.h 文件,這個文件預定義了 USE_MYMATH 的值。但我們并不直接編寫這個文件,為了方便從 CMakeLists.txt 中導入配置,我們編寫一個 config.h.in 文件,內容如下:
#cmakedefine USE_MYMATH
這樣 CMake 會自動根據 CMakeLists 配置文件中的設置自動生成 config.h 文件。
編譯項目
現在編譯一下這個項目,為了便于交互式的選擇該變量的值,可以使用 ccmake 命令(也可以使用 cmake -i 命令,該命令會提供一個會話式的交互式配置界面。 )
從中可以找到剛剛定義的 USE_MYMATH 選項,按鍵盤的方向鍵可以在不同的選項窗口間跳轉,按下 enter 鍵可以修改該選項。修改完成后可以按下 c 選項完成配置,之后再按 g 鍵確認生成 Makefile 。ccmake 的其他操作可以參考窗口下方給出的指令提示。
我們可以試試分別將 USE_MYMATH 設為 ON 和 OFF 得到的結果:
USE_MYMATH 為 ON
運行結果:
[ehome@xman Demo4]$ ./Demo
Now we use our own MathFunctions library.
7 ^ 3 = 343.000000
10 ^ 5 = 100000.000000
2 ^ 10 = 1024.000000
此時 config.h 的內容為:
#define USE_MYMATH
USE_MYMATH 為 OFF
運行結果:
[ehome@xman Demo4]$ ./Demo
Now we use the standard library.
7 ^ 3 = 343.000000
10 ^ 5 = 100000.000000
2 ^ 10 = 1024.000000
此時 config.h 的內容為:
/* #undef USE_MYMATH */
下面是其他網友的補充
使用cmake編譯,組織C++項目
前言
這篇博客是我對cmake用法的一些經驗總結, 還很淺顯, 如果有錯誤或者更好的方案, 歡迎指正~
使用方法統一為在build目錄中執行:
$: cmake ..
$: make
我覺得養成外部編譯是一個好習慣
例一
目錄結構為:
lzj@lzj:~/C-Plus-Plus/makefile_cmake/cmake_1$ tree
.
├── build
├── CMakeLists.txt
└── src
├── hello
│ ├── hello.cc
│ └── hello.h
├── main.cpp
└── world
├── world.cc
└── world.h
src 目錄中不同屬性類維護在不同目錄中
main.cpp中使用hello.h和world.h
CMakeLists.txt為 :
cmake_minimum_required (VERSION 3.0)
project (test_1)aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/src/hello SOURCE_HELLO)
aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/src/world SOURCE_WORLD)add_definitions("-g -Wall -std=c++11")
add_executable(main
${CMAKE_CURRENT_LIST_DIR}/src/main.cpp
${SOURCE_HELLO}
${SOURCE_WORLD})
例二
目錄結構為:
lzj@lzj:~/C-Plus-Plus/makefile_cmake/cmake_2$ tree
.
├── build
├── CMakeLists.txt
├── include
│ └── person.h
└── src
├── main.cpp
└── person.cc
include目錄下統一包含頭文件和宏定義之類, 源文件放在 src 目錄下維護
person 類是一個簡單的空類, 擁有一個私有成員變量val, 一個公有成員函數來打印該變量, 在main.cpp中調用
CMakeLists.txt為 :
cmake_minimum_required(VERSION 3.0)
project(test_2)include_directories(${PROJECT_SOURCE_DIR}/include)
add_definitions("-g -Wall -std=c++11")
add_executable(main
${PROJECT_SOURCE_DIR}/src/main.cpp #這個路徑看這個main.cpp位于哪里了
${PROJECT_SOURCE_DIR}/src/person.cc)
例三
目錄結構為:
lzj@lzj:~/C-Plus-Plus/makefile_cmake/cmake_3$ tree
.
├── build
├── CMakeLists.txt
├── main.cpp
└── src
├── CMakeLists.txt
├── hello.cc
├── hello.h
├── world.cc
└── world.h
將編寫的代碼編譯為庫, 在main.cpp中使用, 編譯main.cpp時鏈接該庫
頂層目錄中CMakeLists.txt為:
cmake_minimum_required (VERSION 3.0)
project (test_3)add_subdirectory(src)
add_definitions("-g -Wall -std=c++11")
add_executable(main main.cpp)
target_link_libraries(main TEST3) #自己的庫名為TEST3
子目錄 src 中的CMakeLists.txt為:
aux_source_directory(. DIR_LIB_SRCS)
add_library (TEST3 ${DIR_LIB_SRCS})
當然如果src目錄下為多文件時, 每個目錄下都要添加該語句的CMakeLists.txt
感謝各位的閱讀!關于“cmake的示例分析”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。