CMakeLists入門學習筆記

0、前言

因爲在使用OPENCV以及caffe的過程中都接觸到了許多關於CMake的使用,於是就想了解一下CMake究竟是怎樣一個東西,有什麼作用。順便做一個學習筆記。
本文參考《CMake Practice》這篇文章完成,旨在指導用戶快速使用CMake,如果需要更詳細的內容,請通讀《CMake Practice》這篇文章。下載路徑:http://sewm.pku.edu.cn/src/paradise/reference/CMake%20Practice.pdf

1、CMake簡介

CMake是一個工程構建工具,能夠自動生產makefile文件,方便構建編譯文件,鏈接庫,安裝文件等。

cmake 的特點主要有:
1,開放源代碼,使用類 BSD 許可發佈。http://cmake.org/HTML/Copyright.html
2,跨平臺,並可生成 native 編譯配置文件,在 Linux/Unix 平臺,生成 makefile,在
蘋果平臺,可以生成 xcode,在 Windows 平臺,可以生成 MSVC 的工程文件。
3,能夠管理大型項目,KDE4 就是最好的證明。
4,簡化編譯構建過程和編譯過程。Cmake 的工具鏈非常簡單:cmake+make。
5,高效慮,按照 KDE 官方說法,CMake 構建 KDE4 的 kdelibs 要比使用 autotools 來
構建 KDE3.5.6 的 kdelibs 快 40%,主要是因爲 Cmake 在工具鏈中沒有 libtool。
6,可擴展,可以爲 cmake 編寫特定功能的模塊,擴充 cmake 功能。

cmake基本語法規則:
前面提到過,cmake 其實仍然要使用”cmake 語言和語法”去構建,上面的內容就是所謂的”cmake 語言和語法”,最簡單的語法規則是:
1,變量使用${}方式取值,但是在 IF 控制語句中是直接使用變量名
2,指令(參數 1 參數 2…)
參數使用括弧括起,參數之間使用空格或分號分開。
3,指令是大小寫無關的,參數和變量是大小寫相關的。但,推薦你全部使用大寫指令。

2、CMakeLists.txt文件分析

每個需要編譯的目錄(子目錄)都要有一個CMakeLists.txt文件
在工程目錄下的CMakeLists.txt文件稱作工程CMake文件,在這個文件裏需要指出工程名字,需要編譯的子目錄,例如:

{
    cmake_minimum_required(VERSION 3.5)

    PROJECT(HELLO)
    ADD_SUBDIRECTORY(src)
}

  • cmake_minimum_required(VERSION 3.5)
    功能說明: 規定cmake程序的最低版本。可選
    • 如果CMakeLists.txt文件中使用了一些高版本cmake特有的一些命令的時候,就需要加上這樣一行,提醒用戶升級到該版本之後再執行cmake

  • PROJECT 指令
    功能說明: 聲明一個工程
    語法: PROJECT(projectname [CXX] [C] [Java])
    參數說明:

    • projectname:定義工程名稱
    • [CXX]…:指定工程支持的語言列表,可忽略的,默認表示支持所有語言

    這個指令隱式的定義了兩個 cmake 變量:
    ==_BINARY_DIR== 以及 ==_SOURCE_DIR==。
    前者表示編譯輸出的路徑;後者表示工程所在的路徑。


  • ADD_SUBDIRECTORY 指令:
    功能說明: 添加需要編譯的源文件的子目錄
    語法: ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
    參數說明:
    • source_dir:向當前工程添加存放源文件的子目錄
    • [binary_dir]:指定中間二進制或目標文件存放的位置
    • [EXCLUDE_FROM_ALL]:將該目錄從編譯過程中排除

接下來給出一個在子目錄的CMakeLists.txt文件

{
    INCLUDE_DIRECTORIES(/usr/include/thrift)
    SET(SRC_LIST main.cc
            rpc/CRMasterCaller.cpp
            rpc/CRNode_server.skeleton.cpp
            rpc/Schd_constants.cpp
            rpc/CRMaster.cpp
            rpc/CRNode.cpp
            rpc/Schd_types.cpp
            task/TaskExecutor.cpp
            task/TaskMoniter.cpp
            util/Const.cpp
            util/Globals.cc
            util/utils.cc
            util/Properties.cpp
            )

    ADD_EXECUTABLE(crnode ${SRC_LIST})
    LINK_DIRECTORIES(/usr/lib /lib/local/lib)
    TARGET_LINK_LIBRARIES(crnode log4cpp thrift)
    MESSAGE(STATUS "This is BINARY dir " ${HELLO_BINARY_DIR})
    MESSAGE(STATUS "This is SOURCE dir " ${HELLO_SOURCE_DIR})

    INSTALL(TARGETS crnode
            RUNTIME DESTINATION bin
    )    
}

