作者:AlphaGL。
本文目錄如下:
CMake全稱為“cross platform make”,是一個開源的跨平臺自動化構(gòu)建系統(tǒng)。使用指定名為CMakeLists.txt
的配置文件可以控制軟件的構(gòu)建、測試和打包等流程。同時,通過編寫平臺無關的CMakeLists.txt
文件和需要簡單的配置,CMake就能生成對應目標平臺的構(gòu)建文件,例如:類Unix系統(tǒng)的makefile文件、Windows的Visual Studio工程或者Mac的Xcode工程,大大簡化了跨平臺和交叉編譯方面的工作。
當然,類似的make工具也很多,Autocof
、JAM
、QMake
、SCons
甚至ANT
,目的都是指定一套規(guī)則來簡化整個構(gòu)建編譯流程。CMake工具鏈簡單、靈活,且跨平臺,很多知名項目都在使用CMake構(gòu)建。適合以C、C++或者java等編譯語言的項目。
CMake下載地址為:
https://cmake.org/download/
CMake的安裝過程很簡單,這里就不再贅述了。其中CMake提供帶GUI界面的工具cmake-gui
。本文主要是以命令行的形式來講述CMake的使用,這里就稍微提一下cmake-gui的使用。原理都是差不多的。
簡述操作步驟如下:
1、在本地目錄新建cmake文件夾(例如:我的目錄為E:\workplace\cmake
),并在cmake目錄中創(chuàng)建bin目錄用于存放構(gòu)建過程中產(chǎn)生的臨時文件和目標文件(例如:我的目錄為E:\workplace\cmake\bin
)。
2、在cmake目錄中新建hello_cmake.c
與CMakeLists.txt
文件,內(nèi)容如下:
hello_cmake.c:
#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)
3、運行cmake-gui,會打開如下界面:
(1)源碼所在的路徑,即CMakeLists.txt
所在的路徑。本例為E:\workplace\cmake
(2)構(gòu)建過程中產(chǎn)生的文件的路徑。本例為:E:\workplace\cmake\bin
,注意這個路徑可以與(1)路徑相同,但若項目很大產(chǎn)生的文件很多要執(zhí)行清理等操作時會比較麻煩。
(3)執(zhí)行configure。
*.sln
的項目文件。在Visual Studio中打開該項目,并執(zhí)行??梢钥吹秸_輸出了"Hello CMake"。
這里,依然使用剛才的示例來說明下CMake命令行的方式的使用(清理bin目錄下的文件即可),使用步驟如下:
(1)將CMake安裝路徑添加到Path環(huán)境變量中。Mac版本可以終端中輸入命令:export PATH=/Applications/CMake.app/Contents/bin:$PATH
即可。
(2)在Windows命令行中執(zhí)行如下命令:
CMakeLists.txt
所在路徑,-G用來指定構(gòu)建生成目標平臺的項目工程。分別對應上面的GUI的操作。(3)在類Unix的操作系統(tǒng)中,可以執(zhí)行如下操作。這里我還是用的上面的示例代碼,我用Cygwin模擬下對應的cmake操作,如圖:
由此可見,在Unix系列的操作系統(tǒng)上,使用CMake步驟分為:
cmake
命令生成makefile
文件。make
命令編譯執(zhí)行,生成最終的目標文件。CMake命令行的選項可以在命令行終端上,輸入cmake --help
查看。更詳盡的解釋可以查看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-source
和path-to-existing-build
二選一,分別表示一個CMakeLists.txt
所在的路徑和一個已存在的構(gòu)建工程所在的路徑。例如:
cmake .
這里option為空,構(gòu)建的路徑為用戶所在的當前路徑。
其中option常用的有:-G <generator-name>
:
指定構(gòu)建系統(tǒng)生成器,當前平臺所支持的generator-name
可以通過幫助手冊查看。例如: cmake -G "Visual Studio 11 2012" E:\workplace\cmake
,生成VS2012的構(gòu)建工程。
-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
:
以向?qū)У姆绞竭\行CMake。此選項會彈出一系列的提示,要求用戶回答關于工程配置的一些問題。這些結(jié)果會被用來設置cmake的緩存值。注意,新版的CMake可能不再支持此選項。
-E
:
CMake命令行模式。CMake提供了一系列與平臺無關的命令。例如:copy
,make_directory
,echo
等,更多詳細參見cmake -E help
。
用CMake構(gòu)建一個項目工程,是通過一個或多個CMakeLists.txt文件來控制的。CMakeLists.txt中包含一系列命令來描述需要執(zhí)行的構(gòu)建。
在CMakeLists.txt中的命令的語法,都是形如下面這種格式:
command (args...)
command:是命令的名字。
args:是參數(shù)的列表。多個參數(shù)使用空格隔開。
cmake_minimum_required:
設置項目要求的CMake最低版本號,如果當前版本的CMake低于所需的值,它將停止處理項目并報告錯誤。注意在project
之前調(diào)用該命令,一般在CMakeLists.txt文件開頭調(diào)用。命令格式為:
cmake_minimum_required(VERSION major.minor[.patch[.tweak]] [FATAL_ERROR])
使用示例:
cmake_minimum_required(VERSION 2.8.5)
add_custom_command:
該命令可以為生成的構(gòu)建系統(tǒng)添加一條自定義的構(gòu)建規(guī)則。這里又包含兩種使用方式,一種是通過自定義命令在構(gòu)建中生成輸出文件,另外一種是向構(gòu)建目標添加自定義命令。命令格式分別為:
(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])
參數(shù)介紹:
OUTPUT:
指定命令預期產(chǎn)生的輸出文件。如果輸出文件的名稱是相對路徑,即相對于當前的構(gòu)建的源目錄路徑。輸出文件可以指定多個output1,output2(可選)等。
COMMAND:
指定要在構(gòu)建時執(zhí)行的命令行。如果指定多個COMMAND,它們講按順心執(zhí)行。ARGS
參數(shù)是為了向后兼容,為可選參數(shù)。args1和args2為參數(shù),多個參數(shù)用空格隔開。
MAIN_DEPENDENCY:
可選命令,指定命令的主要輸入源文件。
DEPENDS:
指定命令所依賴的文件。
BYPRODUCTS:
可選命令,指定命令預期產(chǎn)生的文件,但其修改時間可能會比依賴性更新,也可能不會更新。
IMPLICIT_DEPENDS:
可選命令,請求掃描輸入文件的隱式依賴關系。給定的語言指定應使用相應的依賴性掃描器的編程語言。目前只支持C和CXX語言掃描器。必須為IMPLICIT_DEPENDS列表中的每個文件指定語言。從掃描中發(fā)現(xiàn)的依賴關系在構(gòu)建時添加到自定義命令的依賴關系。請注意,IMPLICIT_DEPENDS選項目前僅支持Makefile生成器,并且將被其他生成器忽略。
WORKING_DIRECTORY:
可選命令,使用給定的當前工作目錄執(zhí)行命令。如果它是相對路徑,它將相對于對應于當前源目錄的構(gòu)建樹目錄。
COMMENT:
可選命令,在構(gòu)建時執(zhí)行命令之前顯示給定消息。
DEPFILE:
可選命令,為Ninja生成器指定一個.d
depfile。 .d
文件保存通常由自定義命令本身發(fā)出的依賴關系。對其他生成器使用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)自定義構(gòu)建事件
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])
參數(shù)介紹:
TARGET:
定義了與構(gòu)建指定
PRE_BUILD:
在目標中執(zhí)行任何其他規(guī)則之前運行。這僅在Visual Studio 7或更高版本上受支持。對于所有其他生成器PRE_BUILD將被視為PRE_LINK。
PRE_LINK:
在編譯源之后運行,但在鏈接二進制文件或運行靜態(tài)庫的庫管理器或存檔器工具之前運行。
POST_BUILD:
在目標中的所有其他規(guī)則都已執(zhí)行后運行。
使用實例:
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:
該命令可以給指定名稱的目標執(zhí)行指定的命令,該目標沒有輸出文件,并始終被構(gòu)建。命令的格式為:
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...]])
參數(shù)介紹(上面介紹過含義相同的參數(shù),這里就不再贅述了):
Name:
指定目標的名稱。
ALL:
表明此目標應添加到默認構(gòu)建目標,以便每次都將運行(該命令名稱不能為ALL)
SOURCES:
指定要包括在自定義目標中的其他源文件。指定的源文件將被添加到IDE項目文件中,以方便編輯,即使它們沒有構(gòu)建規(guī)則。
使用示例:
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:
使頂級目標依賴于其他頂級目標,以確保它們在該目標之前構(gòu)建。這里的頂級目標是由add_executable
,add_library
或add_custom_target
命令之一創(chuàng)建的目標。
使用示例:
add_custom_target(mylib DEPENDS ${MYLIB})add_executable(${APP_NAME} ${SRC_LIST})add_dependencies(${APP_NAME} mylib)
add_executable:
使用指定的源文件給項目添加一個可執(zhí)行文件。命令格式為:
add_executable(<name> [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] source1 [source2 ...])
參數(shù)介紹:
name:
該命令調(diào)用列出的源文件來構(gòu)建的可執(zhí)行目標
WIN32:
如果給出WIN32,則在創(chuàng)建的目標上設置屬性WIN32_EXECUTABLE。
MACOSX_BUNDLE:
如果給定MACOSX_BUNDLE,將在創(chuàng)建的目標上設置相應的屬性。
EXCLUDE_FROM_ALL:
如果給定EXCLUDE_FROM_ALL,將在創(chuàng)建的目標上設置相應的屬性。
source:
源碼列表。
使用示例:
add_executable(HelloCMake hello_cmake.c)
add_library:
使用指定的源文件給項目添加一個庫。命令格式為:
add_library(<name> [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] source1 [source2 ...])
參數(shù)介紹:
name:
該命令調(diào)用列出的源文件來構(gòu)建的庫目標
STATIC:
靜態(tài)庫,在鏈接其他目標時使用。
SHARED:
動態(tài)鏈接庫,運行時加載。
MODULE:
不會被鏈接到其它目標中,但是可能會在運行時使用dlopen-系列的函數(shù)動態(tài)鏈接。
使用示例:
add_library(HelloCMake hello_cmake.c)
add_subdirectory:
向構(gòu)建中添加子目錄。命令格式為:
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:
將文件復制到其他位置并修改其內(nèi)容。命令格式為:
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:
指定鏈接器查找?guī)斓穆窂?。命令格式為?/p>
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" ...)
參數(shù)說明:
mode:
可選的值為none,STATUS,WARNING,AUTHOR_WARNING,SEND_ERROR,F(xiàn)ATAL_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:
設置目標的一些屬性來改變它們構(gòu)建的方式。命令格式為:
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)
使用${}進行變量的引用。例如:message(${Hello_VERSION}),Hello為工程名。CMake提供了很多有用的變量。以下僅列舉常用的變量:
CMAKE_BINARY_DIR
:
構(gòu)建樹的頂層路徑
CMAKE_COMMAND
:
指向CMake可執(zhí)行文件的完整路徑
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
:
指向當前編譯工程構(gòu)建的全路徑。
<PROJECT-NAME>_BINARY_DIR
:
指向當前編譯工程構(gòu)建的全路徑。
<PROJECT-NAME>_SOURCE_DIR
:
指向構(gòu)建工程的全路徑。
PROJECT_SOURCE_DIR
:
指向構(gòu)建工程的全路徑。
PROJECT_NAME
:
project命令傳遞的工程名參數(shù)。
<PROJECT-NAME>_VERSION
:
項目的完整版本號。
有了上面的基礎,再編寫CMakeLists.txt自然會事半功倍。下面,以幾個小實例來說下通過CMakeLists.txt的來構(gòu)建項目。
這里cJSON庫為例來說明下CMakeLists.txt的寫法。當然,這里的代碼并嚴謹,僅用來演示CMakeList的用法。
(1)在本地建立cJSONdemo1的目錄工程,并將cJSON庫源代碼拷貝到目錄中,并在該目錄新建CMakeLists.txt
文件。目錄結(jié)構(gòu)如下:
cJSONdemo1 ├── cJSON_Utils.h ├── cJSON_Utils.c ├── cJSON.h├── cJSON.c└── CMakeLists.txt
CMakeLists.txt文件內(nèi)容如下:
cmake_minimum_required(VERSION 2.8.5)project(cJSON-lib)set(CJSON_SRC cJSON.c cJSON_Utils.c)add_library(cjson STATIC ${CJSON_SRC})
在終端下執(zhí)行如下操作:
(2)自動搜索目錄源碼
在上面cJSONdemo1的基礎上做一些改進。前面提過set(<variable> <value>...)
,可以預見在cJSON庫源碼越來越多的情況下,會變成這樣:
set(CJSON_SRC cJSON.c cJSON1.c cJSON2.c cJSON3.c cJSON4.c cJSON5.c)
這樣,源文件越多,需要添加次數(shù)就越多。而且,每增加一個源文件就需要修改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)指定構(gòu)建庫的名字,路徑和前綴。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
。通過上面過程了解了將cJSON庫構(gòu)建文件靜態(tài)庫的過程。下面,再添加測試代碼來調(diào)用cJSON庫,并最終構(gòu)建為可執(zhí)行文件。目錄如下:
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})
在終端下執(zhí)行如下操作:
在上面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); }}#endifint 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;}
最終效果如下: