CMake學習

CMake學習

本篇分享一下有關CMake的一些學習心得以及相關使用。html

做者:AlphaGL。版權全部,歡迎保留原文連接進行轉載 :)java

本文目錄以下:express

一、CMake介紹

CMake全稱爲「cross platform make」,是一個開源的跨平臺自動化構建系統。使用指定名爲CMakeLists.txt的配置文件能夠控制軟件的構建、測試和打包等流程。同時,經過編寫平臺無關的CMakeLists.txt文件和須要簡單的配置,CMake就能生成對應目標平臺的構建文件,例如:類Unix系統的makefile文件、Windows的Visual Studio工程或者Mac的Xcode工程,大大簡化了跨平臺和交叉編譯方面的工做。編程

固然,相似的make工具也不少,AutocofJAMQMakeSCons甚至ANT,目的都是指定一套規則來簡化整個構建編譯流程。CMake工具鏈簡單、靈活,且跨平臺,不少知名項目都在使用CMake構建。適合以C、C++或者java等編譯語言的項目。json

二、CMake安裝與使用

2.1 CMake的安裝

CMake下載地址爲:
https://cmake.org/download/緩存

2.2 CMake-gui的使用

CMake的安裝過程很簡單,這裏就再也不贅述了。其中CMake提供帶GUI界面的工具cmake-gui。本文主要是以命令行的形式來說述CMake的使用,這裏就稍微提一下cmake-gui的使用。原理都是差很少的。app

簡述操做步驟以下:
一、在本地目錄新建cmake文件夾(例如:個人目錄爲E:\workplace\cmake),並在cmake目錄中建立bin目錄用於存放構建過程當中產生的臨時文件和目標文件(例如:個人目錄爲E:\workplace\cmake\bin)。編程語言

二、在cmake目錄中新建hello_cmake.cCMakeLists.txt文件,內容以下:
hello_cmake.cide

#include <stdio.h>

int main() {
    printf("Hello CMake\n");
    return 0;
}

CMakeLists.txt函數

cmake_minimum_required (VERSION 2.8)
project (HelloCMake)
add_executable(HelloCMake hello_cmake.c)

三、運行cmake-gui,會打開以下界面:

(1)源碼所在的路徑,即CMakeLists.txt所在的路徑。本例爲E:\workplace\cmake
(2)構建過程當中產生的文件的路徑。本例爲:E:\workplace\cmake\bin,注意這個路徑能夠與(1)路徑相同,但若項目很大產生的文件不少要執行清理等操做時會比較麻煩。
(3)執行configure。


這裏指定生成的構建工程爲VS2012的項目工程。點擊Finish便可自動編譯,並生成對應的*.sln的項目文件。

在Visual Studio中打開該項目,並執行。能夠看到正確輸出了"Hello CMake"。

2.3 CMake命令行的使用

這裏,依然使用剛纔的示例來講明下CMake命令行的方式的使用(清理bin目錄下的文件便可),使用步驟以下:
(1)將CMake安裝路徑添加到Path環境變量中。Mac版本能夠終端中輸入命令:export PATH=/Applications/CMake.app/Contents/bin:$PATH便可。

(2)在Windows命令行中執行以下命令:

在當前構建的路徑,執行cmake,cmake後面參數爲CMakeLists.txt所在路徑,-G用來指定構建生成目標平臺的項目工程。分別對應上面的GUI的操做。

(3)在類Unix的操做系統中,能夠執行以下操做。這裏我仍是用的上面的示例代碼,我用Cygwin模擬下對應的cmake操做,如圖:

在Cygwin中新版的CMake會報警告(在32位Windows系統上則會報錯)。

因而可知,在Unix系列的操做系統上,使用CMake步驟分爲:

  1. 編寫CMakeLists.txt配置文件。
  2. 執行cmake命令生成makefile文件。
  3. 執行make命令編譯執行,生成最終的目標文件。
  4. 運行最終生成的可執行文件便可,這步可選。
2.4 CMake命令行說明

