1. 程式人生 > >Linux——cmake使用示例與整理總結

Linux——cmake使用示例與整理總結

轉自:http://blog.csdn.net/wzzfeitian/article/details/40963457/

cmake中一些預定義變數

  • PROJECT_SOURCE_DIR 工程的根目錄
  • PROJECT_BINARY_DIR 執行cmake命令的目錄,通常是${PROJECT_SOURCE_DIR}/build
  • CMAKE_INCLUDE_PATH 環境變數,非cmake變數
  • CMAKE_LIBRARY_PATH 環境變數
  • CMAKE_CURRENT_SOURCE_DIR 當前處理的CMakeLists.txt所在的路徑
  • CMAKE_CURRENT_BINARY_DIR target編譯目錄
    使用ADD_SURDIRECTORY(src bin)可以更改此變數的值
    SET(EXECUTABLE_OUTPUT_PATH <新路徑>)並不會對此變數有影響,只是改變了最終目標檔案的儲存路徑
  • CMAKE_CURRENT_LIST_FILE 輸出呼叫這個變數的CMakeLists.txt的完整路徑
  • CMAKE_CURRENT_LIST_LINE 輸出這個變數所在的行
  • CMAKE_MODULE_PATH 定義自己的cmake模組所在的路徑
    SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake),然後可以用INCLUDE命令來呼叫自己的模組
  • EXECUTABLE_OUTPUT_PATH 重新定義目標二進位制可執行檔案的存放位置
  • LIBRARY_OUTPUT_PATH 重新定義目標連結庫檔案的存放位置
  • PROJECT_NAME 返回通過PROJECT指令定義的專案名稱
  • CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS 用來控制IF ELSE語句的書寫方式

系統資訊

  • CMAKE_MAJOR_VERSION cmake主版本號,如2.8.6中的2
  • CMAKE_MINOR_VERSION cmake次版本號,如2.8.6中的8
  • CMAKE_PATCH_VERSION cmake補丁等級,如2.8.6中的6
  • CMAKE_SYSTEM 系統名稱,例如Linux-2.6.22
  • CAMKE_SYSTEM_NAME 不包含版本的系統名,如Linux
  • CMAKE_SYSTEM_VERSION 系統版本,如2.6.22
  • CMAKE_SYSTEM_PROCESSOR 處理器名稱,如i686
  • UNIX 在所有的類UNIX平臺為TRUE,包括OS X和cygwin
  • WIN32 在所有的win32平臺為TRUE,包括cygwin

開關選項

  • BUILD_SHARED_LIBS 控制預設的庫編譯方式。如果未進行設定,使用ADD_LIBRARY時又沒有指定庫型別,預設編譯生成的庫都是靜態庫 (可在t3中稍加修改進行驗證)
  • CMAKE_C_FLAGS 設定C編譯選項
  • CMAKE_CXX_FLAGS 設定C++編譯選項

cmake常用命令

基本語法規則:
  • cmake變數使用`${}`方式取值,但是在IF控制語句中是直接使用變數名
  • 環境變數使用$ENV{}方式取值,使用SET(ENV{VAR} VALUE)賦值
  • 指令(引數1 引數2…)
    引數使用括弧括起,引數之間使用空格或分號分開。

    以ADD_EXECUTABLE指令為例:
    ADD_EXECUTABLE(hello main.c func.c)或者
    ADD_EXECUTABLE(hello main.c;func.c)
    
  • 指令是大小寫無關的,引數和變數是大小寫相關的。推薦你全部使用大寫指令。

