cmake使用

1. cmake介紹

CMake主要是解決跨平臺編譯的問題。
CMake的用途是能通過一系列的源碼和相關(guān)的配置來生成需要的編譯器平臺上的項(xiàng)目文件。
譬如,如果一個(gè)項(xiàng)目需要在Windows上用VS編譯,在Linux上用make編譯,在OS X上用XCODE,
那么按以前的做法是在整個(gè)項(xiàng)目文件里看三個(gè)目錄,分別放置VS的sln文件,Linux的makefile,OS X的XCODE,
然后讓不同需求的人到相應(yīng)的目錄用自己需要的工程文件(這看起來沒有什么不好似乎)。
有了CMake以后,就不需要這三個(gè)目錄了,只要有一個(gè)給CMake讀的文件,然后CMake的UI上會(huì)需要用戶選擇目標(biāo)平臺,
這樣CMake就會(huì)生成目標(biāo)平臺上的工程文件。舉例,如果用戶選的是VS2005平臺,那么CMake就會(huì)在源代碼目錄下生成供VS2005使用的sln文件;
如果是make,就會(huì)生成makefile等等。

2. cmake安裝

2.1 linux環(huán)境

vim ~/.bashrc
alias cmake=/usr/local/xxxxx/cmake/bin/cmake
source ~/.bashrc
cmake -version

3. cmake簡單示例

3.1 簡單示例1

同一級目錄下的兩個(gè)文件test.cpp,CMakeLists.txt
src文件test.cpp:

#include <iostream>

int main()
{
    std::cout << "hello." << std::endl;
    return 0;
}

CMakeLists.txt 文件:

cmake_minimum_required(VERSION 3.5)

# set the project name
project (hello_cmake)

message("this is a test msg, project name is : ${PROJECT_NAME}")

# add the executable
add_executable(hello_cmake test.cpp)

執(zhí)行編譯命令:

mkdir build
cd build
cmake ..
make

3.2 簡單示例2(不同目錄)

目錄結(jié)構(gòu):

.
├── CMakeLists.txt
├── include
│   └── hello.h
└── src
    ├── hello.cpp
    └── main.cpp

hello.h文件內(nèi)容:

#ifndef HELLO_H__
#define HELLO_H__
#include <iostream>
void print();
#endif

hello.cpp文件內(nèi)容:

#include "hello.h"

void print()
{
    std::cout << "hello." << std::endl;
}

main.cpp文件內(nèi)容:

#include "hello.h"

int main()
{
    print();
    return 0;
}

CMakeLists.txt文件內(nèi)容:

cmake_minimum_required(VERSION 3.5)
project (hello_headers)
 
# 設(shè)置源文件變量
set(SOURCES
    src/hello.cpp
    src/main.cpp
)
 
# 根據(jù)源文件目錄構(gòu)建可執(zhí)行程序
add_executable(hello_headers ${SOURCES})
 
# 設(shè)置包含目錄
target_include_directories(hello_headers   #目標(biāo)
    PRIVATE 
        ${PROJECT_SOURCE_DIR}/include      #包含目錄
)

3.3 static link 靜態(tài)庫

目錄結(jié)構(gòu)及內(nèi)容同上,除CMakeLists.txt不同:

cmake_minimum_required(VERSION 3.5)
project(hello_library)
 
#將hello.cpp打包成靜態(tài)庫
add_library(hello_library STATIC 
    src/hello.cpp
)
 
#設(shè)置包含目錄
target_include_directories(hello_library   #目標(biāo)
    PUBLIC 
        ${PROJECT_SOURCE_DIR}/include      #包含
)
 
 
#—————?jiǎng)?chuàng)建可執(zhí)行程序—————
add_executable(hello_binary 
    src/main.cpp
)
 
# 設(shè)置鏈接期間的鏈接庫
target_link_libraries( hello_binary
    PRIVATE 
        hello_library
)

3.4 dynamic link動(dòng)態(tài)庫

目錄結(jié)構(gòu)及內(nèi)容同上,除CMakeLists.txt不同:

cmake_minimum_required(VERSION 3.5)
project(hello_library)
 
#將hello.cpp打包成動(dòng)態(tài)庫
#Generate the shared library from the library sources
add_library(hello_library SHARED 
    src/hello.cpp
)

#給動(dòng)態(tài)庫hello_library起一個(gè)別名hello::library
add_library(hello::library ALIAS hello_library)
#設(shè)置包含目錄
message(" PROJECT_SOURCE_DIR is : ${PROJECT_SOURCE_DIR}")
target_include_directories(hello_library
    PUBLIC 
        ${PROJECT_SOURCE_DIR}/include
)
 
# 構(gòu)建可執(zhí)行程序
add_executable(hello_binary
    src/main.cpp
)

#添加動(dòng)態(tài)鏈接庫
target_link_libraries( hello_binary
    PRIVATE 
        hello::library
)

4. cmake語法

4.1 變量

4.1.1 普通變量

基本的變量操作指令是set() unset()
變量名區(qū)分大小寫

set(MyString1 "Text1")
set("My String 2" "Text2")
message(${MyString1})
message(${My\ String\ 3})
unset(MyString1)

4.1.2 環(huán)境變量

set(ENV{<variable>} <value>) unset(ENV{<variable>})

#讀取cmake腳本中定義的環(huán)境變量:
set(ENV{CMAKE_PATH} "myown/path/example")
# 判斷CMAKE_PATH環(huán)境變量是否定義
if(DEFINED ENV{CMAKE_PATH}) //注意此處ENV前沒有$符號
  message("CMAKE_PATH_1: $ENV{CMAKE_PATH}") //注意此處ENV前有$符號
else()
  message("NOT DEFINED CMAKE_PATH VARIABLES")
endif()
# 讀取系統(tǒng)中的環(huán)境變量:
cmake_minimum_required(VERSION 3.20.0)
project(Environment)
#在配置期間打印myenv環(huán)境變量
message("generated with " $ENV{myenv})
# 在構(gòu)建階段過程中打印相同的變量
add_custom_target(EchoEnv ALL COMMAND echo "myenv in build is" $ENV{myenv})

測試命令:
創(chuàng)建build構(gòu)建系統(tǒng):cmake -B build ./
執(zhí)行構(gòu)建: cd build; cmake --build ./

4.1.3 變量作用域

目錄作用域的啟用一般是在父目錄下的CmakeList.txt中有add_subdirectory(“子目錄路徑”)指令,而在子目錄的CMakeLists.txt會(huì)將父目錄的所有變量拷貝到當(dāng)前CMakeLists.txt中,當(dāng)前CMakeLists.txt中的變量的作用域僅在當(dāng)前子目錄有效。
特點(diǎn):向下有效和數(shù)值拷貝生成副本,在不使用特殊關(guān)鍵字的情況下,嵌套(子)作用域針對普通變量的修改不會(huì)影響到父作用域。
針對變量,普通變量僅僅有效于當(dāng)前作用域,而緩存變量和環(huán)境變量可以在全局作用域中使用。

4.2 控制結(jié)構(gòu)

三類控制結(jié)構(gòu):條件塊、循環(huán)、定義指令
條件塊:

if(<condition>)
  <commands>
elseif(<condition>) # optional block, can be repeated
  <commands>
else() # optional block
  <commands>
endif()

循環(huán):

while(<condition>)
  <commands>
endwhile()

foreach(<loop_variable> IN [LISTS <lists>] [ITEMS <items>])

4.3 指令

4.3.1 自定義指令

CMake中的定義指令通過兩種方法實(shí)現(xiàn):macro()和function()

#CMake中的宏
macro(<name> [<argument> ])
  <commands>
endmacro()

函數(shù):

//CMake中的函數(shù)聲明
function(<name> [<argument> ])
  <commands>
endfunction()

4.3.2 實(shí)用指令

include指令:
如引用官方和CMake社區(qū)中已經(jīng)配置好了的CMake模板,所謂的CMake模板就是將CMake代碼劃分到單獨(dú)的.cmake文件中,以保持內(nèi)容的有序和獨(dú)立性

include(<file|module> [OPTIONAL] [RESULT_VARIABLE <var>])
include("${CMAKE_CURRENT_LIST_DIR}/<filename>.cmake")

file指令:
file() 指令會(huì)以一種與系統(tǒng)無關(guān)的方式讀取、寫入和傳輸文件,并使用文件系統(tǒng)、文件鎖、路徑和存檔

file(READ <filename> <out-var> [...])
file({WRITE | APPEND} <filename> <content>...)
 file(DOWNLOAD <url> [<file>] [...])

execute_process指令:

execute_process(COMMAND <cmd1> [<arguments>]  [OPTIONS])

cmake最小版本號設(shè)置:
cmake_minimum_required(VERSION 3.10)

set the project name:
project(Tutorial)

add the executable 生成可執(zhí)行文件:
add_executable(Tutorial tutorial.cpp)

set the project name and version:
project(Tutorial VERSION 1.0)

specify the C++ standard 設(shè)置使用的c++版本:
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

添加靜態(tài)庫:

add_library(message
 STATIC
    Message.hpp
    Message.cpp
  )
add_executable(hello-world hello-world.cpp)
target_link_libraries(hello-world message)

指定編譯器:

# set minimum cmake version & project name and language
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(recipe-06 LANGUAGES C CXX)
 
# CMake將語言的編譯器存儲在CMAKE_<LANG>_COMPILER變量中,其中<LANG>是受支持的任何一種語言,對于我們的目的是CXX、C或Fortran
# 建議使用-D CMAKE_<LANG>_COMPILER CLI選項(xiàng)設(shè)置編譯器,而不是導(dǎo)出CXX、CC和FC。
# CLI選項(xiàng):-D CMAKE_<LANG>_COMPILER 是確保跨平臺并與非POSIX兼容的唯一方法,避免變量污染與項(xiàng)目一起構(gòu)建的外部庫環(huán)境,使用CLI中的-D選項(xiàng),例如:
    # $ cmake -D CMAKE_CXX_COMPILER=clang++ ..