CMake命令行的選項能夠在命令行終端上,輸入cmake --help查看。更詳盡的解釋能夠查看CMake的官方手冊。

cmake幫助手冊

CMake命令行格式爲:

(1) cmake [<options>] (<path-to-source> | <path-to-existing-build>)  
(2) cmake [(-D <var>=<value>)...] -P <cmake-script-file>  
(3) cmake --build <dir> [<options>...] [-- <build-tool-options>...]  
(4) cmake -E <command> [<options>...]  
(5) cmake --find-package <options>...

常見的使用方式是第一種。這裏也主要介紹這種方式。
(1)[<options>],表示option爲可選的。path-to-sourcepath-to-existing-build二選一,分別表示一個CMakeLists.txt所在的路徑和一個已存在的構建工程所在的路徑。例如:

cmake .

這裏option爲空,構建的路徑爲用戶所在的當前路徑。

其中option經常使用的有:
-G <generator-name>
指定構建系統生成器,當前平臺所支持的generator-name能夠經過幫助手冊查看。例如: cmake -G "Visual Studio 11 2012" E:\workplace\cmake,生成VS2012的構建工程。

-D <var>:<type>=<value>, -D <var>=<value>
添加變量及值到CMakeCache.txt中。例如:cmake -D EXECUTABLE_OUTPUT_PATH="bin" .,會在CMakeCache.txt中添加一條

//No help, variable specified on the command line.
EXECUTABLE_OUTPUT_PATH:UNINITIALIZED=bin

這樣,能夠在CMakeLists.txt文件中讀取該變量的值。例如:message(${EXECUTABLE_OUTPUT_PATH})

-U <globbing_expr>
此選項可用於從CMakeCache.txt文件中刪除一個或多個變量,支持使用*的匹配。與-D對應,使用是須謹慎,可能會致使CMakeCache.txt不工做。

-i
以嚮導的方式運行CMake。此選項會彈出一系列的提示,要求用戶回答關於工程配置的一些問題。這些結果會被用來設置cmake的緩存值。注意,新版的CMake可能再也不支持此選項。

-E
CMake命令行模式。CMake提供了一系列與平臺無關的命令。例如:copymake_directoryecho等,更多詳細參見cmake -E help

三、CMake語法及CMakeLists.txt編寫

用CMake構建一個項目工程,是經過一個或多個CMakeLists.txt文件來控制的。CMakeLists.txt中包含一系列命令來描述須要執行的構建。

3.1 CMake語法

在CMakeLists.txt中的命令的語法,都是形以下面這種格式:

command (args...)

command:是命令的名字。
args:是參數的列表。多個參數使用空格隔開。

3.1.1 經常使用的命令

cmake_minimum_required
設置項目要求的CMake最低版本號,若是當前版本的CMake低於所需的值,它將中止處理項目並報告錯誤。注意在project以前調用該命令,通常在CMakeLists.txt文件開頭調用。命令格式爲:

cmake_minimum_required(VERSION major.minor[.patch[.tweak]]
                       [FATAL_ERROR])

使用示例:

cmake_minimum_required(VERSION 2.8.5)

add_custom_command
該命令能夠爲生成的構建系統添加一條自定義的構建規則。這裏又包含兩種使用方式,一種是經過自定義命令在構建中生成輸出文件,另一種是向構建目標添加自定義命令。命令格式分別爲:
(1)生成文件

add_custom_command(OUTPUT output1 [output2 ...]
                   COMMAND command1 [ARGS] [args1...]
                   [COMMAND command2 [ARGS] [args2...] ...]
                   [MAIN_DEPENDENCY depend]
                   [DEPENDS [depends...]]
                   [BYPRODUCTS [files...]]
                   [IMPLICIT_DEPENDS <lang1> depend1
                                    [<lang2> depend2] ...]
                   [WORKING_DIRECTORY dir]
                   [COMMENT comment]
                   [DEPFILE depfile]
                   [VERBATIM] [APPEND] [USES_TERMINAL])

