cmake之CMakelist.txt的使用

2023-05-16

文章目录

    • 常用命令
      • 1. 指定 cmake 的最小版本
      • 2. 打印信息
        • 2.1. 打印普通信息
        • 2.2. 打印告警
        • 2.3. 打印错误
      • 3. 项目名称
      • 4. 设置变量
      • 5. 查找指定的库文件
      • 6. 设置包含的目录
      • 7. 设置链接库搜索目录
      • 8. 指定编译包含的源文件
        • 8.1 明确指定包含哪些源文件
        • 8.2 搜索所有的 cpp 文件
        • 8.3 自定义搜索规则
      • 9. 设置编译类型
      • 10. 设置 target 需要链接的库
      • 11. 包含其它 cmake 文件
      • 12. 重命名
        • 12.1. 添加后缀
        • 12.2. 添加版本号
        • 12.3. 重命名
      • 13. install安装
        • 13.1 目标文件的安装
        • 13.2 普通文件的安装
        • 13.3 非目标文件的可执行程序安装(比如脚本之类)
        • 13.4 目录的安装
    • 条件控制
      • 1. if…elseif…else…endif
      • 2. while…endwhile
      • 3. foreach…endforeach
    • 常用变量
      • 1. 预定义变量
      • 2. 环境变量
      • 3. 系统信息
      • 4. 主要开关选项
    • cmake指定特定版本gcc、g++

常用命令

1. 指定 cmake 的最小版本

cmake_minimum_required(VERSION 3.22.1)

2. 打印信息

2.1. 打印普通信息

message(${PROJECT_SOURCE_DIR})
message("some message")

2.2. 打印告警

message(WARNING "warnning message")

2.3. 打印错误

FATAL_ERROR 会导致编译失败,可配合条件判断使用

message(FATAL_ERROR "error message")

3. 项目名称

project(demo)

可选项,它会引入两个变量 demo_BINARY_DIRdemo_SOURCE_DIR
同时cmake自动定义两个变量 PROJECT_BINARY_DIRPROJECT_SOURCE_DIR

4. 设置变量

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -Wall -fPIC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -O3 -Wall -fPIC")
set(CMAKE_BUILD_TYPE Release)
set(TARGET test)
set(CMAKE_INSTALL_PREFIX "../install")

5. 查找指定的库文件

同类型的命令有:

find_file()
find_path()
find_program()
find_package()
find_library()

用法:
find_library(VAR name path)查找到指定的预编译库,并将它的路径存储在变量中。
默认的搜索路径为 cmake 包含的系统库,因此如果是 NDK 的公共库只需要指定库的 name 即可。

find_library(log-lib log )
set(CMAKE_PREFIX_PATH "/home/libtorch_170/share/cmake/Torch")
find_package(Torch REQUIRED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TORCH_CXX_FLAGS}")

set(OpenCV_DIR "/home/opencv450/install/lib/cmake/opencv4")
find_package(OpenCV 4 REQUIRED)

6. 设置包含的目录

include_directories(
    ${PROJECT_SOURCE_DIR}/include
    ${CMAKE_CURRENT_SOURCE_DIR}
    ${CMAKE_CURRENT_BINARY_DIR}
    ${CMAKE_CURRENT_SOURCE_DIR}/include
)

Linux 下还可以通过如下方式设置包含的目录

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${CMAKE_CURRENT_SOURCE_DIR}")

7. 设置链接库搜索目录

link_directories(
     ${CMAKE_CURRENT_SOURCE_DIR}/libs
 )

Linux 下还可以通过如下方式设置包含的目录

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_CURRENT_SOURCE_DIR}/libs")

8. 指定编译包含的源文件

8.1 明确指定包含哪些源文件

add_library(demo demo.cpp test.cpp util.cpp)

8.2 搜索所有的 cpp 文件

aux_source_directory(dir VAR) 发现一个目录下所有的源代码文件并将列表存储在一个变量中。

aux_source_directory(. SRC_LIST) # 搜索当前目录下的所有.cpp文件
add_library(demo ${SRC_LIST})

8.3 自定义搜索规则

file(GLOB SRC_LIST "*.cpp" "protocol/*.cpp")
add_library(demo ${SRC_LIST})
# 或者
file(GLOB SRC_LIST "*.cpp")
file(GLOB SRC_PROTOCOL_LIST "protocol/*.cpp")
add_library(demo ${SRC_LIST} ${SRC_PROTOCOL_LIST})
# 或者
aux_source_directory(. SRC_LIST)
aux_source_directory(protocol SRC_PROTOCOL_LIST)
add_library(demo ${SRC_LIST} ${SRC_PROTOCOL_LIST})