message(STATUS "Is the C++ compiler loaded? ${CMAKE_CXX_COMPILER_LOADED}")
if(CMAKE_CXX_COMPILER_LOADED)
 message(STATUS "The C++ compiler ID is: ${CMAKE_CXX_COMPILER_ID}")
 message(STATUS "Is the C++ from GNU? ${CMAKE_COMPILER_IS_GNUCXX}")
 message(STATUS "The C++ compiler version is: ${CMAKE_CXX_COMPILER_VERSION}")
endif()
 
message(STATUS "Is the C compiler loaded? ${CMAKE_C_COMPILER_LOADED}")
if(CMAKE_C_COMPILER_LOADED)
 message(STATUS "The C compiler ID is: ${CMAKE_C_COMPILER_ID}")
 message(STATUS "Is the C from GNU? ${CMAKE_COMPILER_IS_GNUCC}")
 message(STATUS "The C compiler version is: ${CMAKE_C_COMPILER_VERSION}")
endif()
 
 
# CMake提供了額外的變量來與編譯器交互:
 # CMAKE_<LANG>_COMPILER_LOADED:如果為項(xiàng)目啟用了語言<LANG>,則將設(shè)置為TRUE。
 # CMAKE_<LANG>_COMPILER_ID:編譯器標(biāo)識字符串,編譯器供應(yīng)商所特有。
 # 例如,GCC用于GNU編譯器集合,AppleClang用于macOS上的Clang, MSVC用于Microsoft Visual Studio編譯器。
 # 注意,不能保證為所有編譯器或語言定義此變量。
 # CMAKE_COMPILER_IS_GNU<LANG>:如果語言<LANG>是GNU編譯器集合的一部分,則將此邏輯變量設(shè)置為TRUE。
 # 注意變量名的<LANG>部分遵循GNU約定:C語言為CC, C++語言為CXX, Fortran語言為G77。
 # CMAKE_<LANG>_COMPILER_VERSION:此變量包含一個(gè)字符串,該字符串給定語言的編譯器版本

編譯選項(xiàng)指定:

# set minimum cmake version & project name and language
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(recipe-07 LANGUAGES C CXX)
 
# we default to Release build type
if(NOT CMAKE_BUILD_TYPE)
 set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
endif()
 
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
 
message(STATUS "C flags, Debug configuration: ${CMAKE_C_FLAGS_DEBUG}")
message(STATUS "C flags, Release configuration: ${CMAKE_C_FLAGS_RELEASE}")
message(STATUS "C flags, Release configuration with Debug info: ${CMAKE_C_FLAGS_RELWITHDEBINFO}")
message(STATUS "C flags, minimal Release configuration: ${CMAKE_C_FLAGS_MINSIZEREL}")
 
message(STATUS "C++ flags, Debug configuration: ${CMAKE_CXX_FLAGS_DEBUG}")
message(STATUS "C++ flags, Release configuration: ${CMAKE_CXX_FLAGS_RELEASE}")
message(STATUS "C++ flags, Release configuration with Debug info: ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
message(STATUS "C++ flags, minimal Release configuration: ${CMAKE_CXX_FLAGS_MINSIZEREL}")

5. cmake添加打印信息

message([<mode>] "message to display" ...)
mode選項(xiàng):
(none) = Important information
STATUS = Incidental information
WARNING = CMake Warning, continue processing
AUTHOR_WARNING = CMake Warning (dev), continue processing
SEND_ERROR = CMake Error, continue processing, but skip generation
FATAL_ERROR = CMake Error, stop processing and generation
DEPRECATION = CMake Deprecation Error or Warning if variable
CMAKE_ERROR_DEPRECATED or CMAKE_WARN_DEPRECATED
is enabled, respectively, else no message.

message(STATUS "hello world.")

參考:
cmake語法
cmake菜譜
cmake官方文檔
cmake常用指令

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • tags: 嵌入式categories: 開發(fā) cmake 總結(jié) 交叉編譯 設(shè)置編譯器CMAKE_FORCE_C_...
    jasonzeng閱讀 3,296評論 0 2
  • CMake簡介 CMake 是一個(gè)跨平臺的安裝(編譯[https://baike.baidu.com/item/%...
    skycoder閱讀 5,339評論 0 3
  • 1.安裝 $sudo apt-get install cmake 2.示例:簡單的文件目錄 sample |—...
    荷包蛋醬閱讀 29,904評論 0 15
  • CMake 是一種跨平臺的免費(fèi)開源軟件工具,用于使用與編譯器無關(guān)的方法來管理軟件的構(gòu)建過程。在 Android S...
    張坤的筆記閱讀 2,252評論 2 0
  • 注:首發(fā)地址 1. 前言 當(dāng)在做 Android NDK 開發(fā)時(shí),如果不熟悉用 CMake 來構(gòu)建,讀不懂 CMa...
    cfanr閱讀 24,801評論 1 53

友情鏈接更多精彩內(nèi)容