參數介紹:
OUTPUT:
指定命令預期產生的輸出文件。若是輸出文件的名稱是相對路徑,即相對於當前的構建的源目錄路徑。輸出文件能夠指定多個output1,output2(可選)等。

COMMAND:
指定要在構建時執行的命令行。若是指定多個COMMAND,它們講按順心執行。ARGS參數是爲了向後兼容,爲可選參數。args1和args2爲參數,多個參數用空格隔開。

MAIN_DEPENDENCY:
可選命令,指定命令的主要輸入源文件。

DEPENDS:
指定命令所依賴的文件。

BYPRODUCTS:
可選命令,指定命令預期產生的文件,但其修改時間可能會比依賴性更新,也可能不會更新。

IMPLICIT_DEPENDS:
可選命令,請求掃描輸入文件的隱式依賴關係。給定的語言指定應使用相應的依賴性掃描器的編程語言。目前只支持C和CXX語言掃描器。必須爲IMPLICIT_DEPENDS列表中的每一個文件指定語言。從掃描中發現的依賴關係在構建時添加到自定義命令的依賴關係。請注意,IMPLICIT_DEPENDS選項目前僅支持Makefile生成器,而且將被其餘生成器忽略。

WORKING_DIRECTORY:
可選命令,使用給定的當前工做目錄執行命令。若是它是相對路徑,它將相對於對應於當前源目錄的構建樹目錄。

COMMENT:
可選命令,在構建時執行命令以前顯示給定消息。

DEPFILE:
可選命令,爲Ninja生成器指定一個.d depfile。 .d文件保存一般由自定義命令自己發出的依賴關係。對其餘生成器使用DEPFILE是一個錯誤。

使用實例:

add_executable(MakeTable MakeTable.cxx) 
add_custom_command (
  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
  COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
  DEPENDS MakeTable
  COMMENT "This is a test"
  )

(2)自定義構建事件

add_custom_command(TARGET <target>
                   PRE_BUILD | PRE_LINK | POST_BUILD
                   COMMAND command1 [ARGS] [args1...]
                   [COMMAND command2 [ARGS] [args2...] ...]
                   [BYPRODUCTS [files...]]
                   [WORKING_DIRECTORY dir]
                   [COMMENT comment]
                   [VERBATIM] [USES_TERMINAL])

參數介紹:
TARGET:
定義了與構建指定 相關聯的新命令。當 已經存在是,相應的command將再也不執行。

PRE_BUILD:
在目標中執行任何其餘規則以前運行。這僅在Visual Studio 7或更高版本上受支持。對於全部其餘生成器PRE_BUILD將被視爲PRE_LINK。

PRE_LINK:
在編譯源以後運行,但在連接二進制文件或運行靜態庫的庫管理器或存檔器工具以前運行。

POST_BUILD:
在目標中的全部其餘規則都已執行後運行。

使用實例:

add_custom_command(TARGET ${APP_NAME} 
             PRE_BUILD
                     COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/Resources ${CMAKE_CURRENT_BINARY_DIR})

add_custom_target
該命令能夠給指定名稱的目標執行指定的命令,該目標沒有輸出文件,並始終被構建。命令的格式爲:

add_custom_target(Name [ALL] [command1 [args1...]]
                  [COMMAND command2 [args2...] ...]
                  [DEPENDS depend depend depend ... ]
                  [BYPRODUCTS [files...]]
                  [WORKING_DIRECTORY dir]
                  [COMMENT comment]
                  [VERBATIM] [USES_TERMINAL]
                  [SOURCES src1 [src2...]])

參數介紹(上面介紹過含義相同的參數,這裏就再也不贅述了):
Name:
指定目標的名稱。

ALL:
代表此目標應添加到默認構建目標,以便每次都將運行(該命令名稱不能爲ALL)

SOURCES:
指定要包括在自定義目標中的其餘源文件。指定的源文件將被添加到IDE項目文件中,以方便編輯,即便它們沒有構建規則。

使用示例:

add_custom_target(APP ALL
      DEPENDS ${APP_NAME} # 依賴add_custom_command輸出的jar包
      COMMENT "building cassdk_jni.jar"
    )

add_definitions
爲源文件的編譯添加由-D引入的宏定義。命令格式爲:

add_definitions(-DFOO -DBAR ...)

使用示例:

add_definitions(-DWIN32)

add_dependencies
使頂級目標依賴於其餘頂級目標,以確保它們在該目標以前構建。這裏的頂級目標是由add_executableadd_libraryadd_custom_target命令之一建立的目標。
使用示例:

add_custom_target(mylib DEPENDS ${MYLIB})
add_executable(${APP_NAME} ${SRC_LIST})
add_dependencies(${APP_NAME} mylib)

add_executable
使用指定的源文件給項目添加一個可執行文件。命令格式爲:

add_executable(<name> [WIN32] [MACOSX_BUNDLE]
               [EXCLUDE_FROM_ALL]
               source1 [source2 ...])

參數介紹:
name:
該命令調用列出的源文件來構建的可執行目標 對應於邏輯目標名稱,在項目中必須是全局惟一的。構建的可執行文件的實際文件名是基於本機平臺的約定。

WIN32:
若是給出WIN32,則在建立的目標上設置屬性WIN32_EXECUTABLE。

MACOSX_BUNDLE:
若是給定MACOSX_BUNDLE,將在建立的目標上設置相應的屬性。

EXCLUDE_FROM_ALL:
若是給定EXCLUDE_FROM_ALL,將在建立的目標上設置相應的屬性。

source:
源碼列表。

使用示例:

add_executable(HelloCMake hello_cmake.c)

add_library
使用指定的源文件給項目添加一個庫。命令格式爲:

add_library(<name> [STATIC | SHARED | MODULE]
            [EXCLUDE_FROM_ALL]
            source1 [source2 ...])

參數介紹:
name:
該命令調用列出的源文件來構建的庫目標 對應於邏輯目標名稱,在項目中必須是全局惟一的。

STATIC:
靜態庫,在連接其餘目標時使用。

SHARED:
動態連接庫,運行時加載。

MODULE:
不會被連接到其它目標中,可是可能會在運行時使用dlopen-系列的函數動態連接。

使用示例:

add_library(HelloCMake hello_cmake.c)

add_subdirectory:
向構建中添加子目錄。命令格式爲:

add_subdirectory(source_dir [binary_dir]
                 [EXCLUDE_FROM_ALL])

使用示例:

add_subdirectory(${SRC_ROOT})

aux_source_directory
查找目錄中的全部源文件。命令格式爲:

aux_source_directory(<dir> <variable>)

查找指定目錄dir中全部源文件的名稱,並將列表存儲在提供的variable中。

使用示例:

aux_source_directory(. DIR_SRCS)
add_executable(${APP_NAME} ${DIR_SRCS})

configure_file
將文件複製到其餘位置並修改其內容。命令格式爲:

configure_file(<input> <output>
               [COPYONLY] [ESCAPE_QUOTES] [@ONLY]
               [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])

使用示例:

configure_file (
  "${PROJECT_SOURCE_DIR}/Config.h.in"
  "${PROJECT_BINARY_DIR}/Config.h"
  )

file
文件操做相關的命令。命令格式爲:

file(WRITE <filename> <content>...)
file(APPEND <filename> <content>...)
file(READ <filename> <variable>
     [OFFSET <offset>] [LIMIT <max-in>] [HEX])
file(STRINGS <filename> <variable> [<options>...])
file(<MD5|SHA1|SHA224|SHA256|SHA384|SHA512> <filename> <variable>)
file(GLOB <variable>
     [LIST_DIRECTORIES true|false] [RELATIVE <path>]
     [<globbing-expressions>...])
file(GLOB_RECURSE <variable> [FOLLOW_SYMLINKS]
     [LIST_DIRECTORIES true|false] [RELATIVE <path>]
     [<globbing-expressions>...])
