理論上來說,任意一個c++程序都可以使用g++來編譯捞蚂,但當程序規(guī)模越來越大時跷究,一個工程可能有許多的文件夾和源文件,這時輸入的編譯命令將會越來越長。因此潭袱,對于C++使用一些工程管理工具會更加高效锋恬。這里我們使用CMake。
在一個CMake工程中彤悔,我們會使用cmake命令生成一個Makefile文件索守,然后,用make命令根據(jù)這個 makefile文件的內(nèi)容來編譯整個工程杨赤。
入門案例:單個源文件
- 編寫 CMakeLists.txt
首先編寫 CMakeLists.txt 文件,并保存在與 main.cc 源文件同個目錄下:
# 聲明要求的cmake最低版本
cmake_minimum_required (VERSION 2.8)
# 聲明一個cmake工程
project (HelloSLAM)
# 添加一個可執(zhí)行程序
#語法 :add_executable(程序名 源代碼文件)
add_executable(Demo main.cc)
CMakeLists.txt 文件用于告訴cmake我們要對這個目錄下的文件做什么事情植捎,CmakeLists.txt 文件的內(nèi)容需要遵守cmake的語法阳柔。
編譯項目
在當前目錄執(zhí)行 cmake . ,得到 Makefile 后再使用 make 命令編譯得到 Demo1 可執(zhí)行文件济锄。
cmake .
得到Makefile后再使用make
命令編譯得到Demo1可執(zhí)行文件
多個源文件
上面的例子只有單個源文件拟淮,現(xiàn)在假如把power
函數(shù)單獨寫進一個名為MathFunctions
的源文件里谴忧,使得這個工程變成如下形式:
./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
命令跑筝,該命令會查找指定目錄下的所有源文件瞒滴,然后將結(jié)果存進指定變量名妓忍。其語法如下:
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
的可執(zhí)行文件耕皮。
多個目錄凌停,多個源文件
現(xiàn)在進一步將 MathFunctions.h
和 MathFunctions.cc
文件移動到 math 目錄下罚拟。
./Demo3
|
+--- main.cc
|
+--- math/
|
+--- MathFunctions.cc
|
+--- MathFunctions.h
對于這種情況完箩,需要分別在項目根目錄 Demo3 和 math 目錄里各編寫一個 CMakeLists.txt 文件。為了方便阻逮,我們可以先將 math 目錄里的文件編譯成靜態(tài)庫再由 main 函數(shù)調(diào)用秩彤。
根目錄中的 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)
該文件添加了下面的內(nèi)容: 第3行漫雷,使用命令 add_subdirectory
指明本項目包含一個子目錄 math
,這樣 math
目錄下的CMakeLists.txt
文件和源代碼也會被處理 与柑。第6行蓄坏,使用命令 target_link_libraries
指明可執(zhí)行文件 main
需要連接一個名為 MathFunctions
的鏈接庫 。
子目錄中的 CMakeLists.txt:
# 查找當前目錄下的所有源文件
# 并將名稱保存到 DIR_LIB_SRCS 變量
aux_source_directory(. DIR_LIB_SRCS)
# 生成鏈接庫
add_library (MathFunctions ${DIR_LIB_SRCS})
在該文件中使用命令 add_library
將 src
目錄中的源文件編譯為靜態(tài)鏈接庫干旧。
自定義編譯選項
CMake 允許為項目增加編譯選項,從而可以根據(jù)用戶的環(huán)境和需求選擇最合適的編譯方案挠将。
例如,可以將 MathFunctions 庫設(shè)為一個可選的庫乳丰,如果該選項為 ON 内贮,就使用該庫定義的數(shù)學(xué)函數(shù)來進行運算汞斧。否則就調(diào)用標準庫中的數(shù)學(xué)函數(shù)庫粘勒。
修改 CMakeLists 文件
第一步是在頂層的 CMakeLists.txt 文件中添加該選項:
# CMake 最低版本號要求
cmake_minimum_required (VERSION 2.8)
# 項目信息
project (Demo4)
# 加入一個配置頭文件庙睡,用于處理 CMake 對源碼的設(shè)置
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 生成,通過這樣的機制啡邑,將可以通過預(yù)定義一些參數(shù)和變量來控制代碼的生成井赌。 - 第13行的
option
命令添加了一個USE_MYMATH
選項族展,并且默認值為ON
。 - 第17行根據(jù)
USE_MYMATH
變量的值來決定是否使用我們自己編寫的 MathFunctions 庫贵涵。
修改 main.cc文件
之后修改 main.cc]文件恰画,讓其根據(jù) USE_MYMATH
的預(yù)定義值來決定是否調(diào)用標準庫還是 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 文件,這個文件預(yù)定義了 USE_MYMATH
的值端盆。但我們并不直接編寫這個文件费封,為了方便從 CMakeLists.txt 中導(dǎo)入配置,我們編寫一個 config.h.in文件焚鹊,內(nèi)容如下:
#cmakedefine USE_MYMATH
這樣 CMake 會自動根據(jù) CMakeLists 配置文件中的設(shè)置自動生成 config.h 文件
編譯項目
現(xiàn)在編譯一下這個項目韧献,為了便于交互式的選擇該變量的值研叫,可以使用 ccmake 命令