9. 设置编译类型

add_executable(demo demo.cpp)       # 生成可执行文件
add_library(common STATIC util.cpp) # 生成静态库
add_library(common SHARED util.cpp) # 生成动态库或共享库

add_library 默认生成是静态库,通过以上命令生成文件名字,

在 Linux 下是:
demo
libcommon.a
libcommon.so

在 Windows 下是:
demo.exe
common.lib
common.dll

10. 设置 target 需要链接的库

库的路径可以通过设置链接库搜索目录添加

target_link_libraries( ${TARGET} #这是生成的目标
	# 然后下面是生成目标所需要链接的库,如:
	${TORCH_LIBRARIES}
	${OpenCV_LIBS} 
	dl 
	m 
	pthread 
	rt 
)

11. 包含其它 cmake 文件

include(./common.cmake) # 指定包含文件的全路径
include(def) 			# 在搜索路径中搜索def.cmake文件
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) # 设置include的搜索路径

12. 重命名

此处的TARGET为生成的名字,以name为例

set(TARGET name)

12.1. 添加后缀

生成类似这样的动态库libname_message.so

set(CMAKE_RELEASE_POSTFIX "_message")  	#这条命令需要放在add_library之前
add_library(${TARGET} SHARED ${SRC_LIST})

生成类似这样的可执行文件name_message

add_executable(${TARGET}  ${SRC_LIST}) 
set_target_properties(${TARGET} PROPERTIES RELEASE_POSTFIX "_message")

12.2. 添加版本号

生成类似这样的动态库libname.so.x.y.z
最前面使用前缀lib,中间为库的名字,后缀为.so,后面跟着 3 个数字组成的版本号。"x"表示**主版本号,"y"表示次版本号,"z"表示发布版本号。

VERSION:完整版本号 SOVERSION:SONAME

set_target_properties(${TARGET} PROPERTIES VERSION 1.0.0 SOVERSION 1) 

12.3. 重命名

如果不想用name,想换个名字;将“name”换成“hello”

set_target_properties (${TARGET} PROPERTIES OUTPUT_NAME "hello")

13. install安装

安装的方式有两种,一种是执行cmake的时候指定安装目录:

cmake -DCMAKE_INSTALL_PREFIX=../install  ..

另一种是在CMakelist.txt 中设置安装的根路径:

set(CMAKE_INSTALL_PREFIX ../PATH)
INSTALL指令用于定义安装规则,安装的内容可以包括目标二进制、动态库、静态库以及
文件、目录、脚本等。

13.1 目标文件的安装

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

参数中的TARGETS后面跟的就是我们通过ADD_EXECUTABLE或者ADD_LIBRARY定义的
目标文件,可能是可执行二进制、动态库、静态库。

目标类型也就相对应的有三种,ARCHIVE特指静态库,LIBRARY特指动态库,RUNTIME
特指可执行目标二进制。

DESTINATION定义了安装的路径,如果路径以/开头,那么指的是绝对路径,这时候
CMAKE_INSTALL_PREFIX其实就无效了。如果你希望使用CMAKE_INSTALL_PREFIX来
定义安装路径,就要写成相对路径,即不要以/开头,那么安装后的路径就是
${CMAKE_INSTALL_PREFIX}/<DESTINATION定义的路径>

简单的例子:

#如果 demo 是可执行文件则会安装到${CMAKE_INSTALL_PREFIX}/bin目录  
#如果是动态库则会安装到${CMAKE_INSTALL_PREFIX}/lib目录  
#如果是静态库则会安装到${CMAKE_INSTALL_PREFIX}/libstatic目录

install(TARGETS ${TARGET}
       RUNTIME DESTINATION bin          #可执行文件安装路径(追加)
       LIBRARY DESTINATION lib          #动态库文件安装路径(追加)
       ARCHIVE DESTINATION libstatic    #静态库文件安装路径(追加)
)

13.2 普通文件的安装

INSTALL(FILES files... DESTINATION <dir>
         [PERMISSIONS permissions...]
         [CONFIGURATIONS [Debug|Release|...]]
         [COMPONENT <component>]
         [RENAME <name>] [OPTIONAL])
可用于安装一般文件,并可以指定访问权限,文件名是此指令所在路径下的相对路径。
如果默认不定义权限PERMISSIONS,安装后的权限为,OWNER_WRITE,OWNER_READ,
GROUP_READ,和WORLD_READ,即644权限。

简单的例子:

install (FILES ${PROJECT_SOURCE_DIR}/include/mpt_study.h ${PROJECT_SOURCE_DIR}/include/mpt_public.h                 #安装文件
    DESTINATION include                                                     #普通文件安装路径(追加)
    PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ                #权限
)

13.3 非目标文件的可执行程序安装(比如脚本之类)

INSTALL(PROGRAMS files... DESTINATION <dir>
     [PERMISSIONS permissions...]
     [CONFIGURATIONS [Debug|Release|...]]
     [COMPONENT <component>]
     [RENAME <name>] [OPTIONAL])
跟上面的FILES指令使用方法一样,唯一的不同是安装后权限为:
OWNER_EXECUTE, GROUP_EXECUTE, 和WORLD_EXECUTE,即755权限

简单的例子:

install (PROGRAMS ${PROJECT_SOURCE_DIR}/compile.sh                          #安装文件
    DESTINATION SHPATH                                                      #普通文件安装路径(追加)
    PERMISSIONS OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE                   #权限
)

13.4 目录的安装

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...]] [...])
这里主要介绍其中的DIRECTORY、PATTERN以及PERMISSIONS参数。
DIRECTORY后面连接的是所在Source目录的相对路径,但务必注意:
abc和abc/有很大的区别。
abc意味着abc这个目录会安装在目标路径下;
abc/意味着abc这个目录的内容会被安装在目标路径下;
如果目录名不以/结尾,那么这个目录将被安装为目标路径下的abc,如果目录名以/结尾,
代表将这个目录中的内容安装到目标路径,但不包括这个目录本身。
PATTERN用于使用正则表达式进行过滤,
PERMISSIONS用于指定PATTERN过滤后的文件权限。

简单的例子:

#install 目录安装
INSTALL(DIRECTORY icons scripts/                                                #安装目录文件    icons整个文件夹  scripts文件夹下的文件(不包含文件夹) 
    DESTINATION cpdir                                                           #目录安装路径
    PATTERN "CVS" EXCLUDE                                                       #过滤掉 CVS
    PATTERN "scripts/*"                                                         #选中所有文件
    PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ   #权限
)

这条指令的执行结果是:
将icons目录安装到 <prefix>/share/myproj,将scripts/中的内容安装到
<prefix>/share/myproj
不包含目录名为CVS的目录,对于scripts/*文件指定权限为 OWNER_EXECUTE
OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ.

条件控制

1. if…elseif…else…endif

逻辑判断和比较:
if (expression):expression 不为空(0,N,NO,OFF,FALSE,NOTFOUND)时为真
if (not exp):与上面相反
if (var1 AND var2)
if (var1 OR var2)
if (COMMAND cmd):如果 cmd 确实是命令并可调用为真
if (EXISTS dir) if (EXISTS file):如果目录或文件存在为真
if (file1 IS_NEWER_THAN file2):当 file1 比 file2 新,或 file1/file2 中有一个不存在时为真,文件名需使用全路径
if (IS_DIRECTORY dir):当 dir 是目录时为真
if (DEFINED var):如果变量被定义为真
if (var MATCHES regex):给定的变量或者字符串能够匹配正则表达式 regex 时为真,此处 var 可以用 var 名,也可以用 ${var}
if (string MATCHES regex)

数字比较:
if (variable LESS number):LESS 小于
if (string LESS number)
if (variable GREATER number):GREATER 大于
if (string GREATER number)
if (variable EQUAL number):EQUAL 等于
if (string EQUAL number)

字母表顺序比较:
if (variable STRLESS string)
if (string STRLESS string)
if (variable STRGREATER string)
if (string STRGREATER string)
if (variable STREQUAL string)
if (string STREQUAL string)

示例:

    if(MSVC)
        set(LINK_LIBS common)
    else()
        set(boost_thread boost_log.a boost_system.a)
    endif()
    target_link_libraries(demo ${LINK_LIBS})
    # 或者
    if(UNIX)
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fpermissive -g")
    else()
        add_definitions(-D_SCL_SECURE_NO_WARNINGS
        D_CRT_SECURE_NO_WARNINGS
        -D_WIN32_WINNT=0x601
        -D_WINSOCK_DEPRECATED_NO_WARNINGS)
    endif()
     
    if(${CMAKE_BUILD_TYPE} MATCHES "debug")
        ...
    else()
        ...
    endif()

2. while…endwhile

    while(condition)
        ...
    endwhile()

3. foreach…endforeach

    foreach(loop_var RANGE start stop [step])
        ...
    endforeach(loop_var)

start 表示起始数,stop 表示终止数,step 表示步长,示例:

    foreach(i RANGE 1 9 2)
        message(${i})
    endforeach(i)
    # 输出:13579

常用变量

1. 预定义变量

PROJECT_SOURCE_DIR:工程的根目录
PROJECT_BINARY_DIR:运行 cmake 命令的目录,通常是 ${PROJECT_SOURCE_DIR}/build
PROJECT_NAME:返回通过 project 命令定义的项目名称
CMAKE_CURRENT_SOURCE_DIR:当前处理的 CMakeLists.txt 所在的路径
CMAKE_CURRENT_BINARY_DIR:target 编译目录
CMAKE_CURRENT_LIST_DIR:CMakeLists.txt 的完整路径
CMAKE_CURRENT_LIST_LINE:当前所在的行
CMAKE_MODULE_PATH:定义自己的 cmake 模块所在的路径,SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake),然后可以用INCLUDE命令来调用自己的模块
EXECUTABLE_OUTPUT_PATH:重新定义目标二进制可执行文件的存放位置
LIBRARY_OUTPUT_PATH:重新定义目标链接库文件的存放位置

2. 环境变量

使用环境变量

 $ENV{Name}

写入环境变量

 set(ENV{Name} value) # 这里没有“$”符号

3. 系统信息

CMAKE_MAJOR_VERSION:cmake 主版本号,比如 3.4.1 中的 3
CMAKE_MINOR_VERSION:cmake 次版本号,比如 3.4.1 中的 4
CMAKE_PATCH_VERSION:cmake 补丁等级,比如 3.4.1 中的 1
CMAKE_SYSTEM:系统名称,比如 Linux-2.6.22
CMAKE_SYSTEM_NAME:不包含版本的系统名,比如 Linux
CMAKE_SYSTEM_VERSION:系统版本,比如 2.6.22
CMAKE_SYSTEM_PROCESSOR:处理器名称,比如 i686
UNIX:在所有的类 UNIX 平台下该值为 TRUE,包括 OS X 和 cygwin
WIN32:在所有的 win32 平台下该值为 TRUE,包括 cygwin

4. 主要开关选项

BUILD_SHARED_LIBS:这个开关用来控制默认的库编译方式,如果不进行设置,使用 add_library 又没有指定库类型的情况下,默认编译生成的库都是静态库。如果 set(BUILD_SHARED_LIBS ON) 后,默认生成的为动态库
CMAKE_C_FLAGS:设置 C 编译选项,也可以通过指令 add_definitions() 添加
CMAKE_CXX_FLAGS:设置 C++ 编译选项,也可以通过指令 add_definitions() 添加
add_definitions(-DENABLE_DEBUG -DABC) # 参数之间用空格分隔

cmake指定特定版本gcc、g++

cmake -D CMAKE_C_COMPILER=/path/to/gcc/bin/gcc -D CMAKE_CXX_COMPILER=/path/to/gcc/bin/g++ 
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

cmake之CMakelist.txt的使用 的相关文章

随机推荐

  • UCOSII 信号量和信号量集实例

    代码来自于书本光盘 嵌入式操作系统UCOSII原理及应用 实例1信号量 include 34 includes h 34 define TASK STK SIZE 512 任务堆栈长度 OS STK StartTaskStk TASK ST
  • 正点原子MiniFly V1.2学习笔记一

    之前看过原子哥的FreeRTOS开发手册 xff0c 但是对整个项目 怎么架构还不是很清楚 由于最近工作需要上FreeRTOS xff0c 所以决定通过MiniFly来学习一下FreeRTOS的架构 一 main 函数 int main s
  • 正点原子MiniFly V1.2学习笔记三---atkpRxAnlTask

    第5个任务 解析处理接收到的指令 xTaskCreate atkpRxAnlTask 34 ATKP RX ANL 34 300 NULL 6 NULL 上面第1个任务 xff0c 把串口接收到的数据解包后得到指令 xff0c 然后把指令发
  • 正点原子MiniFly V1.2学习笔记五---sensorsTask

    这里先学习第8个任务sensorsTask xff0c 2 xff0c 3 xff0c 6 xff0c 7任务后面再学 xff0c 先学重要的 xTaskCreate sensorsTask 34 SENSORS 34 450 NULL 4
  • 嵌入式项目管理学习——001重点明确和心态转换

    相信做嵌入式的码哥们在参与一定数量的产品设计和生产之后 xff0c 都会发现一个问题 xff0c 如果没有一个负责的产品经理 xff0c 就会陷入到产品延期 沟通缺失 目标不清晰 需求不明确等等的问题 xff0c 我目前也是达到了这样一个状
  • 正点原子MiniFly V1.2学习笔记六---stabilizerTask

    第9个任务 xff0c 优先级5 xTaskCreate stabilizerTask 34 STABILIZER 34 450 NULL 5 NULL 一 任务函数 使用绝对延时 xff0c 周期执行任务 二 传感器数据是怎么传到这个任务
  • 正点原子MiniFly V1.2学习笔记七---configParamTask

    第6个任务 xff0c 优先级1 xff0c 最低优先级 配置参数任务 xTaskCreate configParamTask 34 CONFIG TASK 34 150 NULL 1 NULL 一 全局参数configParam 1 参数
  • C++码农要读的经典

    刚大四 xff0c 还在忙着找工作 xff0c 读过的书不是很多 xff0c 还有一些好书在读 xff0c 还有一些书将来必读 C语言程序设计 谭浩强版本 这个版本一致被人说误导子弟 xff0c 当然还有很多人推崇 我觉得这本书不是什么好书
  • 解读gazebo_ros_control gazebo_ros

    本篇的目的是想解读gazebo ros control 以及 gazebo ros 因为gazebo本身是独立于ros的 通过教程Intermediate Control plugin 以及教程 Category Write a plugi
  • vtaskstartscheduler(); //开启任务调度语句不执行

    项目场景 xff1a FreeRTOS实时嵌入式操作系统开发 基于stm32 第一章移植代码 问题描述 xff1a 任务调度器执行到vtaskstartscheduler 开启任务调度语句不执行 span class token keywo
  • python3中定义类变量,并使用类函数修改类变量的值

    定义类变量的方式有两种 1 在 init 中定义self elements 其中self elements是类变量名 a是传入Difference类的参数名 xff0c 这里的 init 作用是定义了类变量名 xff0c 将外部参数a传给类
  • printf函数的内涵以及造成的严重内存问题

    问题的引出 xff1a 在某型号的核心网络交换机设备中 xff0c 为调试方便 xff0c 实现了一个把内存内容从终端打印的功能 xff0c 也就是dump memory xff0c 屏幕的左边显示十六进制 xff0c 右边以ASCII形式
  • 关于docker那点事儿——Dockerfile编写

    Dockerfile编写 前言一 Dockerfile创建镜像二 Dockerfile常用指令三 示例1 Dockerfile构建nginx镜像2 Dockerfile构建微服务 四 CMD与ENTRYPOINT比较 前言 Dockerfi
  • SylixOS信号量(二进制信号量、 计数型信号量、 互斥信号量(简称互斥量)、 读写信号量)

    目录 二进制信号量 互斥信号量 计数器信号量 读写信号量 SylixOS 信号量 多个线程在读写某个共享数据 xff08 全局变量等 xff09 时必须通过某种方法实现共享数据的互斥访问或者同步访问 xff08 例如线程 B 等待线程 A
  • 什么是优先级反转及解决方法

    什么是优先级反转 优先级反转 xff0c 是指在使用信号量时 xff0c 可能会出现的这样一种不合理的现象 xff0c 即 xff1a 高优先级任务被低优先级任务阻塞 xff0c 导致高优先级任务迟迟得不到调度 但其他中等优先级的任务却能抢
  • STM32CubeMX在F103上的ADC注入通道配置异常问题

    前言 最近业余时间在搞无刷电机FOC的控制 xff0c 其中有一部分是关于流过电机三相绕组电流采集的 xff0c 需要用到STM32内置的ADC xff0c 核心是需要使用注入通道以确保ADC数据采集的实时性 xff0c 但是我在STM32
  • C++ static静态成员变量用法

    C 43 43 static静态成员变量用法 参考网址 xff1a 1 http c biancheng net cpp biancheng view 209 html 2 https www runoob com cplusplus cp
  • 解决AndroidStudio 控制台编译输出中文乱码,黑方块+问号之类的

    100 有效 解决AndroidStudio 控制台编译输出中文乱码 xff08 黑色方框问号 xff09 xff0c 亲测解决 xff01 xff08 转载 xff09 Pdx 666的博客 CSDN博客 背景在AndroidStudio
  • sphinx安装及简单使用

    sphinx安装及简单使用 如果你要编写技术文档 可以用 reStructuredText 或 Markdown 格式编辑文件 xff0c 然后使用 Sphinx 工具转换成 html PDF ePub等格式 xff0c 或者托管到 git
  • cmake之CMakelist.txt的使用

    文章目录 常用命令1 指定 cmake 的最小版本2 打印信息2 1 打印普通信息2 2 打印告警2 3 打印错误 3 项目名称4 设置变量5 查找指定的库文件6 设置包含的目录7 设置链接库搜索目录8 指定编译包含的源文件8 1 明确指定