部分常用命令列表:
  • PROJECT
    PROJECT(projectname [CXX] [C] [Java])
    指定工程名稱,並可指定工程支援的語言。支援語言列表可忽略,預設支援所有語言
  • SET
    SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
    定義變數(可以定義多個VALUE,如SET(SRC_LIST main.c util.c reactor.c))
  • MESSAGE
    MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] “message to display” …)
    向終端輸出使用者定義的資訊或變數的值
    SEND_ERROR, 產生錯誤,生成過程被跳過
    STATUS, 輸出字首為—的資訊
    FATAL_ERROR, 立即終止所有cmake過程
  • ADD_EXECUTABLE
    ADD_EXECUTABLE(bin_file_name ${SRC_LIST})
    生成可執行檔案
  • ADD_LIBRARY
    ADD_LIBRARY(libname [SHARED | STATIC | MODULE] [EXCLUDE_FROM_ALL] SRC_LIST)
    生成動態庫或靜態庫
    SHARED 動態庫
    STATIC 靜態庫
    MODULE 在使用dyld的系統有效,若不支援dyld,等同於SHARED
    EXCLUDE_FROM_ALL 表示該庫不會被預設構建
  • SET_TARGET_PROPERTIES
    設定輸出的名稱,設定動態庫的版本和API版本
  • CMAKE_MINIMUM_REQUIRED
    CMAKE_MINIMUM_REQUIRED(VERSION version_number [FATAL_ERROR])
    宣告CMake的版本要求
  • ADD_SUBDIRECTORY
    ADD_SUBDIRECTORY(src_dir [binary_dir] [EXCLUDE_FROM_ALL])
    向當前工程新增存放原始檔的子目錄,並可以指定中間二進位制和目標二進位制的存放位置
    EXCLUDE_FROM_ALL含義:將這個目錄從編譯過程中排除
  • SUBDIRS
    deprecated,不再推薦使用
    (hello sample)相當於分別寫ADD_SUBDIRECTORY(hello),ADD_SUBDIRECTORY(sample)
  • INCLUDE_DIRECTORIES
    INCLUDE_DIRECTORIES([AFTER | BEFORE] [SYSTEM] dir1 dir2 … )
    向工程新增多個特定的標頭檔案搜尋路徑,路徑之間用空格分隔,如果路徑包含空格,可以使用雙引號將它括起來,預設的行為為追加到當前標頭檔案搜尋路徑的後面。有如下兩種方式可以控制搜尋路徑新增的位置:
    • CMAKE_INCLUDE_DIRECTORIES_BEFORE,通過SET這個cmake變數為on,可以將新增的標頭檔案搜尋路徑放在已有路徑的前面
    • 通過AFTER或BEFORE引數,也可以控制是追加還是置前
  • LINK_DIRECTORIES
    LINK_DIRECTORIES(dir1 dir2 …)
    新增非標準的共享庫搜尋路徑
  • TARGET_LINK_LIBRARIES
    TARGET_LINK_LIBRARIES(target lib1 lib2 …)
    為target新增需要連結的共享庫
  • ADD_DEFINITIONS
    向C/C++編譯器新增-D定義
    ADD_DEFINITIONS(-DENABLE_DEBUG -DABC),引數之間用空格分隔
  • ADD_DEPENDENCIES
    ADD_DEPENDENCIES(target-name depend-target1 depend-target2 …)
    定義target依賴的其他target,確保target在構建之前,其依賴的target已經構建完畢
  • AUX_SOURCE_DIRECTORY
    AUX_SOURCE_DIRECTORY(dir VAR)
    發現一個目錄下所有的原始碼檔案並將列表儲存在一個變數中
    把當前目錄下的所有原始碼檔名賦給變數DIR_HELLO_SRCS
  • EXEC_PROGRAM
    EXEC_PROGRAM(Executable [dir where to run] [ARGS <args>][OUTPUT_VARIABLE <var>] [RETURN_VALUE <value>])
    用於在指定目錄執行某個程式(預設為當前CMakeLists.txt所在目錄),通過ARGS新增引數,通過OUTPUT_VARIABLE和RETURN_VALUE獲取輸出和返回值,如下示例

    # 在src中執行ls命令,在src/CMakeLists.txt新增
    EXEC_PROGRAM(ls ARGS "*.c" OUTPUT_VARIABLE LS_OUTPUT RETURN_VALUE LS_RVALUE)
    IF (not LS_RVALUE)
        MESSAGE(STATUS "ls result: " ${LS_OUTPUT}) # 縮排僅為美觀,語法無要求
    ENDIF(not LS_RVALUE)
    
  • INCLUDE
    INCLUDE(file [OPTIONAL]) 用來載入CMakeLists.txt檔案
    INCLUDE(module [OPTIONAL])用來載入預定義的cmake模組
    OPTIONAL引數的左右是檔案不存在也不會產生錯誤
    可以載入一個檔案,也可以載入預定義模組(模組會在CMAKE_MODULE_PATH指定的路徑進行搜尋)
    載入的內容將在處理到INCLUDE語句時直接執行

  • FIND_

    • FIND_FILE(<VAR> name path1 path2 …)
      VAR變數代表找到的檔案全路徑,包含檔名
    • FIND_LIBRARY(<VAR> name path1 path2 …)
      VAR變數代表找到的庫全路徑,包含庫檔名

      FIND_LIBRARY(libX X11 /usr/lib)
      IF (NOT libx)
          MESSAGE(FATAL_ERROR "libX not found")
      ENDIF(NOT libX)
      
    • FIND_PATH(<VAR> name path1 path2 …)
      VAR變數代表包含這個檔案的路徑

    • FIND_PROGRAM(<VAR> name path1 path2 …)
      VAR變數代表包含這個程式的全路徑
    • FIND_PACKAGE(<name> [major.minor] [QUIET] [NO_MODULE] [[REQUIRED | COMPONENTS] [componets …]])
      用來呼叫預定義在CMAKE_MODULE_PATH下的Find<name>.cmake模組,你也可以自己定義Find<name>
      模組,通過SET(CMAKE_MODULE_PATH dir)將其放入工程的某個目錄供工程使用
  • IF
    語法:

    IF (expression)
        COMMAND1(ARGS ...)
        COMMAND2(ARGS ...)
        ...
    ELSE (expression)
        COMMAND1(ARGS ...)
        COMMAND2(ARGS ...)
        ...
    ENDIF (expression) # 一定要有ENDIF與IF對應

    IF (expression), expression不為:空,0,N,NO,OFF,FALSE,NOTFOUND或<var>_NOTFOUND,為真
    IF (not exp), 與上面相反
    IF (var1 AND var2)
    IF (var1 OR var2)
    IF (COMMAND cmd) 如果cmd確實是命令並可呼叫,為真
    IF (EXISTS dir) IF (EXISTS file) 如果目錄或檔案存在,為真
    IF (file1 IS_NEWER_THAN file2),當file1比file2新,或file1/file2中有一個不存在時為真,檔名需使用全路徑
    IF (IS_DIRECTORY dir) 當dir是目錄時,為真
    IF (DEFINED var) 如果變數被定義,為真
    IF (var MATCHES regex) 此處var可以用var名,也可以用${var}
    IF (string MATCHES regex)

    當給定的變數或者字串能夠匹配正則表示式regex時為真。比如:
    IF ("hello" MATCHES "ell")
        MESSAGE("true")
    ENDIF ("hello" MATCHES "ell")
    

    數字比較表示式
    IF (variable LESS number)
    IF (string LESS number)
    IF (variable GREATER number)
    IF (string GREATER number)
    IF (variable EQUAL number)
    IF (string EQUAL number)

    按照字母表順序進行比較
    IF (variable STRLESS string)
    IF (string STRLESS string)
    IF (variable STRGREATER string)
    IF (string STRGREATER string)
    IF (variable STREQUAL string)
    IF (string STREQUAL string)

    一個小例子,用來判斷平臺差異:
    IF (WIN32)
        MESSAGE(STATUS “This is windows.”)
    ELSE (WIN32)
        MESSAGE(STATUS “This is not windows”)
    ENDIF (WIN32)
    上述程式碼用來控制在不同的平臺進行不同的控制,但是,閱讀起來卻並不是那麼舒服,ELSE(WIN32)之類的語句很容易引起歧義。
    可以SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON)
    這時候就可以寫成:
    IF (WIN32)
    ELSE ()
    ENDIF ()
    配合ELSEIF使用,可能的寫法是這樣:
    IF (WIN32)
        #do something related to WIN32
    ELSEIF (UNIX)
        #do something related to UNIX
    ELSEIF(APPLE)
        #do something related to APPLE
    ENDIF (WIN32)
    
  • WHILE
    語法:

    WHILE(condition)
        COMMAND1(ARGS ...)
        COMMAND2(ARGS ...)
        ...
    ENDWHILE(condition)
    

    其真假判斷條件可以參考IF指令

  • FOREACH
    FOREACH指令的使用方法有三種形式:
    1. 列表
      語法:
      FOREACH(loop_var arg1 arg2 ...)
           COMMAND1(ARGS ...)
           COMMAND2(ARGS ...)
       ...
      ENDFOREACH(loop_var)
      
      示例:
      AUX_SOURCE_DIRECTORY(. SRC_LIST)
      FOREACH(F ${SRC_LIST})
           MESSAGE(${F})
      ENDFOREACH(F)
      
    2. 範圍
      語法:
      FOREACH(loop_var RANGE total)
          COMMAND1(ARGS ...)
          COMMAND2(ARGS ...)
          ...
      ENDFOREACH(loop_var)
      
      示例:
      0到total以1為步進
      FOREACH(VAR RANGE 10)
         MESSAGE(${VAR})
      ENDFOREACH(VAR)
      輸出:
      012345678910
    3. 範圍和步進
      語法:
      FOREACH(loop_var RANGE start stop [step])
          COMMAND1(ARGS ...)
          COMMAND2(ARGS ...)
          ...
      ENDFOREACH(loop_var)
      
      從start開始到stop結束,以step為步進,
      注意:直到遇到ENDFOREACH指令,整個語句塊才會得到真正的執行。
      FOREACH(A RANGE 5 15 3)
          MESSAGE(${A})
      ENDFOREACH(A)
      輸出:
      581114