file(RENAME <oldname> <newname>)
file(REMOVE [<files>...])
file(REMOVE_RECURSE [<files>...])
file(MAKE_DIRECTORY [<directories>...])
file(RELATIVE_PATH <variable> <directory> <file>)
file(TO_CMAKE_PATH "<path>" <variable>)
file(TO_NATIVE_PATH "<path>" <variable>)
file(DOWNLOAD <url> <file> [<options>...])
file(UPLOAD   <file> <url> [<options>...])
file(TIMESTAMP <filename> <variable> [<format>] [UTC])
file(GENERATE OUTPUT output-file
     <INPUT input-file|CONTENT content>
     [CONDITION expression])
file(<COPY|INSTALL> <files>... DESTINATION <dir>
     [FILE_PERMISSIONS <permissions>...]
     [DIRECTORY_PERMISSIONS <permissions>...]
     [NO_SOURCE_PERMISSIONS] [USE_SOURCE_PERMISSIONS]
     [FILES_MATCHING]
     [[PATTERN <pattern> | REGEX <regex>]
      [EXCLUDE] [PERMISSIONS <permissions>...]] [...])
file(LOCK <path> [DIRECTORY] [RELEASE]
     [GUARD <FUNCTION|FILE|PROCESS>]
     [RESULT_VARIABLE <variable>]
     [TIMEOUT <seconds>])

以上都是文件相關的操做,這裏就不詳細解釋。
使用示例爲:

# 查找src目錄下全部以hello開頭的文件並保存到SRC_FILES變量裏
file(GLOB SRC_FILES "src/hello*")
# 遞歸查找
file(GLOB_RECURSE SRC_FILES "src/hello*")

find_file
查找一個文件的完整路徑。命令格式爲:

find_file (<VAR> name1 [path1 path2 ...])

使用示例:

find_file(HELLO_H hello.h)

find_library
查找一個庫文件。命令格式爲:

find_library (<VAR> name1 [path1 path2 ...])

使用示例:

find_library(LUA lua5.1 /usr/lib /lib)

find_package
查找並加載外部項目的設置。命令格式爲:

find_package(<package> [version] [EXACT] [QUIET] [MODULE]
             [REQUIRED] [[COMPONENTS] [components...]]
             [OPTIONAL_COMPONENTS components...]
             [NO_POLICY_SCOPE])

使用示例爲:

find_package(Protobuf)

find_path
查找包含某個文件的路徑。命令格式爲:

find_path (<VAR> name1 [path1 path2 ...])

使用示例:

find_path(DIR_SRCS hello.h .)

include_directories
將給定的目錄添加到編譯器用於搜索包含文件的目錄。相對路徑則相對於當前源目錄。命令格式爲:

include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])

使用示例:

include_directories(
  ${CMAKE_CURRENT_SOURCE_DIR}
  ${CMAKE_CURRENT_SOURCE_DIR}/cocos
  ${CMAKE_CURRENT_SOURCE_DIR}/cocos/platform
  ${CMAKE_CURRENT_SOURCE_DIR}/extensions
  ${CMAKE_CURRENT_SOURCE_DIR}/external
)

include
包含其餘目錄的CMakeLists.txt文件。命令格式爲:

include(<file|module> [OPTIONAL] [RESULT_VARIABLE <VAR>]
                      [NO_POLICY_SCOPE])

使用示例:

include(platform/CMakeLists.txt)

link_directories
指定連接器查找庫的路徑。命令格式爲:

link_directories(directory1 directory2 ...)

使用示例:

link_directories(${PROJECT_SOURCE_DIR}/lib)

list
列表相關的操做。命令格式爲:

list(LENGTH <list> <output variable>)
list(GET <list> <element index> [<element index> ...]
     <output variable>)
list(APPEND <list> [<element> ...])
list(FILTER <list> <INCLUDE|EXCLUDE> REGEX <regular_expression>)
list(FIND <list> <value> <output variable>)
list(INSERT <list> <element_index> <element> [<element> ...])
list(REMOVE_ITEM <list> <value> [<value> ...])
list(REMOVE_AT <list> <index> [<index> ...])
list(REMOVE_DUPLICATES <list>)
list(REVERSE <list>)
list(SORT <list>)

