【CMake】掌握CMake基本操作

UnderTurrets發表於2024-08-15

@

目錄
  • 1.檔案樹和CMakeLists.txt一覽
    • 1.1 語法基本規則
    • 1.2 檔案目錄講解
  • 2.基本指令講解
    • 2.1 CMAKE_MINIMUM_REQUIRED(VERSION XXX)
    • 2.2 PROJECT(projectname)
    • 2.3 SET()
    • 2.4 ADD_SUBDIRECTORY(src bin)
    • 2.5 INCLUDE_DIRECTORIES(lib/)
    • 2.6 ADD_EXECUTABLE(main main.cpp)
    • 2.7 ADD_LIBRARY(引數一 引數二(STATIC/SHARED) 引數二)
    • 2.8 TARGET_LINK_LIBRARIES(引數一;引數二)
    • 2.9 FIND_PACKAGE()
  • 3.構建和安裝同名靜態庫和動態庫
    • 3.1 靜態庫和動態庫的區別
    • 3.2 構建指令
      • 3.2.1 ADD_LIBRARY
      • 3.2.2 SET_TARGET_PROPERTIES
    • 3.3 安裝指令
      • 3.3.1 INSTALL()
      • 3.3.2 安裝檔案型別與關鍵字對應關係


1.檔案樹和CMakeLists.txt一覽

  • 檔案樹
xu736946693@ubuntu:~/Desktop/CMake-template$ tree  -L 3
.
├── cmake
│   ├── ProjectXXConfig.cmake.in
│   └── ProjectXXConfigVersion.cmake.in
├── CMakeLists.txt
├── doc
│   └── READMEimgRes
│       └── 8836961877de48e1ada55af7810b1457.png
├── lib
│   ├── authority.h
│   ├── Module1
│   │   ├── filename.cpp
│   │   └── filename.h
│   └── projectname.h
├── LICENSE
├── main.cpp
├── README.md
├── run.sh
└── settings.zip
  • CMakeLists.txt
cmake_minimum_required(VERSION 3.16)

set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 17)
# 設定庫的名稱
set(LIB_NAME ProjectXX)
# 設定可執行檔案的名字
PROJECT(${LIB_NAME}_exe)
#設定版本
set(version 1.0)
# 拼接名字
set(LIB_NAME_VERSION ${LIB_NAME}-${version})
#設定安裝位置,將標頭檔案和庫都安裝到這個文章
set(CMAKE_INSTALL_PREFIX /usr/local/)

# 依賴的外部庫
#find_package(OpenCV REQUIRED)

# 自己的庫依賴的標頭檔案
include_directories(
        ${CMAKE_CURRENT_SOURCE_DIR}
        ${CMAKE_CURRENT_BINARY_DIR}
        lib
        lib/Module1
        # 以下為外部依賴
        # ${OpenCV_INCLUDE_DIRS}
)

