CMake意為cross-platform make,可用于管理c/c++工程。CMake解析配置檔案CMakeLists.txt生成Makefile,相比直接用Makefile管理工程,CMake更靈活和簡單。
一.cmake的安裝及基本文法
(1)安裝cmake。
下載下傳位址:http://www.cmake.org/cmake/resources/software.html
有linux和windows版本的.
(2)一個執行個體 CMake Hello World
首先編寫一個簡單的程式(hello.cpp):
#include <stdio.h>
int main()
{
printf("Hello World");
return 0;
}
編寫CMakeLists.txt,并與hello.cpp放在同一個目錄。添加如下内容:
project(hello)
cmake_minimum_required(VERSION 2.8)
aux_source_directory(. DIR_SRCS)
add_executable(hello ${DIR_SRCS})
在 CMakeLists.txt 所在的目錄下建立一個build目錄,進入該目錄執行 CMake 指令生成建構檔案:
mkdir build
cd build
cmake ..
make
./hello
此時,即可在build下生成可執行檔案.
(3)CMake基本文法
編寫的CMakeLists.txt需要符合一定的文法規則,它主要由CMake指令組成。
1)注釋的文法:在CMake中注釋使用"#"字元開始到此行結束。
2)CMake指令:指令不區分大小寫(參數會區分大小寫),指令由指令、參數清單組成,參數之間使用空格進行分隔。
使用一對雙引号包括的字元串認為是一個參數。指令可以是一個内置指令(例如:project,add_executable等),也可以是一個使用者定義的宏(macro)或者函數(function)。
3)資料類型:CMake的基本資料類型是字元串,一組字元串在一起稱為清單(list),例如:
# 通過 set 指令建構一個list變量 VAR
set(VAR a b c)
#使用文法 ${VariableName} 來通路名字為 VariableName 的變量的值(變量名區分大小寫)。需要注意的是,即使在字元串中也可以使用 ${VariableName} 來通路變量的值:
# 輸出 VAR = a;b;c
message("VAR = ${VAR}")
#使用文法 $ENV{VariableName} 來通路環境變量的值(ENV{VariableName} 則表示環境變量本身),輸出環境變量 PATH 的值
message($ENV{PATH})
set(ENV{PATH} /usr/bin)
4)條件控制和循環結構
if(expression)
#...
elseif(expression2)
else()
endif()
對于 if(string) 來說:
如果 string 為(不區分大小寫)1、ON、YES、TRUE、Y、非 0 的數則表示真
如果 string 為(不區分大小寫)0、OFF、NO、FALSE、N、IGNORE、空字元串、以 -NOTFOUND 結尾的字元串則表示假
如果 string 不符合上面兩種情況,則 string 被認為是一個變量的名字。變量的值為第二條所述的各值則表示假,否則表示真。
# 此政策(Policy)在 CMake2.8.0 才被引入
# 是以這裡需要指定最低 CMake 版本為 2.8
set(YES 0)
# 輸出 True
if(YES)
message(True)
message(False)
# 輸出 False
if(${YES})
表達式中可以包含操作符,操作符包括:
一進制操作符,例如:EXISTS、COMMAND、DEFINED 等
二進制操作符,例如:EQUAL、LESS、GREATER、STRLESS、STRGREATER 等
NOT(非操作符)
AND(與操作符)、OR(或操作符)
操作符優先級:一進制操作符 > 二進制操作符 > NOT > AND、OR
常用操作符介紹:
if(NOT expression)
為真的前提是 expression 為假
if(expr1 AND expr2)
為真的前提是 expr1 和 expr2 都為真
if(expr1 OR expr2)
為真的前提是 expr1 或者 expr2 為真
if(COMMAND command-name)
為真的前提是存在 command-name 指令、宏或函數且能夠被調用
if(EXISTS name)
為真的前提是存在 name 的檔案或者目錄(應該使用絕對路徑)
if(file1 IS_NEWER_THAN file2)
為真的前提是 file1 比 file2 新或者 file1、file2 中有一個檔案不存在(應該使用絕對路徑)
if(IS_DIRECTORY directory-name)
為真的前提是 directory-name 表示的是一個目錄(應該使用絕對路徑)
if(variable|string MATCHES regex)
為真的前提是變量值或者字元串比對 regex 正規表達式
if(variable|string LESS variable|string)
if(variable|string GREATER variable|string)
if(variable|string EQUAL variable|string)
為真的前提是變量值或者字元串為有效的數字且滿足小于(大于、等于)的條件
if(variable|string STRLESS variable|string)
if(variable|string STRGREATERvariable|string)
if(variable|string STREQUALvariable|string)
為真的前提是變量值或者字元串以字典序滿足小于(大于、等于)的條件
if(DEFINED variable)
為真的前提是variable表示的變量被set定義了。
foreach 循環範例:
set(VAR a b c)
foreach(f ${VAR})
message(${f})
endforeach()
while 循環範例:
set(VAR 5)
while(${VAR} GREATER 0)
message(${VAR})
math(EXPR VAR "${VAR} - 1")
endwhile()
5)函數和宏定義
函數會為變量建立一個局部作用域,而宏則使用全局作用域。範例:
# 定義一個宏 hello
macro(hello MESSAGE)
message(${MESSAGE})
endmacro()
# 調用宏 hello
hello("hello world")
# 定義一個函數 hello
function(hello MESSAGE)
endfunction()
函數和宏可以通過指令 return() 傳回,但是函數和宏的傳回值必須通過參數傳遞出去。例如:
function(get_func RESULT)
#RESULT 的值為實參的值,是以需要使用 ${RESULT}
#這裡使用 PARENT_SCOPE 是因為函數會建構一個局部作用域
set(${RESULT} "Hello Function" PARENT_SCOPE)
macro(get_macro RESULT)
set(${RESULT} "Hello Macro")
# 輸出 Hello Function,函數傳回值
get_func(V1)
message(${V1})
# 輸出 Hello Macro,宏傳回值
get_macro(V2)
message(${V2})
7)字元串的一些問題
字元串可跨行且支援轉移字元,例如:
set(VAR "hello
world")
message("\${VAR} = ${VAR}")
# 輸出結果為:
# ${VAR} = hello
# world
二.cmake的常用指令
CMake 2.8 的指令可以在此查詢:http://www.cmake.org/cmake/help/v2.8.8/cmake.html#section_Commands
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 中
使用範例: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
使用範例:add_library(Lib ${DIR_SRCS})
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)
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 檔案
使用範例:include_directories(${PROJECT_SOURCE_DIR}/lib)
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")
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)
三.CMake常用變量
1.${UNIX} 如果為真,表示為 UNIX-like 的系統,包括 AppleOS X 和 CygWin
2.${WIN32} 如果為真,表示為 Windows 系統,包括 CygWin
3.${APPLE} 如果為真,表示為 Apple 系統
4.${CMAKE_SIZEOF_VOID_P} 表示 void* 的大小(例如為 4 或者 8),可以使用其來判斷目前建構為 32 位還是 64 位
5.${CMAKE_CURRENT_LIST_DIR} 表示正在處理的CMakeLists.txt 檔案的所在的目錄的絕對路徑(2.8.3 以及以後版本才支援)
6.${CMAKE_ARCHIVE_OUTPUT_DIRECTORY} 用于設定 ARCHIVE 目标的輸出路徑
7.${CMAKE_LIBRARY_OUTPUT_DIRECTORY} 用于設定 LIBRARY 目标的輸出路徑
8.${CMAKE_RUNTIME_OUTPUT_DIRECTORY} 用于設定 RUNTIME 目标的輸出路徑
9.${PROJECT_SOURCE_DIR} ${CMAKE_SOURCE_DIR} ${<projectname>_SOURCE_DIR} 這三個變量指代的内容是一緻的,不論采用何種編譯方式,都是工程頂層目錄。也就是在 in source 編譯時,他跟 CMAKE_BINARY_DIR 等變量一緻。PROJECT_SOURCE_DIR 跟其他指令稍有差別,現在,你可以了解為他們是一緻的。
10.${PROJECT_NAME}傳回通過 PROJECT 指令定義的項目名稱。
11.${CMAKE_BINARY_DIR} ${PROJECT_BINARY_DIR} ${<projectname>_BINARY_DIR} 這三個變量指代的内容是一緻的,如果是 in source 編譯,指得就是工程頂層目錄;如果是 out-of-source 編譯,指的是工程編譯發生的目錄。PROJECT_BINARY_DIR 跟其他指令稍有差別,現在,你可以了解為他們是一緻的。
12.${CMAKE_CURRENT_SOURCE_DIR} 指的是目前處理的 CMakeLists.txt 所在的路徑,比如上面我們提到的 src 子目錄。
13.${CMAKE_CURRRENT_BINARY_DIR}如果是 in-source 編譯,它跟 CMAKE_CURRENT_SOURCE_DIR 一緻,如果是 out-of-source 編譯,他指的是 target 編譯目錄。使用我們上面提到的 ADD_SUBDIRECTORY(src bin)可以更改這個變量的值。使用 SET(EXECUTABLE_OUTPUT_PATH <新路徑>)并不會對這個變量造成影響,它僅僅修改了最終目标檔案存放的路徑。
14.${CMAKE_CURRENT_LIST_FILE}輸出調用這個變量的 CMakeLists.txt 的完整路徑
15.${CMAKE_CURRENT_LIST_LINE}輸出這個變量所在的行
16.${CMAKE_MODULE_PATH}這個變量用來定義自己的 cmake 子產品所在的路徑。如果你的工程比較複雜,有可能會自己編寫一些 cmake 子產品,這些 cmake 子產品是随你的工程釋出的,為了讓 cmake 在處理CMakeLists.txt 時找到這些子產品,你需要通過 SET 指令,将自己的 cmake 子產品路徑設定一下。比如SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)這時候你就可以通過 INCLUDE 指令來調用自己的子產品了。
17.${EXECUTABLE_OUTPUT_PATH} 和 ${LIBRARY_OUTPUT_PATH}分别用來重新定義最終結果的存放目錄,前面我們已經提到了這兩個變量。
四.建構類型
CMake 為我們提供了四種建構類型:
Debug
Release
MinSizeRel
RelWithDebInfo
如果使用 CMake 為 Windows MSVC 生成 projects/workspaces 那麼我們将得到上述的 4 種解決方案配置。
如果使用 CMake 生成 Makefile 時,我們需要做一些不同的工作。CMake 中存在一個變量 CMAKE_BUILD_TYPE 用于指定建構類型,此變量隻用于基于 make 的生成器。我們可以這樣指定建構類型:
$ CMake -DCMAKE_BUILD_TYPE=Debug .
這裡的 CMAKE_BUILD_TYPE 的值為上述的 4 種建構類型中的一種。
生成Debug和Release版本
在 Visual Studio 中我們可以生成 debug 版和 release 版的程式,使用 CMake 我們也可以達到上述效果。debug 版的項目生成的可執行檔案需要有調試資訊并且不需要進行優化,而 release 版的不需要調試資訊但需要優化。這些特性在 gcc/g++ 中是通過編譯時的參數來決定的,如果将優化程度調到最高需要設定參數-O3,最低是 -O0 即不做優化;添加調試資訊的參數是 -g -ggdb ,如果不添加這個參數,調試資訊就不會被包含在生成的二進制檔案中。
CMake 中有一個變量CMAKE_BUILD_TYPE ,可以的取值是 Debug、Release、RelWithDebInfo 和 MinSizeRel。當這個變量值為 Debug 的時候,CMake 會使用變量 CMAKE_CXX_FLAGS_DEBUG 和 CMAKE_C_FLAGS_DEBUG中的字元串作為編譯選項生成Makefile ,當這個變量值為 Release 的時候,工程會使用變量 CMAKE_CXX_FLAGS_RELEASE 和CMAKE_C_FLAGS_RELEASE 選項生成 Makefile。
示例:
PROJECT(main)
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
SET(CMAKE_SOURCE_DIR .)
SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
AUX_SOURCE_DIRECTORY(. DIR_SRCS)
ADD_EXECUTABLE(main ${DIR_SRCS})
第 5 和 6 行設定了兩個變量 CMAKE_CXX_FLAGS_DEBUG 和CMAKE_CXX_FLAGS_RELEASE, 這兩個變量是分别用于 debug 和 release 的編譯選項。
五.編譯和連結标志
C 編譯标志相關變量:
CMAKE_C_FLAGS
CMAKE_C_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]
C++ 編譯标志相關變量:
CMAKE_CXX_FLAGS
CMAKE_CXX_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]
CMAKE_C_FLAGS 或CMAKE_CXX_FLAGS 可以指定編譯标志
CMAKE_C_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]或 CMAKE_CXX_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO] 則指定特定建構類型的編譯标志,這些編譯标志将被加入到 CMAKE_C_FLAGS 或 CMAKE_CXX_FLAGS 中去,例如,如果建構類型為 DEBUG,那麼 CMAKE_CXX_FLAGS_DEBUG 将被加入到 CMAKE_CXX_FLAGS中去.
連結标志相關變量:
CMAKE_EXE_LINKER_FLAGS
CMAKE_EXE_LINKER_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]
CMAKE_MODULE_LINKER_FLAGS
CMAKE_MODULE_LINKER_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]
CMAKE_SHARED_LINKER_FLAGS
CMAKE_SHARED_LINKER_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]
它們類似于編譯标志相關變量
六.編譯32位和64位程式
對于 Windows MSVC,我們可以設定 CMake Generator 來确定生成 Win32 還是 Win64 工程檔案,例如:
# 用于生成 Visual Studio 10Win64 工程檔案
CMake -G "Visual Studio 10 Win64"
# 用于生成 Visual Studio 10Win32 工程檔案
CMake -G "Visual Studio 10"
我們可以通過 CMake --help 來檢視目前平台可用的 Generator。
CMake .. -DUSE_32BITS=1
if(USE_32BITS)
message(STATUS "Using 32bits")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}-m32")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}-m32")
endif(USE_32BITS)
對于 UNIX 和類 UNIX 平台,我們可以通過編譯器标志(選項)來控制進行 32 位還是 64 位建構。
GCC指令行參數
32位版:加上 -m32 參數,生成32位的代碼。
64位版:加上 -m64 參數,生成64位的代碼。
debug版:加上 -g 參數,生成調試資訊。
release版:加上 -static 參數,進行靜态連結,使程式不再依賴動态庫。加上 -O3 參數,進行最快速度優化。加上-DNDEBUG參數,定義NDEBUG宏,屏蔽斷言。
當沒有-m32或-m64參數時,一般情況下會生成跟作業系統位數一緻的代碼,但某些編譯器存在例外,例如——
32位Linux下的GCC,預設是編譯為32位代碼。
64位Linux下的GCC,預設是編譯為64位代碼。
Window系統下的MinGW,總是編譯為32位代碼。因為MinGW隻支援32位代碼。
Window系統下的MinGW-w64(例如安裝了TDM-GCC,選擇MinGW-w64),預設是編譯為64位代碼,包括在32位的Windows系統下。
Makefile檔案中的示例:
# [args] 生成模式. 0代表debug模式, 1代表release模式. makeRELEASE=1.
ifeq ($(RELEASE),0)
CFLAGS += -g
else
#release
CFLAGS += -static -O3 -DNDEBUG
LFLAGS += -static
endif
# [args] 程式位數. 32代表32位程式, 64代表64位程式, 其他預設. makeBITS=32.
ifeq ($(BITS),32)
CFLAGS += -m32
LFLAGS += -m32
ifeq($(BITS),64)
CFLAGS += -m64
LFLAGS += -m64
else
endif
七.多源檔案目錄的處理方式
例子1:其他源目錄檔案當作庫檔案
我們在每一個源碼目錄中都會放置一個 CMakeLists.txt 檔案。我們現在假定有這麼一個工程:
HelloWorld
|
+------- Main.cpp
+------- CMakeLists.txt
+------- Lib
|
+------- Lib.cpp
+------- Lib.h
+------- CMakeLists.txt
這裡 Lib 目錄下的檔案将被編譯為一個庫。首先,我們看一下 Lib 目錄下的 CMakeLists.txt 檔案:
add_library(Lib STATIC ${DIR_SRCS})
然後,看一下 HelloWorld 目錄下的 CMakeLists.txt 檔案:
project(Main)
add_subdirectory(Lib) #表示需要執行lib下的CMakeLists.txt
INCLUDE_DIRECTORIES(Lib) #.h檔案的搜尋路徑
add_executable(Main ${DIR_SRCS})
target_link_libraries(Main Lib)
這裡使用了 add_subdirectory 指定了需要進行建構的子目錄,并且使用了 target_link_libraries 指令,表示 Main 可執行檔案需要連結 Lib庫。我們執行 CMake . 指令,首先會執行 HelloWorld 目錄下的 CMakeLists.txt 中的指令,當執行到 add_subdirectory(Lib) 指令的時候會進入 Lib 子目錄并執行其中的CMakeLists.txt 檔案。
例子2:多目錄下的源檔案使用一個 CMakeLists.txt編譯
一個完整的Demo可參考這裡。假設目前目錄的結構為
Demo
+------- a.cpp
+------- b.cpp
+------- include
|
+------- common.h
|
+------- defines.h
+------- other
+------- c.cpp
+------- d.cpp
+------- libB.a
+------- libBd.a
+------- libA.so
+------- libAd.so
+------- libB.so
+------- libBd.so
+------- libC.so
+------- libCd.so
使用下面的CMakeLists.txt檔案,目标是編譯目前目錄和./other目錄下的所有源檔案,并連結./lib目錄下的相應庫檔案到最終的可執行檔案./bin/hello(或./bin/hellod)。
project(helloworld)
set(CMAKE_VERBOSE_MAKEFILE on)
set(CMAKE_CXX_COMPILER "g++")
set(CMAKE_CXX_FLAGS "-Wall")
set(CMAKE_CXX_FLAGS_DEBUG "-g3")
set(CMAKE_CXX_FLAGS_RELEASE "-O2")
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
set(SRC_LIST "")
aux_source_directory(. tmpdir)
set(DIR_SRCS ${SRC_LIST} ${tmpdir})
aux_source_directory(./other tmpdir)
#... ... 這裡可以用一個foreach來做
include_directories(${PROJECT_SOURCE_DIR}/include)
link_directories(${PROJECT_SOURCE_DIR}/lib)
if(${CMAKE_BUILD_TYPE} MATCHES "debug")
add_executable(hellod ${SRC_LIST})
target_link_libraries(hellod Ad Bd.a Cd.so)
add_executable(hello ${SRC_LIST})
target_link_libraries(hello A B.a C.so)
執行指令cmake -DCMAKE_BUILD_TYPE=debug . 生成Makefile,make之後生成./bin/hellod(調試版本),或執行cmake .最後生成./bin/hello。
例子3 CMakeLists.txt檔案的一般寫法(一個簡單的模闆,用于生成庫或可執行檔案)
#(1)指明cmke需要的版本及工程名
#(2)指明工程的CMakeLists.txt樹節點.(通常用于庫工程的編譯或多工程的編譯,指明其他工程的CMakeLists.txt的路徑),目的是形成CMakeLists.txt樹,但各個CMakeLists.txt之間是隔離的.
add_subdirectory(lib) #lib工程,可能要生成靜态或動态庫
add_subdirectory(sample1) #sample1工程,可能需要生成一個.exe
...
#(3)添加本工程的宏定義
add_definitions(-D_UNICODE -DUNICODE)
#(4)添加本工程的頭檔案搜尋路徑及已有庫的搜尋路徑
include_directories(Lib) #多路徑時,用空格分隔
link_directories(/usr/lib /usr/local/lib)
#(5)添加本工程所有源檔案所在路徑
set(SRC_LIST "") #使用這種方式添加其實挺友善
#(6)添加本工程生成的目标,可執行目标或庫目标
add_executable(main ${DIR_SRCS}) 或者 add_library(hello STATIC ${DIR_SRCS})
#(7)添加本工程目标所依賴的庫目标及其他已有庫
target_link_libraries(main hello pthread ) #連結庫用空格分隔
本文轉自 a_liujin 51CTO部落格,原文連結:http://blog.51cto.com/a1liujin/1794706,如需轉載請自行聯系原作者