cmake总结

一,cmake概念

CMake是开源、跨平台的构建工具,可以让我们通过编写简单的配置文件去生成本地的Makefile,这个配置文件是独立于运行平台和编译器的,这样就不用亲自去编写Makefile了,而且配置文件可以直接拿到其它平台上使用,无需修改,非常方便。

要使用cmake,需要编写 CMakeLists.txt 文件,这个文件会被 cmake 工具解析。

执行cmake:cmake CMakeLists文件所在路径

二,cmake使用

CMakeLists.txt基本命令:

  • CMAKE_MINIMUM_REQUIRED(VERSION 版本号):指定使用cmake的最低版本
  • PROJECT(工程名):定义工程的名称
  • ADD_EXECUTABLE(可执行文件名 所有需要用到的源文件):定义工程生成的可执行文件
bash 复制代码
# 例如:(需要通过三个源文件生成一个可执行文件)

CMAKE_MINIMUM_REQUIRED(VERSION 3.0)

PROJECT(MAIN)

ADD_EXECUTABLE(main main.cpp a.cpp b.cpp)

SET

上面例子中,将所有需要用到的源文件全部写到ADD_EXECUTABLE中,这会导致维护起来十分困难,尤其在项目比较大的时候,源文件比较多的情况下。

定义变量:
  • SET(变量名 值):定义一个变量并初始化其值

使用变量:${变量名}

在上面的情况下我们可以:

bash 复制代码
# ADD_EXECUTABLE(main main.cpp a.cpp b.cpp)改为:

SET(SRC main.cpp a.cpp b.cpp)

ADD_EXECUTABLE(main ${SRC})
指定C++标准
  • CMAKE_CXX_STANDARD:定义C++标准的宏
bash 复制代码
# 例如设置C++14标准

SET(CMAKE_CXX_STANDARD 14)
指定可执行文件的输出路径
  • EXECUTABLE_OUTPUT_PATH:定义可执行文件路径的宏
bash 复制代码
# 例如:将生成的可执行文件放到一个不存在的目录下

SET(EXECUTABLE_OUTPUT_PATH ./output/)

搜索文件

其实上述的不论是在ADD_EXECUTABLE中加源文件,还是在SET中添加源文件都没有解决根本问题(源文件数量很大时难以维护)因此如果可以直接查找到目录下所有的源文件并保存在变量中,那么可以解决上述的问题

常用两个宏:

PROJECT_SOURCE_DIR:保存cmake命令后跟随的路径,也就是CMakeLists.txt所在的路径

CMAKE_CURRENT_SOURCE_DIR:保存CMakeLists.txt所在的路径

  • AUX_SOURCE_DIRECTORY(搜索路径 变量名):将搜索路径下所有源文件存储在变量中。
bash 复制代码
# 例如:查找CMakeLists.txt所在目录下所有源文件,存储在变量中

AUX_SOURCE_DIRECTORY(${PROJECT_SOURCE_DIR} SRC)
  • FILE(GLOB/GLOB_RECURSE 变量名 搜索路径和搜索文件类型):将搜索路径下的所有满足类型的文件名存储在变量中(GLOB_RECURSE是进行递归查找,当前文件下的子目录也会进行查找)
bash 复制代码
# 例如:查找CMakeLists.txt所在目录下所有源文件,存储在变量中

FILE(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)

指定头文件搜索路径

当工程中源文件与头文件不在一个目录下时,为了使源文件能够找到头文件:我们直接改变源文件中的 #include "../include/head.h",但是这种方法在源文件很多时非常麻烦。因此如果我们能直接让所有源文件都去自己找到头文件,就可以解决

  • INCLUDE_DIRECTORIES(所有头文件路径):在所有设置的路径下查找头文件
bash 复制代码
# 例如:按照上图中,在include下找头文件

INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include)

cmake制作库文件

在Linux下库文件分为两种:动态库(libxxx.so) 和 静态库(libxxx.a)

  • ADD_LIBRARY(库名称 STATIC/SHARED 所有需要用到的源文件):将所有源文件制作成库文件(动态库:SHARED 静态库:STATIC)
  • LIBRARY_OUTPUT_PATH:设置库文件输出路径的宏
bash 复制代码
# 例如:目前需要将SRC(保存所有源文件的变量)制作为静/动态库并放到CMakeLists.txt所在目录的lib下

SET(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib)

# 静态库 libmain.a
ADD_LIBRARY(main STATIC ${SRC})

# 动态库 libmain.so
ADD_LIBRARY(main SHARED ${SRC})

cmake链接库文件

链接静态库
  • LINK_LIBRARIES(所有需要库文件):为程序链接所有需要的静态库
  • LINK_DIRECTORIES(所有库文件的搜索路径):指定库文件(静/动态库)搜索路径
bash 复制代码
# 如上图,我需要链接静态库libmain.a去生成可执行文件

CMAKE_MINIMUM_REQUIRED(VIRSION 3.0)

PROJECT(MAIN)

AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/ SRC)

SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/build/output)

INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/invlude)

LINK_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/lib.a)

LINK_LIBRARIES(libmain.a)

ADD_EXECUTABLE(main ${SRC})
链接动态库

TARGET_LINK_LIBRARIES(目标 PRIVATE/PUBLIC/INTERFACE 动态库1 ...):为程序链接所有需要动态库

  • 目标:源文件,动态库文件,可执行文件
  • PRIVATE/PUBLIC/INTERFACE:动态库的访问权限(不写默认为PUBLIC)
  • 注意:一般链接库都放在CMakeLists.txt的文件末尾

其中

PUBLIC:其后面的库会被link到目标中,并且里面的符号会被导出,供第三发使用(a链接了b,c;d链接了a;d可以使用b,c的函数)

PRIVATE:其后面的库会被link到目标中,并且终结掉,第三方不知道你调了什么库(a链接了b,c;d链接了a;d不可以使用b,c的函数)

INTERFACE:其后面的库不会被link到目标中,只会导出符号(可以使用函数,但不知道哪个库的)

bash 复制代码
CMAKE_MINIMUM_REQUIRED(VERSION 3.0)

PROJECT(MAIN)

AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/ SRC)

SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/build/output)

INCLUDE_LIBRARIES(${CMAKE_CURRENT_SOURCE_DIR}/include)

LINK_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/lib/a ${CMAKE_CURRENT_SOURCE_DIR}/lib/so)

ADD_EXECUTABLE(main ${SRC})

TARGET_LINK_LIBRARIES(main libmain.so)

打印日志

  • MESSAGE((无) | STATUS | WARNING | AUTHOR_WARNING | SEND_ERROR | FATAL_ERROR "日志信息"):根据不同的等级按照不同的形式输出日志

其中:

(无):什么都不写代表重要信息

STATUS:非重要信息,输出时前面带有"-- "

WARNING:警告信息

AUTHOR_WARNING:警告信息(dev)

SEND_ERROR:错误信息,不会终止执行

FATAL_ERROR:错误信息,终止执行

字符串操作

追加字符串
  • SET(变量名 字符串/${变量} ...):将字符串拼接起来存储在变量中
  • LIST(APPEND 变量名 字符串/${变量} ...):将字符串拼接起来存储在变量中
bash 复制代码
# 例如:

AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/src SRC)

# SET拼接元素
SET(TMP hello world)

SET(TMP1 ${TMP} ${SRC})

MESSAGE(${TMP})

MESSAGE(${TMP1})

# LIST拼接元素
LIST(APPEND TMP "xxx1" "sss2" ${SRC})
删除字符串
  • LIST(REMOVE_ITEM 变量名 移除字符串 ...):移除变量中的字符串
bash 复制代码
# 例如:移除5个源文件中没有用的main.cpp,使用其他4个源文件生成库文件

AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/src SRC)

MESSAGE(${SRC})

LIST(REMOVE_ITEM SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp)

MESSAGE(${SRC})

嵌套cmake

  • ADD_SUBDIRECTORY(目录名称):将该目录构建为当前节点的子节点

父节点CMakeLists.txt中定义的变量,在子节点中是可见的,可以访问到

举例如下:

父节点:

bash 复制代码
CMAKE_MINIMUM_REQUIRED(VERSION 3.15)

PROJECT(TEST)

# 创建父子节点关系
ADD_SUBDIRECTORY(calc)
ADD_SUBDIRECTORY(sort)
ADD_SUBDIRECTORY(test1)
ADD_SUBDIRECTORY(test2)

calc子节点:

bash 复制代码
CMAKE_MINIMUM_REQUIRED(VERSION 3.15)

PROJECT(CALC)

AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/ SRC)

INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../include)

SET(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../lib)

# 生成静态库libcalc.a
ADD_LIBRARY(calc STATIC ${SRC})

sort子节点:

bash 复制代码
CMAKE_MINIMUM_REQUIRED(VERSION 3.15)

PROJECT(SORT)

AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/ SRC)

INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../include)

SET(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../lib)

# 生成静态库libsort.a
ADD_LIBRARY(sort STATIC ${SRC})

test1子节点:

bash 复制代码
CMAKE_MINIMUM_REQUIRED(VERSION 3.15)

PROJECT(TEST1)

AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/ SRC)

INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../include)

LINK_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../lib)

# 链接静态库libcalc.a
LINK_LIBRARIES(calc)

SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../bin)

# 生成可执行文件app1
ADD_EXECUTABLE(app1 ${SRC})

test2子节点:

bash 复制代码
CMAKE_MINIMUM_REQUIRED(VERSION 3.15)

PROJECT(TEST2)

AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/ SRC)

INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../include)

LINK_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../lib)

# 链接静态库libsort.a
LINK_LIBRARIES(sort)

SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../bin)

# 生成可执行文件app2
ADD_EXECUTABLE(app2 ${SRC})
相关推荐
zhy295632 天前
【LIBS】开源库编译之OSQP
ubuntu·cmake·osqp·libs
charlee443 天前
CMake构建学习笔记19-OpenSSL库的构建
ssl·cmake·c/c++·构建
Prejudices4 天前
CMake的INSTALL FILES和INSTALL DIRECTORY有什么区别
cmake
上官永石5 天前
《Modern CMake for C++》学习笔记
cmake
Yongqiang Cheng7 天前
Installing CMake (安装 CMake)
cmake·安装 cmake
石悼花10 天前
Visual Studio 2022+CMake配置PCL1.14.1
c++·cmake·visual studio·pcl·openni2
___波子 Pro Max.14 天前
cmake CMAKE_CURRENT_SOURCE_DIR和CMAKE_CURRENT_LIST_DIR的区别
cmake
dragoo117 天前
vscode cmake头文件无法跳转
c++·vscode·cmake·头文件
路西法Lux17 天前
Cmake+基础命令
cmake