注:

  • INCLUDE_DIRECTORIES 指令
    功能說明: 向工程添加多個特定的頭文件搜索路徑
    語法: INCLUDE_DIRECTORIES([AFTER|BEFORE] [SYSTEM] dir1 dir2 …)
    參數說明:
    • [AFTER|BEFORE]:控制路徑添加順序,追加or置前

  • LINK_DIRECTORIES 指令
    功能說明: 添加非標準的共享庫搜索路徑
    語法: LINK_DIRECTORIES(directory1 directory2 …)
    參數說明:
    • directory1:要添加的目錄路徑

  • TARGET_LINK_LIBRARIES 指令
    功能說明: 來爲 target 添加需要鏈接的共享庫
    語法: TARGET_LINK_LIBRARIES(target library1

  • SET 指令
    功能說明: 顯式的定義變量
    語法: SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
    參數說明:
    • VAR:變量名
    • [VALUE]:變量值

  • ADD_EXECUTABLE 指令
    功能說明: 添加要執行的編譯命令
    語法: ADD_EXECUTABLE(target [Value])
    參數說明:
    • target:要編譯輸出目標的名字
    • [Value]:需要的源文件

  • MESSAGE 指令
    功能說明: 於向終端輸出用戶定義的信息
    語法: MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] “message to display” …)
    參數說明:
    • [SEND_ERROR | STATUS | FATAL_ERROR]:產生錯誤,生成過程被跳過 | 輸出前綴爲—的信息 | 立即終止所有 cmake 過程

  • INSTALL 指令
    功能說明: 將編譯生成的文件分類安裝到制定的目錄路徑。可分成好幾類文件的安裝命令

    • 安裝目標文件
      語法:

      {
      INSTALL(TARGETS targets...
              [[ARCHIVE|LIBRARY|RUNTIME]
              [DESTINATION < dir >]
              [PERMISSIONS permissions...]  
              [CONFIGURATIONS
              [Debug|Release|...]]
              [COMPONENT < component >]
              [OPTIONAL]
              ] [...])
      }  
      

      舉例說明:

      {
      INSTALL(TARGETS myrun mylib mystaticlib
              RUNTIME DESTINATION bin
              LIBRARY DESTINATION lib
              ARCHIVE DESTINATION libstatic)
      }
      

      上面的例子會將:
      將:
      1) 可執行二進制文件 myrun, 安裝到${CMAKE_INSTALL_PREFIX}/bin 目錄
      2) 動態庫 libmylib, 安裝到${CMAKE_INSTALL_PREFIX}/lib 目錄
      3) 靜態庫 libmystaticlib, 安裝到${CMAKE_INSTALL_PREFIX}/libstatic 目錄


    • 安裝普通文件
      語法:

      {
      INSTALL(FILES files... DESTINATION <dir>
           [PERMISSIONS permissions...]
           [CONFIGURATIONS [Debug|Release|...]]
           [COMPONENT <component>]
           [RENAME <name>] [OPTIONAL])
      }  
      

      舉例說明:

      {
      INSTALL(FILES COPYRIGHT README DESTINATION share/doc/cmake/t2)
      }
      

      上面的例子會將:
      把文件COPYRIGHT、README, 安裝到目錄 < prefix >/share/doc/cmake/t2下


    • 安裝非目標文件的可執行程序文件(腳本文件)
      語法:

      {
      INSTALL(PROGRAMS files... DESTINATION <dir>
           [PERMISSIONS permissions...]
           [CONFIGURATIONS [Debug|Release|...]]
           [COMPONENT <component>]
           [RENAME <name>] [OPTIONAL])
      }  
      

      舉例說明:

      {
      INSTALL(PROGRAMS runhello.sh DESTINATION bin)
      }
      

      上面的例子會將:
      把可執行文件runhello.sh, 安裝到目錄< prefix >/bin下


    • 安裝目錄
      語法:

      {
      INSTALL(DIRECTORY dirs... DESTINATION <dir>
           [FILE_PERMISSIONS permissions...]
           [DIRECTORY_PERMISSIONS permissions...]
           [USE_SOURCE_PERMISSIONS]
           [CONFIGURATIONS [Debug|Release|...]]
           [COMPONENT <component>]
           [[PATTERN <pattern> | REGEX <regex>]
           [EXCLUDE] [PERMISSIONS permissions...]] [...]) 
      }
      

      舉例說明:

      {
      INSTALL(DIRECTORY icons scripts/ DESTINATION share/myproj
           PATTERN "CVS" EXCLUDE
           PATTERN "scripts/*"
           PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ
           GROUP_EXECUTE GROUP_READ)
      }
      

      上面的例子會:
      將 icons 目錄安裝到 < prefix >/share/myproj
      將 scripts/中的內容安裝到/share/myproj
      不包含目錄名爲 CVS 的目錄
      對於 scripts/*文件指定權限爲 OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ


3、內部編譯與外部編譯

假設我們此時已經完成了兩個CMakeLists.txt文件的編寫,可以執行cmake命令生成Makefile文件了。此時我們由兩種方法可以執行cmake、編譯和安裝:

cmake .
make   

或者

mkdir build
cd build
cmake ..
make  

兩種方法最大的不同在於執行cmake和make的工作路徑不同。
第一種方法中,cmake生成的所有中間文件和可執行文件都會存放在項目目錄中,稱爲“內部構建”
而第二種方法中,中間文件和可執行文件都將存放再build目錄中。稱爲“外部構建”。
cmake強烈推薦使用外部構建的方法。

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