cmake中如何生成動態庫和靜態庫

參考ADD_LIBRARY和SET_TARGET_PROPERTIES用法
t3示例

cmake中如何使用動態庫和靜態庫(查詢庫的路徑)

參考INCLUDE_DIRECTORIES, LINK_DIRECTORIES, TARGET_LINK_LIBRARIES用法
t4示例使用動態庫或靜態庫
t5示例如何使用cmake預定義的cmake模組(以FindCURL.cmake為例演示)
t6示例如何使用自定義的cmake模組(編寫了自定義的FindHELLO.cmake)
注意讀t5和t6的CMakeLists.txt和FindHELLO.cmake中的註釋部分

cmake中如何指定生成檔案的輸出路徑

  • 如上ADD_SUBDIRECTORY的時候指定目標二進位制檔案輸出路徑(推薦使用下面這種)
  • 使用SET命令重新定義EXECUTABLE_OUTPUT_PATH和LIBRARY_OUTPUT_PATH變數來指定最終的二進位制檔案的位置
    SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
    SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
    
    上面的兩條命令通常緊跟ADD_EXECUTABLE和ADD_LIBRARY,與其寫在同一個CMakeLists.txt即可

cmake中如何增加編譯選項

使用變數CMAKE_C_FLAGS新增C編譯選項
使用變數CMAKE_CXX_FLAGS新增C++編譯選項
使用ADD_DEFINITION新增

cmake中如何增加標頭檔案路徑

參考INCLUDE_DIRECTORIES命令用法

cmake中如何在螢幕上列印資訊

參考MESSAGE用法

cmake中如何給變數賦值

參考SET和AUX_SOURCE_DIRECTORY用法

建議:在Project根目錄先建立build,然後在build資料夾內執行cmake ..,這樣就不會汙染原始碼, 如果不想要這些自動生成的檔案了,只要簡單的刪除build資料夾就可以