主頁 > 軟體設計 > Linux下的工程管理——CMake學習指南,手把手教你入門【建議新手收藏】

Linux下的工程管理——CMake學習指南,手把手教你入門【建議新手收藏】

2020-12-30 12:06:12 軟體設計

一、CMake介紹

CMake是一個比make更高級的編譯配置工具,它可以根據不同平臺、不同的編譯器,生成相應的Makefile或者vcproj專案,通過撰寫CMakeLists.txt,可以控制生成的Makefile,從而控制編譯程序,CMake自動生成的Makefile不僅可以通過make命令構建專案生成目標檔案,還支持安裝(make install)、測驗安裝的程式是否能正確執行(make test,或者ctest)、生成當前平臺的安裝包(make package)、生成原始碼包(make package_source)、產生Dashboard顯示資料并上傳等高級功能,只要在CMakeLists.txt中簡單配置,就可以完成很多復雜的功能,包括寫測驗用例,如果有嵌套目錄,子目錄下可以有自己的CMakeLists.txt,總之,CMake是一個非常強大的編譯自動配置工具,支持各種平臺,KDE也是用它編譯的,感興趣的可以試用一下,

當然,類似的make工具也很多,Autocof、JAM、QMake、SCons甚至ANT,目的都是指定一套規則來簡化整個構建編譯流程,CMake工具鏈簡單、靈活,且跨平臺,很多知名專案都在使用CMake構建,適合以C、C++或者java等編譯語言的專案,

在這里插入圖片描述

二、CMake安裝與使用

2.1 CMake的安裝

CMake下載地址為:https://cmake.org/download/

2.2 CMake-gui的使用

CMake的安裝程序很簡單,這里就不再贅述了,其中CMake提供帶GUI界面的工具cmake-gui,本文主要是以命令列的形式來講述CMake的使用,這里就稍微提一下cmake-gui的使用,原理都是差不多的,

簡述操作步驟如下:

  1. 在本地目錄新建cmake檔案夾(例如:我的目錄為E:\workplace\cmake),并在cmake目錄中創建bin目錄用于存放構建程序中產生的臨時檔案和目標檔案(例如:我的目錄為E:\workplace\cmake\bin),
  2. 在cmake目錄中新建hello_cmake.c與CMakeLists.txt檔案,內容如下:

hello_cmake.c:

#include <stdio.h>

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

CMakeLists.txt:

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

3、運行cmake-gui,會打開如下界面:

  • (1)原始碼所在的路徑,即CMakeLists.txt所在的路徑,本例為E:\workplace\cmake
  • (2)構建程序中產生的檔案的路徑,本例為:E:\workplace\cmake\bin,注意這個路徑可以與(1)路徑相同,但若專案很大產生的檔案很多要執行清理等操作時會比較麻煩,
  • (3)執行configure,這里指定生成的構建工程為VS2012的專案工程,點擊Finish即可自動編譯,并生成對應的
    *.sln的專案檔案,在Visual Studio中打開該專案,并執行,可以看到正確輸出了"Hello CMake",

為了答謝大家關注和支持,這次給大家準備了限時領取福利:阿里面試題、百度面試題、滴滴面試題、華為面試題、京東面試題、美團面試題、騰訊面試題、頭條面試題、中興面試題,

在這里插入圖片描述
還等什么小編推薦自己的linuxC/C++語言交流群:【1106675687】整理了一些個人覺得比較好的學習書籍、視頻資料共享在群檔案里面,有需要的可以自行添加哦!前100名進群領取,額外贈送一份價值199的C/C++、linux資料包含(視頻教程、電子書、實戰專案及代碼),下面部分展示,
在這里插入圖片描述
在這里插入圖片描述

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命令列格式為:

(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所在的路徑和一個已存在的構建工程所在的路徑,例如:

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提供了一系列與平臺無關的命令,例如:copy,make_directory,echo等,更多詳細參見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]

引數介紹:
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_executable,add_library或add_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 常用的變數

使用 進 行 變 量 的 引 用 , 例 如 : m e s s a g e ( {}進行變數的參考,例如:message( message({Hello_VERSION}),Hello為工程名,CMake提供了很多有用的變數,

以下僅列舉常用的變數:

  1. CMAKE_BINARY_DIR:構建樹的頂層路徑
  2. CMAKE_COMMAND:指向CMake可執行檔案的完整路徑
  3. CMAKE_CURRENT_BINARY_DIR:當前正在被處理的二進制目錄的路徑,
  4. CMAKE_CURRENT_SOURCE_DIR:指向正在被處理的原始碼目錄的路徑,
  5. CMAKE_HOME_DIRECTORY:指向原始碼樹頂層的路徑,
  6. CMAKE_PROJECT_NAME:當前工程的工程名,
  7. CMAKE_ROOT:CMake的安裝路徑,
  8. CMAKE_SOURCE_DIR:原始碼樹的頂層路徑,
  9. CMAKE_VERSION:cmake的完整版本號,
  10. PROJECT_BINARY_DIR:指向當前編譯工程構建的全路徑,
  11. _BINARY_DIR:指向當前編譯工程構建的全路徑,
  12. _SOURCE_DIR:指向構建工程的全路徑,
  13. PROJECT_SOURCE_DIR:指向構建工程的全路徑,
  14. PROJECT_NAME:project命令傳遞的工程名引數,
  15. _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( …),可以預見在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 "")

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官方檔案,

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/242420.html

標籤:其他

上一篇:孫叫獸重磅推薦Chrome插件——CSDN瀏覽器助手

下一篇:Python爬取全網文字并詞云分析(全程一鍵化!)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more