1. cmake介紹
CMake主要是解決跨平臺編譯的問題。
CMake的用途是能通過一系列的源碼和相關(guān)的配置來生成需要的編譯器平臺上的項目文件叁温。
譬如,如果一個項目需要在Windows上用VS編譯,在Linux上用make編譯,在OS X上用XCODE寒亥,
那么按以前的做法是在整個項目文件里看三個目錄,分別放置VS的sln文件荧关,Linux的makefile溉奕,OS X的XCODE,
然后讓不同需求的人到相應(yīng)的目錄用自己需要的工程文件(這看起來沒有什么不好似乎)忍啤。
有了CMake以后加勤,就不需要這三個目錄了,只要有一個給CMake讀的文件同波,然后CMake的UI上會需要用戶選擇目標平臺鳄梅,
這樣CMake就會生成目標平臺上的工程文件。舉例未檩,如果用戶選的是VS2005平臺卫枝,那么CMake就會在源代碼目錄下生成供VS2005使用的sln文件;
如果是make讹挎,就會生成makefile等等校赤。
2. cmake安裝
2.1 linux環(huán)境
- 下載地址
https://cmake.org/download/ - 編譯安裝
./bootstrap --prefix=/usr/local/cmake
make -j 6
make install
vim ~/.bashrc
alias cmake=/usr/local/xxxxx/cmake/bin/cmake
source ~/.bashrc
cmake -version
3. cmake簡單示例
3.1 簡單示例1
同一級目錄下的兩個文件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 #目標
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 #目標
PUBLIC
${PROJECT_SOURCE_DIR}/include #包含
)
#—————創(chuàng)建可執(zhí)行程序—————
add_executable(hello_binary
src/main.cpp
)
# 設(shè)置鏈接期間的鏈接庫
target_link_libraries( hello_binary
PRIVATE
hello_library
)
3.4 dynamic link動態(tài)庫
目錄結(jié)構(gòu)及內(nèi)容同上筒溃,除CMakeLists.txt不同:
cmake_minimum_required(VERSION 3.5)
project(hello_library)
#將hello.cpp打包成動態(tài)庫
#Generate the shared library from the library sources
add_library(hello_library SHARED
src/hello.cpp
)
#給動態(tài)庫hello_library起一個別名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
)
#添加動態(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會將父目錄的所有變量拷貝到當前CMakeLists.txt中,當前CMakeLists.txt中的變量的作用域僅在當前子目錄有效怜奖。
特點:向下有效和數(shù)值拷貝生成副本浑测,在不使用特殊關(guān)鍵字的情況下,嵌套(子)作用域針對普通變量的修改不會影響到父作用域歪玲。
針對變量迁央,普通變量僅僅有效于當前作用域,而緩存變量和環(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中的定義指令通過兩種方法實現(xiàn):macro()和function()
#CMake中的宏
macro(<name> [<argument> ])
<commands>
endmacro()
函數(shù):
//CMake中的函數(shù)聲明
function(<name> [<argument> ])
<commands>
endfunction()
4.3.2 實用指令
include指令:
如引用官方和CMake社區(qū)中已經(jīng)配置好了的CMake模板钙皮,所謂的CMake模板就是將CMake代碼劃分到單獨的.cmake文件中蜂科,以保持內(nèi)容的有序和獨立性
include(<file|module> [OPTIONAL] [RESULT_VARIABLE <var>])
include("${CMAKE_CURRENT_LIST_DIR}/<filename>.cmake")
file指令:
file() 指令會以一種與系統(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選項設(shè)置編譯器可都,而不是導(dǎo)出CXX缓待、CC和FC。
# CLI選項:-D CMAKE_<LANG>_COMPILER 是確毙谠粒跨平臺并與非POSIX兼容的唯一方法命斧,避免變量污染與項目一起構(gòu)建的外部庫環(huán)境,使用CLI中的-D選項嘱兼,例如:
# $ 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:如果為項目啟用了語言<LANG>国葬,則將設(shè)置為TRUE。
# CMAKE_<LANG>_COMPILER_ID:編譯器標識字符串芹壕,編譯器供應(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:此變量包含一個字符串行剂,該字符串給定語言的編譯器版本
編譯選項指定:
# 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選項:
(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.")