cmake學習

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

cmake_minimum_required(VERSION 2.8)

set(YES 0)

# 輸出 True

if(YES)

   message(True)

else()

   message(False)

endif()


# 輸出 False

if(${YES})

   message(True)

else()

   message(False)

endif()


表達式中可以包含操作符,操作符包括:

一元操作符,例如: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)

   message(${MESSAGE})

endfunction()


函數和宏可以通過命令 return() 返回,但是函數和宏的返回值必須通過參數傳遞出去。例如:


cmake_minimum_required(VERSION 2.8)


function(get_func RESULT)

    #RESULT 的值爲實參的值,因此需要使用 ${RESULT}

    #這裏使用 PARENT_SCOPE 是因爲函數會構建一個局部作用域

   set(${RESULT} "Hello Function" PARENT_SCOPE)

endfunction()


macro(get_macro RESULT)

   set(${RESULT} "Hello Macro")

endmacro()


 

# 輸出 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")

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)

三.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")

else()

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

else

    ifeq($(BITS),64)

       CFLAGS += -m64

       LFLAGS += -m64

   else

   endif

endif




七.多源文件目錄的處理方式

例子1:其他源目錄文件當作庫文件

我們在每一個源碼目錄中都會放置一個 CMakeLists.txt 文件。我們現在假定有這麼一個工程:

HelloWorld

|

+------- Main.cpp

|

+------- CMakeLists.txt

|

+------- Lib

        |

        +------- Lib.cpp

        |

        +------- Lib.h

        |

        +------- CMakeLists.txt

這裏 Lib 目錄下的文件將被編譯爲一個庫。首先,我們看一下 Lib 目錄下的 CMakeLists.txt 文件:

aux_source_directory(. DIR_SRCS)

add_library(Lib STATIC ${DIR_SRCS})

然後,看一下 HelloWorld 目錄下的 CMakeLists.txt 文件:

project(Main)

cmake_minimum_required(VERSION 2.8)

add_subdirectory(Lib)  #表示需要執行lib下的CMakeLists.txt

        INCLUDE_DIRECTORIES(Lib) #.h文件的搜索路徑

aux_source_directory(. DIR_SRCS)

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

|

+------- CMakeLists.txt

|

+------- Lib

        |

        +------- libB.a

        |

        +------- libBd.a

        |

        +------- libA.so

        |

        +------- libAd.so

        |

        +------- libB.so

        |

        +------- libBd.so

        |

        +------- libC.so

        |

        +------- libCd.so



使用下面的CMakeLists.txt文件,目標是編譯當前目錄和./other目錄下的所有源文件,並鏈接./lib目錄下的相應庫文件到最終的可執行文件./bin/hello(或./bin/hellod)。


cmake_minimum_required(VERSION 2.8)

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)

set(DIR_SRCS ${SRC_LIST} ${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)

else()

    add_executable(hello ${SRC_LIST})

    target_link_libraries(hello A B.a C.so)

endif()


執行命令cmake -DCMAKE_BUILD_TYPE=debug . 生成Makefile,make之後生成./bin/hellod(調試版本),或執行cmake .最後生成./bin/hello。


例子3 CMakeLists.txt文件的一般寫法(一個簡單的模板,用於生成庫或可執行文件)

#(1)指明cmke需要的版本及工程名

cmake_minimum_required(VERSION 2.8)

project(helloworld)

#(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 "") #使用這種方式添加其實挺方便

aux_source_directory(.  tmpdir)

set(DIR_SRCS ${SRC_LIST} ${tmpdir})

aux_source_directory(./other  tmpdir)

set(DIR_SRCS ${SRC_LIST} ${tmpdir})

...

#(6)添加本工程生成的目標,可執行目標或庫目標

add_executable(main ${DIR_SRCS}) 或者 add_library(hello STATIC ${DIR_SRCS})

#(7)添加本工程目標所依賴的庫目標及其他已有庫

target_link_libraries(main hello pthread ) #鏈接庫用空格分隔


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章