使用示例:

list(APPEND SRC_LIST
    ${PROTO_SRC}
)

message
向用戶顯示消息。命令格式爲:

message([<mode>] "message to display" ...)

參數說明:
mode:
可選的值爲none,STATUS,WARNING,AUTHOR_WARNING,SEND_ERROR,FATAL_ERROR,DEPRECATION。
使用示例:

message(STATUS "This is BINARY dir " ${HELLO_BINARY_DIR})

option
提供用戶能夠選擇的選項。命令格式爲:

option(<option_variable> "help string describing option"
       [initial value])

使用示例:

option (USE_MYMATH "Use tutorial provided math implementation" ON)

project
爲整個工程設置一個工程名。命令格式爲:

project(<PROJECT-NAME> [LANGUAGES] [<language-name>...])
project(<PROJECT-NAME>
        [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
        [LANGUAGES <language-name>...])

使用示例:

project (HelloCMake)

set
將一個CMAKE變量設置爲給定值。命令格式爲:

set(<variable> <value>... [PARENT_SCOPE])

使用示例:

set(COCOS2D_ROOT ${CMAKE_SOURCE_DIR}/cocos2d)

set_target_properties
設置目標的一些屬性來改變它們構建的方式。命令格式爲:

set_target_properties(target1 target2 ...
                      PROPERTIES prop1 value1
                      prop2 value2 ...)

使用示例爲:

set_target_properties(cocos2d
    PROPERTIES
    ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
    VERSION "${COCOS2D_X_VERSION}"
)

string
字符串相關操做。命令格式爲:

string(FIND <string> <substring> <output variable> [REVERSE])
string(REPLACE <match_string>
       <replace_string> <output variable>
       <input> [<input>...])
string(REGEX MATCH <regular_expression>
       <output variable> <input> [<input>...])
string(REGEX MATCHALL <regular_expression>
       <output variable> <input> [<input>...])
string(REGEX REPLACE <regular_expression>
       <replace_expression> <output variable>
       <input> [<input>...])
string(APPEND <string variable> [<input>...])
string(CONCAT <output variable> [<input>...])
string(TOLOWER <string1> <output variable>) 
string(TOUPPER <string1> <output variable>)
string(LENGTH <string> <output variable>)
string(SUBSTRING <string> <begin> <length> <output variable>)
string(STRIP <string> <output variable>)
string(GENEX_STRIP <input string> <output variable>)  
string(COMPARE LESS <string1> <string2> <output variable>)
string(COMPARE GREATER <string1> <string2> <output variable>)
string(COMPARE EQUAL <string1> <string2> <output variable>)
string(COMPARE NOTEQUAL <string1> <string2> <output variable>)
string(COMPARE LESS_EQUAL <string1> <string2> <output variable>)
string(COMPARE GREATER_EQUAL <string1> <string2> <output variable>)
string(<MD5|SHA1|SHA224|SHA256|SHA384|SHA512>
       <output variable> <input>)
string(ASCII <number> [<number> ...] <output variable>)
string(CONFIGURE <string1> <output variable>
       [@ONLY] [ESCAPE_QUOTES])
string(RANDOM [LENGTH <length>] [ALPHABET <alphabet>]
       [RANDOM_SEED <seed>] <output variable>)
string(TIMESTAMP <output variable> [<format string>] [UTC])
string(MAKE_C_IDENTIFIER <input string> <output variable>)
string(UUID <output variable> NAMESPACE <namespace> NAME <name>
       TYPE <MD5|SHA1> [UPPER])

使用示例:

string(REPLACE "${PROJECT_SOURCE_DIR}/hello.c" "" DIR_SRCS "${DIR_ROOT}")

target_link_libraries
將給定的庫連接到一個目標上。命令格式爲:

target_link_libraries(<target> ... <item>... ...)

使用示例:

target_link_libraries(luacocos2d cocos2d)
3.1.2 經常使用的變量

使用${}進行變量的引用。例如:message(${Hello_VERSION}),Hello爲工程名。CMake提供了不少有用的變量。如下僅列舉經常使用的變量:

CMAKE_BINARY_DIR
構建樹的頂層路徑

CMAKE_COMMAND
指向CMake可執行文件的完整路徑

CMAKE_CURRENT_BINARY_DIR
當前正在被處理的二進制目錄的路徑。

CMAKE_CURRENT_SOURCE_DIR
指向正在被處理的源碼目錄的路徑。

CMAKE_HOME_DIRECTORY
指向源碼樹頂層的路徑。

CMAKE_PROJECT_NAME
當前工程的工程名。

CMAKE_ROOT
CMake的安裝路徑。

CMAKE_SOURCE_DIR
源碼樹的頂層路徑。

CMAKE_VERSION
cmake的完整版本號。

PROJECT_BINARY_DIR
指向當前編譯工程構建的全路徑。

<PROJECT-NAME>_BINARY_DIR
指向當前編譯工程構建的全路徑。

<PROJECT-NAME>_SOURCE_DIR
指向構建工程的全路徑。

PROJECT_SOURCE_DIR
指向構建工程的全路徑。

PROJECT_NAME
project命令傳遞的工程名參數。

<PROJECT-NAME>_VERSION
項目的完整版本號。

3.2 CMakeLists.txt編寫

有了上面的基礎,再編寫CMakeLists.txt天然會事半功倍。下面,以幾個小實例來講下經過CMakeLists.txt的來構建項目。

這裏cJSON庫爲例來講明下CMakeLists.txt的寫法。固然,這裏的代碼並嚴謹,僅用來演示CMakeList的用法。

3.2.1 將cJSON構建爲靜態庫

(1)在本地創建cJSONdemo1的目錄工程,並將cJSON庫源代碼拷貝到目錄中,並在該目錄新建CMakeLists.txt文件。目錄結構以下:

cJSONdemo1  
├── cJSON_Utils.h  
├── cJSON_Utils.c  
├── cJSON.h
├── cJSON.c
└── CMakeLists.txt

CMakeLists.txt文件內容以下:

cmake_minimum_required(VERSION 2.8.5)
project(cJSON-lib)
set(CJSON_SRC cJSON.c cJSON_Utils.c)
add_library(cjson STATIC ${CJSON_SRC})

在終端下執行以下操做:

(2)自動搜索目錄源碼
在上面cJSONdemo1的基礎上作一些改進。前面提過set(<variable> <value>...),能夠預見在cJSON庫源碼愈來愈多的狀況下,會變成這樣:

set(CJSON_SRC cJSON.c cJSON1.c cJSON2.c cJSON3.c cJSON4.c cJSON5.c)

這樣,源文件越多,須要添加次數就越多。並且,每增長一個源文件就須要修改CMakeLists.txt文件,「耦合性」太大。這裏,可使用aux_source_directory來自動查找源文件。CMakeLists.txt文件最終以下:

cmake_minimum_required(VERSION 2.8.5)
project(cJSON-lib)
aux_source_directory(. CJSON_SRC)
add_library(cjson STATIC ${CJSON_SRC})

(3)遞歸搜索目錄源碼
若將cJSONdemo改爲包含子目錄,子目錄中又包含源碼的形式,有多級目錄。以下

cJSONdemo1  
  │── cJSON_Utils.h  
  │── cJSON_Utils.c  
  │── cJSON.h
  │── cJSON.c
  │── CMakeLists.txt 
  └── foo 
      ├── cJSON1.h
      ├── cJSON1.c
      ├── cJSON2.h
      ├── cJSON2.c
      └── goo 
          ├── cJSON3.h
          ├── cJSON3.c
          ├── cJSON4.h
          └── cJSON4.c

可使用file命令,來自動遞歸查找相應的源文件。CMakeLists.txt文件最終以下:

cmake_minimum_required(VERSION 2.8.5)
project(cJSON-lib)
file(GLOB_RECURSE CJSON_SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.c)
add_library(cjson STATIC ${CJSON_SRC})

(4)指定構建庫的名字,路徑和前綴。CMakeLists.txt文件最終以下:

cmake_minimum_required(VERSION 2.8.5)
project(cJSON-lib)
file(GLOB_RECURSE CJSON_SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.c)
add_library(cjson STATIC ${CJSON_SRC})
set_target_properties(cjson PROPERTIES OUTPUT_NAME "json")
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/static)
set(CMAKE_STATIC_LIBRARY_PREFIX "")

