在 linux 下使用 CMake 构建应用程序
CMake 簡(jiǎn)介
CMake 是一個(gè)跨平臺(tái)的自動(dòng)化建構(gòu)系統(tǒng),它使用一個(gè)名為 CMakeLists.txt 的文件來(lái)描述構(gòu)建過(guò)程,可以產(chǎn)生標(biāo)準(zhǔn)的構(gòu)建文件,如 Unix 的 Makefile 或Windows Visual C++ 的 projects/workspaces 。文件 CMakeLists.txt 需要手工編寫,也可以通過(guò)編寫腳本進(jìn)行半自動(dòng)的生成。CMake 提供了比 autoconfig 更簡(jiǎn)潔的語(yǔ)法。在 linux 平臺(tái)下使用 CMake 生成 Makefile 并編譯的流程如下:
第一個(gè)工程
現(xiàn)假設(shè)我們的項(xiàng)目中只有一個(gè)源文件 main.cpp
清單 1 源文件 main.cpp
| 1 2 3 4 5 6 7 | 1 #include<iostream> 2 3 int main() 4 { 5???? std::cout<<"Hello word!"<<std::endl; 6???? return 0; 7 } |
為了構(gòu)建該項(xiàng)目,我們需要編寫文件 CMakeLists.txt 并將其與 main.cpp 放在 同一個(gè)目錄下:
清單 2 CMakeLists.txt
| 1 2 3 4 | 1 PROJECT(main) 2 CMAKE_MINIMUM_REQUIRED(VERSION 2.6) 3 AUX_SOURCE_DIRECTORY(. DIR_SRCS) 4 ADD_EXECUTABLE(main ${DIR_SRCS}) |
CMakeLists.txt 的語(yǔ)法比較簡(jiǎn)單,由命令、注釋和空格組成,其中命令是不區(qū)分大小寫的,符號(hào)"#"后面的內(nèi)容被認(rèn)為是注釋。命令由命令名稱、小括號(hào)和參數(shù)組成,參數(shù)之間使用空格進(jìn)行間隔。例如對(duì)于清單2的 CMakeLists.txt 文件:第一行是一條命令,名稱是 PROJECT ,參數(shù)是 main ,該命令表示項(xiàng)目的名稱是 main 。第二行的命令限定了 CMake 的版本。第三行使用命令 AUX_SOURCE_DIRECTORY 將當(dāng)前目錄中的源文件名稱賦值給變量 DIR_SRCS 。 CMake 手冊(cè)中對(duì)命令 AUX_SOURCE_DIRECTORY 的描述如下:
| 1 | aux_source_directory(<dir> <variable>) |
該命令會(huì)把參數(shù) <dir> 中所有的源文件名稱賦值給參數(shù) <variable> 。 第四行使用命令 ADD_EXECUTABLE 指示變量 DIR_SRCS 中的源文件需要編譯 成一個(gè)名稱為 main 的可執(zhí)行文件。
完成了文件 CMakeLists.txt 的編寫后需要使用 cmake 或 ccmake 命令生成Makefile 。 ccmake 與命令 cmake 的不同之處在于 ccmake 提供了一個(gè)圖形化的操作界面。cmake 命令的執(zhí)行方式如下:
| 1 | cmake [options] <path-to-source> |
這里我們進(jìn)入了 main.cpp 所在的目錄后執(zhí)行 “cmake .” 后就可以得到 Makefile 并使用 make 進(jìn)行編譯,如下圖所示。
圖 1. camke 的運(yùn)行結(jié)果
處理多源文件目錄的方法
CMake 處理源代碼分布在不同目錄中的情況也十分簡(jiǎn)單。現(xiàn)假設(shè)我們的源代碼分布情況如下:
圖 2. 源代碼分布情況
其中 src 目錄下的文件要編譯成一個(gè)鏈接庫(kù)。
第一步,項(xiàng)目主目錄中的 CMakeLists.txt
在目錄 step2 中創(chuàng)建文件 CMakeLists.txt 。文件內(nèi)容如下:
清單 3 目錄 step2 中的 CMakeLists.txt
| 1 2 3 4 5 6 | 1 PROJECT(main) 2 CMAKE_MINIMUM_REQUIRED(VERSION 2.6) 3 ADD_SUBDIRECTORY( src ) 4 AUX_SOURCE_DIRECTORY(. DIR_SRCS) 5 ADD_EXECUTABLE(main ${DIR_SRCS}? ) 6 TARGET_LINK_LIBRARIES( main Test ) |
相對(duì)于清單 2,該文件添加了下面的內(nèi)容: 第三行,使用命令 ADD_SUBDIRECTORY 指明本項(xiàng)目包含一個(gè)子目錄 src 。第六行,使用命令 TARGET_LINK_LIBRARIES 指明可執(zhí)行文件 main 需要連接一個(gè)名為Test的鏈接庫(kù) 。
第二步,子目錄中的 CmakeLists.txt
在子目錄 src 中創(chuàng)建 CmakeLists.txt。文件內(nèi)容如下:
清單 4. 目錄 src 中的 CmakeLists.txt
| 1 2 | 1 AUX_SOURCE_DIRECTORY(. DIR_TEST1_SRCS) 2 ADD_LIBRARY ( Test ${DIR_TEST1_SRCS}) |
在該文件中使用命令 ADD_LIBRARY 將 src 目錄中的源文件編譯為共享庫(kù)。
第三步,執(zhí)行 cmake
至此我們完成了項(xiàng)目中所有 CMakeLists.txt 文件的編寫,進(jìn)入目錄 step2 中依次執(zhí)行命令 “cmake .” 和 “make” 得到結(jié)果如下:
圖3. 處理多源文件目錄時(shí) cmake 的執(zhí)行結(jié)果
在執(zhí)行 cmake 的過(guò)程中,首先解析目錄 step2 中的 CMakeLists.txt ,當(dāng)程序執(zhí)行命令 ADD_SUBDIRECTORY( src ) 時(shí)進(jìn)入目錄 src 對(duì)其中的 CMakeLists.txt 進(jìn)行解析。
在工程中查找并使用其他程序庫(kù)的方法
在開發(fā)軟件的時(shí)候我們會(huì)用到一些函數(shù)庫(kù),這些函數(shù)庫(kù)在不同的系統(tǒng)中安裝的位置可能不同,編譯的時(shí)候需要首先找到這些軟件包的頭文件以及鏈接庫(kù)所在的目錄以便生成編譯選項(xiàng)。例如一個(gè)需要使用博克利數(shù)據(jù)庫(kù)項(xiàng)目,需要頭文件db_cxx.h 和鏈接庫(kù) libdb_cxx.so ,現(xiàn)在該項(xiàng)目中有一個(gè)源代碼文件 main.cpp ,放在項(xiàng)目的根目錄中。
第一步,程序庫(kù)說(shuō)明文件
在項(xiàng)目的根目錄中創(chuàng)建目錄 cmake/modules/ ,在 cmake/modules/ 下創(chuàng)建文件 Findlibdb_cxx.cmake ,內(nèi)容如下:
清單 5. 文件 Findlibdb_cxx.cmake
| 1 2 3 4 5 6 7 8 9 10 11 12 | 01 MESSAGE(STATUS "Using bundled Findlibdb.cmake...") 0203 FIND_PATH( 04?? LIBDB_CXX_INCLUDE_DIR 05?? db_cxx.h 06?? /usr/include/ 07?? /usr/local/include/ 08?? ) 09 10 FIND_LIBRARY( 11?? LIBDB_CXX_LIBRARIES NAMES? db_cxx 12?? PATHS /usr/lib/ /usr/local/lib/ 13?? ) |
文件 Findlibdb_cxx.cmake 的命名要符合規(guī)范: FindlibNAME.cmake ,其中NAME 是函數(shù)庫(kù)的名稱。Findlibdb_cxx.cmake 的語(yǔ)法與 CMakeLists.txt 相同。這里使用了三個(gè)命令: MESSAGE , FIND_PATH 和 FIND_LIBRARY 。
- 命令 MESSAGE 會(huì)將參數(shù)的內(nèi)容輸出到終端。
- 命令 FIND_PATH 指明頭文件查找的路徑,原型如下:
find_path(<VAR> name1 [path1 path2 ...]) 該命令在參數(shù) path* 指示的目錄中查找文件 name1 并將查找到的路徑保存在變量 VAR 中。清單5第3-8行的意思是在 /usr/include/ 和 /usr/local/include/ 中查找文件db_cxx.h ,并將db_cxx.h 所在的路徑保存在 LIBDB_CXX_INCLUDE_DIR中。 - 命令 FIND_LIBRARY 同 FIND_PATH 類似,用于查找鏈接庫(kù)并將結(jié)果保存在變量中。清單5第10-13行的意思是在目錄 /usr/lib/ 和 /usr/local/lib/ 中尋找名稱為 db_cxx 的鏈接庫(kù),并將結(jié)果保存在 LIBDB_CXX_LIBRARIES。
第二步, 項(xiàng)目的根目錄中的 CmakeList.txt
在項(xiàng)目的根目錄中創(chuàng)建 CmakeList.txt :
清單 6. 可以查找鏈接庫(kù)的 CMakeList.txt
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 01 PROJECT(main) 02 CMAKE_MINIMUM_REQUIRED(VERSION 2.6) 03 SET(CMAKE_SOURCE_DIR .) 04 SET(CMAKE_MODULE_PATH ${CMAKE_ROOT}/Modules ${CMAKE_SOURCE_DIR}/cmake/modules) 05 AUX_SOURCE_DIRECTORY(. DIR_SRCS) 06 ADD_EXECUTABLE(main ${DIR_SRCS}) 0708 FIND_PACKAGE( libdb_cxx REQUIRED) 09 MARK_AS_ADVANCED( 10 LIBDB_CXX_INCLUDE_DIR 11 LIBDB_CXX_LIBRARIES 12 ) 13 IF (LIBDB_CXX_INCLUDE_DIR AND LIBDB_CXX_LIBRARIES) 14 MESSAGE(STATUS "Found libdb libraries") 15??? INCLUDE_DIRECTORIES(${LIBDB_CXX_INCLUDE_DIR}) 16???? MESSAGE( ${LIBDB_CXX_LIBRARIES} ) 17???? TARGET_LINK_LIBRARIES(main ${LIBDB_CXX_LIBRARIES}18 ) 19 ENDIF (LIBDB_CXX_INCLUDE_DIR AND LIBDB_CXX_LIBRARIES) |
在該文件中第4行表示到目錄 ./cmake/modules 中查找 Findlibdb_cxx.cmake ,8-19 行表示查找鏈接庫(kù)和頭文件的過(guò)程。第8行使用命令 FIND_PACKAGE 進(jìn)行查找,這條命令執(zhí)行后 CMake 會(huì)到變量 CMAKE_MODULE_PATH 指示的目錄中查找文件 Findlibdb_cxx.cmake 并執(zhí)行。第13-19行是條件判斷語(yǔ)句,表示如果 LIBDB_CXX_INCLUDE_DIR 和 LIBDB_CXX_LIBRARIES 都已經(jīng)被賦值,則設(shè)置編譯時(shí)到 LIBDB_CXX_INCLUDE_DIR 尋找頭文件并且設(shè)置可執(zhí)行文件 main 需要與鏈接庫(kù) LIBDB_CXX_LIBRARIES 進(jìn)行連接。
第三步,執(zhí)行 cmake
完成 Findlibdb_cxx.cmake 和 CMakeList.txt 的編寫后在項(xiàng)目的根目錄依次執(zhí)行 “cmake . ” 和 “make ” 可以進(jìn)行編譯,結(jié)果如下圖所示:
圖 4. 使用其他程序庫(kù)時(shí) cmake 的執(zhí)行結(jié)果
使用 cmake 生成 debug 版和 release 版的程序
在 Visual Studio 中我們可以生成 debug 版和 release 版的程序,使用 CMake 我們也可以達(dá)到上述效果。debug 版的項(xiàng)目生成的可執(zhí)行文件需要有調(diào)試信息并且不需要進(jìn)行優(yōu)化,而 release 版的不需要調(diào)試信息但需要優(yōu)化。這些特性在 gcc/g++ 中是通過(guò)編譯時(shí)的參數(shù)來(lái)決定的,如果將優(yōu)化程度調(diào)到最高需要設(shè)置參數(shù)-O3,最低是 -O0 即不做優(yōu)化;添加調(diào)試信息的參數(shù)是 -g -ggdb ,如果不添加這個(gè)參數(shù),調(diào)試信息就不會(huì)被包含在生成的二進(jìn)制文件中。
CMake 中有一個(gè)變量 CMAKE_BUILD_TYPE ,可以的取值是 Debug Release RelWithDebInfo 和 MinSizeRel。當(dāng)這個(gè)變量值為 Debug 的時(shí)候,CMake 會(huì)使用變量 CMAKE_CXX_FLAGS_DEBUG 和 CMAKE_C_FLAGS_DEBUG 中的字符串作為編譯選項(xiàng)生成 Makefile ,當(dāng)這個(gè)變量值為 Release 的時(shí)候,工程會(huì)使用變量 CMAKE_CXX_FLAGS_RELEASE 和 CMAKE_C_FLAGS_RELEASE 選項(xiàng)生成 Makefile。
現(xiàn)假設(shè)項(xiàng)目中只有一個(gè)文件 main.cpp ,下面是一個(gè)可以選擇生成 debug 版和 release 版的程序的 CMakeList.txt :
清單 7
| 1 2 3 4 5 6 7 | 1 PROJECT(main) 2 CMAKE_MINIMUM_REQUIRED(VERSION 2.6) 3 SET(CMAKE_SOURCE_DIR .) 45 SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb") 6 SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall") 78 AUX_SOURCE_DIRECTORY(. DIR_SRCS) 9 ADD_EXECUTABLE(main ${DIR_SRCS}) |
第 5 和 6 行設(shè)置了兩個(gè)變量 CMAKE_CXX_FLAGS_DEBUG 和 CMAKE_CXX_FLAGS_RELEASE, 這兩個(gè)變量是分別用于 debug 和 release 的編譯選項(xiàng)。 編輯 CMakeList.txt 后需要執(zhí)行 ccmake 命令生成 Makefile 。在進(jìn)入項(xiàng)目的根目錄,輸入 "ccmake ." 進(jìn)入一個(gè)圖形化界面,如下圖所示:
圖 5. ccmake 的界面
按照界面中的提示進(jìn)行操作,按 "c" 進(jìn)行 configure ,這時(shí)界面中顯示出了配置變量 CMAKE_BUILD_TYPE 的條目。如下圖所示:
圖 6. 執(zhí)行了 configure 以后 ccmake 的界面
下面我們首先生成 Debug 版的 Makefile :將變量 CMAKE_BUILD_TYPE 設(shè)置為 Debug ,按 "c" 進(jìn)行 configure ,按 "g" 生成 Makefile 并退出。這時(shí)執(zhí)行命令 find * | xargs grep "O0" 后結(jié)果如下:
清單 8 find * | xargs grep "O0"的執(zhí)行結(jié)果
| 1 2 3 4 | CMakeFiles/main.dir/flags.make:CXX_FLAGS = -O0 -Wall -g -ggdb CMakeFiles/main.dir/link.txt:/usr/bin/c++ -O0 -Wall -g -ggdb CMakeFiles/main.dir/main.cpp.o -o main -rdynamic CMakeLists.txt:SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb") |
這個(gè)結(jié)果說(shuō)明生成的 Makefile 中使用了變量 CMAKE_CXX_FLAGS_DEBUG 作為編譯時(shí)的參數(shù)。
下面我們將生成 Release 版的 Makefile :再次執(zhí)行命令 "ccmake ." 將變量CMAKE_BUILD_TYPE 設(shè)置為 Release ,生成 Makefile 并退出。執(zhí)行命令 find * | xargs grep "O0" 后結(jié)果如下:
清單 9 find * | xargs grep "O0"的執(zhí)行結(jié)果
| 1 | CMakeLists.txt:SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb") |
而執(zhí)行命令 find * | xargs grep "O3" 后結(jié)果如下:
清單 10. find * | xargs grep "O3"的執(zhí)行結(jié)果
| 1 2 3 4 5 6 | CMakeCache.txt:CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG CMakeCache.txt:CMAKE_C_FLAGS_RELEASE:STRING=-O3 -DNDEBUG CMakeFiles/main.dir/flags.make:CXX_FLAGS = -O3 -Wall CMakeFiles/main.dir/link.txt:/usr/bin/c++ -O3 -Wall CMakeFiles/main.dir/main.cpp.o -o main -rdynamic CMakeLists.txt:SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall") |
這兩個(gè)結(jié)果說(shuō)明生成的 Makefile 中使用了變量 CMAKE_CXX_FLAGS_RELEASE 作為編譯時(shí)的參數(shù)。
下載資源
- 樣例代碼 (src.rar | 11KB)
相關(guān)主題
- 要了解 CMake, 請(qǐng)參考其官方網(wǎng)站:http://www.cmake.org/。
- 維基百科中對(duì) CMake 也有非常詳細(xì)的說(shuō)明,具體請(qǐng)參考:http://zh.wikipedia.org/wiki/CMake。
- 在 developerWorks Linux 專區(qū) 尋找為 Linux 開發(fā)人員(包括 Linux 新手入門)準(zhǔn)備的更多參考資料,查閱我們 最受歡迎的文章和教程。
- 在 developerWorks 上查閱所有 Linux 技巧 和 Linux 教程。
總結(jié)
以上是生活随笔為你收集整理的在 linux 下使用 CMake 构建应用程序的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 安装 PyCharm
- 下一篇: Windows 配置Apache+CGI