file(GLOB_RECURSE source
        lib/*.hpp
        lib/*.cpp
        lib/Module1/*.cpp
        lib/Module1/*.hpp
        )

file(GLOB_RECURSE include
        lib/*.h
        lib/Module1/*.h
        )

# ----------------- 靜態庫 -----------------
add_library(${LIB_NAME} STATIC ${source})
target_link_libraries(${LIB_NAME} PUBLIC
        # 以下為靜態庫的外部依賴
        # ${OpenCV_LIBS}
        )

# ----------------- 可執行檔案 -----------------
# 可執行檔案生成
add_executable(${PROJECT_NAME}  main.cpp)
# 設定可執行檔案的依賴
target_link_libraries(${PROJECT_NAME}
        # 靜態庫
        ${LIB_NAME}
        # 以下為外部依賴
        # ${OpenCV_LIBS}
        )
# ----------------- 結束可執行檔案的生成 -----------------


# ----------------- 生成 CMake 配置檔案(不需要修改) -----------------
# 生成 CMake 配置檔案
include(CMakePackageConfigHelpers)
configure_package_config_file(
        ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${LIB_NAME}Config.cmake.in
        ${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}Config.cmake
        INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${LIB_NAME_VERSION}/
)

configure_package_config_file(
        ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${LIB_NAME}ConfigVersion.cmake.in
        ${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}ConfigVersion.cmake
        INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${LIB_NAME_VERSION}/
)

# 安裝 CMake 配置檔案
install(FILES
        ${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}Config.cmake
        ${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}ConfigVersion.cmake
        DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${LIB_NAME_VERSION}/
        )
# ----------------- 結束生成 CMake 配置檔案 -----------------


# ----------------- 安裝(不需要修改) -----------------
# 安裝原始碼檔案
install(FILES ${include}
        DESTINATION ${CMAKE_INSTALL_PREFIX}/include/${LIB_NAME_VERSION}/
        )

# 安裝靜態庫、可執行檔案
install(TARGETS ${LIB_NAME} ${PROJECT_NAME}
        EXPORT ${LIB_NAME_VERSION}-targets
        RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin/${LIB_NAME_VERSION}/
        ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${LIB_NAME_VERSION}/
        )

# 安裝匯出檔案
install(EXPORT ${LIB_NAME_VERSION}-targets
        NAMESPACE "${LIB_NAME}::"
        DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${LIB_NAME_VERSION}/
        )

# ----------------- 結束安裝 -----------------

1.1 語法基本規則

  • 變數在使用時加${},但在IF控制語句中不加(基本也用不到)
  • 引數與引數之間用 " ; " 或者 " " 分隔
  • 指令不區分大小寫,引數和變數區分大小寫

1.2 檔案目錄講解

  • cmake-build-debug目錄:用來執行編譯和安裝
  • cmake目錄:用來CMakeLists.txt的配置檔案
  • doc目錄:用來存放說明文件
  • lib目錄:用來存放庫檔案
  • LICENSE檔案:用來存放版權資訊
  • main.cpp:用來存放程式的入口
  • README.md:用來存放基本專案說明
  • run.sh:一鍵呼叫的指令碼檔案
  • settings.zip:用來存放一些配置檔案

2.基本指令講解

2.1 CMAKE_MINIMUM_REQUIRED(VERSION XXX)

指定最低版本要求

2.2 PROJECT(projectname)

引數一:生成工程的名字

可選引數二:使用的程式語言。可以不指定程式語言,自動識別(recommended)

2.3 SET()

set()指令可以建立一個變數並賦值,此處SET(CMAKE_CXX_STANDARD 17)表示設定CMAKE_CXX_STANDARD這個變數為17,即設定C++標準為17。

2.4 ADD_SUBDIRECTORY(src bin)

在./src/目錄下尋找並連結下一個CMakeLists.txt,然後在編譯目錄下,即cmake-build-debug目錄下生成一個bin目錄,並且在bin目錄下執行下這個子CMakeLists.txt裡面的語句

引數一:包含子CMakeLists.txt的目錄

可選引數二:為子CMakeLists.txt建立一個指定名字的目錄去執行,若不給出此引數,則自動在cmake-build-debug目錄下執行子CMakeLists.txt的語句

2.5 INCLUDE_DIRECTORIES(lib/)

新增標頭檔案搜尋的路徑./lib

  • 在Linux系統中,預設的標頭檔案搜尋路徑是/usr/include和/usr/local/include

2.6 ADD_EXECUTABLE(main main.cpp)

將main.cpp檔案生成可執行檔案

引數一:生成的可執行檔案的名字

引數二:含main函式的一個或者多個檔名

  • INCLUDE_DIRECTORIES指令要放在ADD_EXECUTABLE的前面
  • TARGET_LINK_LIBRARIES指令要放在ADD_EXECUTABLE的後面

2.7 ADD_LIBRARY(引數一 引數二(STATIC/SHARED) 引數二)

打包一些原始碼生成一個庫檔案

引數一:生成的庫檔案的名字

引數二:可選STATIC或者SHARED,表示生成的是靜態庫或者動態庫

引數三:一個或者多個原始碼檔案

連結某個庫到可執行檔案

引數一:使用ADD_EXECUTABLE生成的可執行檔案的名字

引數二:庫檔案的路徑

  • 在Linux系統中,預設的庫檔案搜尋路徑是/usr/lib

2.9 FIND_PACKAGE()

在使用第三方庫時,常常使用此指令來找到第三方的庫,如:

FIND_PACKAGE(OpenCV REQUIRED)

此指令會自動在/usr/lib/cmake/usr/share/cmake/usr/lib/x86_64-linux-gnu/cmake/snap/cmake等等這樣的安裝路徑去尋找類似於XXConfig.cmake這樣的配置檔案。

如果是自行下載的庫,沒有進行安裝的話,只需要新增指令:

set(CMAKE_PREFIX_PATH /path/to/libA;/path/to/libB)

這樣就增加了cmake尋找庫的路徑。

3.構建和安裝同名靜態庫和動態庫

3.1 靜態庫和動態庫的區別

  • 靜態庫擴充名為" .a " 和 " .lib " ,動態庫擴充名為" .so " 和 " .dll "
  • 靜態庫在編譯時會整合到目標可執行檔案中,生成的可執行檔案可以獨立執行
  • 動態庫在編譯時不會整合到目標可執行檔案中,生成的可執行檔案不可以獨立執行

3.2 構建指令

3.2.1 ADD_LIBRARY

ADD_LIBRARY(projectname_static STATIC ${LIB_LIST} )
ADD_LIBRARY(projectname_shared SHARED ${LIB_LIST} )

將變數LIB_LIST生成靜態庫檔案libprojectname_static.so

將變數LIB_LIST生成動態態庫檔案libprojectname_shared.h

引數一:生成的庫檔名

引數二:靜態庫(STATIC)或動態庫(SHARED)

引數三:原始碼檔案或變數

  • 在CMake的機制中,以上兩條指令被認為是構建了同名的庫,如果不進行屬性設定,那麼在編譯時會自動進行覆蓋

3.2.2 SET_TARGET_PROPERTIES

SET_TARGET_PROPERTIES(projectname_static PROPERTIES 
                      OUTPUT_NAME "projectname"
                      CLEAN_DIRECT_OUTPUT 1)
SET_TARGET_PROPERTIES(projectname_shared PROPERTIES 
                      OUTPUT_NAME "projectname"
                      CLEAN_DIRECT_OUTPUT 1)

將兩個庫檔名都重新命名為 " projectname ",並且指定輸出時不清除同名檔案

引數一:輸出檔案的名字

引數二:PROPERTIES,表示設定屬性

引數OUTPUT_NAME:重新命名

引數CLEAN_DIRECT_OUTPUT:輸出形式

  • 除此之外,還有很多引數可以選擇

3.3 安裝指令

3.3.1 INSTALL()

INSTALL(FILES projectname.h DESTINATION include/projectname/)
INSTALL(FILES authority.h DESTINATION include/projectname/)
INSTALL(TARGETS projectname_static projectname_shared 
        LIBRARY DESTINATION lib/projectname/
        ARCHIVE DESTINATION lib/projectname/ )  

將檔案projectname.h、authority.h、projectname_static、projectname_shared安裝到指定位置

引數一:要安裝的檔案型別

引數二:要安裝的檔名字

引數DESTINATION:安裝路徑

引數LIBRARY DESTINATION:動態庫安裝路徑

引數ARCHIVE DESTINATION:靜態庫安裝路徑

3.3.2 安裝檔案型別與關鍵字對應關係

關鍵字 檔案型別
TARGETS 庫檔案、標頭檔案
FILES 一般檔案
PROGRAMS 指令碼檔案
DIRECTORY 文字檔案

本文由部落格一文多發平臺 OpenWrite 釋出!