最終效果如圖:

會生成cJSONdemo1/static/json.a

3.2.1 將cJSON外部依賴庫連接進可執行文件中

經過上面過程瞭解了將cJSON庫構建文件靜態庫的過程。下面,再添加測試代碼來調用cJSON庫,並最終構建爲可執行文件。目錄以下:

cJSONdemo2  
  │── test.c
  │── CMakeLists.txt 
  └── lib 
      ├── cJScJSON_UtilsON1.h
      ├── cJSON_Utils.c
      ├── cJSON.h
      ├── cJSON.c
      └── CMakeLists.txt

test.c

#include <stdio.h>
#include <stdlib.h>
#include "lib/cJSON.h"

void parser(char* text) {
    char *out;
    cJSON *json;

    json = cJSON_Parse(text);
    if (!json) {
        printf("Error before: [%s]\n", cJSON_GetErrorPtr());
    }else {
        out = cJSON_Print(json);
        cJSON_Delete(json);
        printf("%s\n", out);
        free(out);
    }
}

int main(int argc, char * argv[]) {
    char text[]="[\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"]";
    parser(text);

    return 0;
}

cJSONdemo2/CMakeLists.txt

cmake_minimum_required(VERSION 2.8.5)

project(cjson-example)

aux_source_directory(. CJSON_EXAMPLE_SRC)

add_subdirectory(./lib)

add_executable(cjson-example ${CJSON_EXAMPLE_SRC})

target_link_libraries(cjson-example cjson)

cJSONdemo2/lib/CMakeLists.txt

cmake_minimum_required(VERSION 2.8.5)

aux_source_directory(. CJSON_SRC)

add_library(cjson STATIC ${CJSON_SRC})

在終端下執行以下操做:

3.2.2 將cJSON庫改成可選

在上面cJSONdemo2的基礎上,新建cJSONConfig.h.in並相應修改test.c。目錄以下:

cJSONdemo3  
  │── test.c
  │── cJSONConfig.h.in
  │── CMakeLists.txt 
  └── lib 
      ├── cJScJSON_UtilsON1.h
      ├── cJSON_Utils.c
      ├── cJSON.h
      ├── cJSON.c
      └── CMakeLists.txt

cJSONConfig.h.in

#cmakedefine USE_CJSON

test.c

#include <stdio.h>
#include <stdlib.h>
#ifdef USE_MYMATH
#include "lib/cJSON.h"

void parser(char* text) {
    char *out;
    cJSON *json;

    json = cJSON_Parse(text);
    if (!json) {
        printf("Error before: [%s]\n", cJSON_GetErrorPtr());
    }else {
        out = cJSON_Print(json);
        cJSON_Delete(json);
        printf("%s\n", out);
        free(out);
    }
}

#endif

int main(int argc, char * argv[]) {
    char text[]="[\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"]";
    #ifdef USE_MYMATH
        parser(text);
    #else
        printf("use other json library\n");
    #endif

    return 0;
}

最終效果以下:

以上只是經過一些簡單的示例來講明瞭CMake基礎及相關應用。更多高級功能須要平常的實踐及查詢CMake官方文檔。

技術交流QQ羣:528655025
做者:AlphaGL
出處:http://www.cnblogs.com/alphagl/ 版權全部,歡迎保留原文連接進行轉載 :)

相關文章
相關標籤/搜索