CMakeList学习笔记

设置项目:project

project(planning VERSION 1.0.0 LANGUAGES CXX) # 项目的名字 版本 1.1.0 编程语言 CXX

设置包含目录:include_directories、targer_include_directories

设置编译类型:add_executable、add_library

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

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

在Linux平台:

demo (可执行文件)

libcommon.a (静态库)

libcommon.so (动态库)

在window平台:

demo.exe (可执行文件)

common.lib (静态库)

common.dll (动态库)

静态库与动态库的区别看Cmakelist知识总结-CSDN博客,这个博主讲的清楚。

总计如下:两者区别在链接阶段,静态链接器会将程序中使用到函数的代码从库文件中拷贝到应用程序中,即在内存中拷贝一份;动态链接在内存中只有一份,但仍需要共享库的支持。

设置变量的值 :set(变量名 变量值)

例:set(SRC_LIST main.cpp) 设置SRC_LIST的值为main.cpp

例:set( CMAKE_BUILD_TYPE "Debug" ) 设置 cmake 编译模式

添加可执行文件或库:add_executable

例:add_executable(my_program main.cpp)

可结合set使用

两个命令的作用对象不同:

include_libraries 命令用于指定项目中所有目标(包括可执行文件和库)的头文件搜索路径。

target_include_libraries 命令用于指定特定的目标(target)(可执行文件或库)的头文件搜索路径。

target_link_libraries(库文件名称/可执行文件名称 链接的库文件名称)

方法一:通过绝对路径指定链接库的位置

例:target_link_libraries(MyTarget PUBLIC path1 path2 ...)

PRIVATE:私有的,其他链接到my_program的库无法使用

PUBLIC:公有的,其他链接到my_program的库可以使用

命令中未指定任何限定符,默认情况下将应用 PUBLIC 限定符

方法二:通过相对路径指定链接库的位置

target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.a)

${CMAKE_CURRENT_SOURCE_DIR}/libs/mylibrary.lib 是相对于当前源代码目录的相对路径,指定了要链接的库文件位置

方法三(比较常用):使用自定义变量指定链接库的位置

set(MY_LIBRARY_PATH /path/to/custom/lib)

target_link_libraries(MyExecutable PRIVATE ${MY_LIBRARY_PATH}/libmylibrary.so)

方法四:使用 find_library() 命令查找链接库并且进行链接接操作

#find_library() 命令用于在指定的路径 /path/to/custom/lib 中查找名为 mylibrary 的库文件libmylibrary.so,并将结果保存在变量 MY_LIBRARY 中。然后,可以使用该变量来链接库。

find_library(MY_LIBRARY NAMES mylibrary PATHS /path/to/custom/lib)

target_link_libraries(MyExecutable PRIVATE ${MY_LIBRARY})
link_libraries(library1 library2)

link_libraries 命令的语法是直接列出需要链接的库的名称,多个库之间用空格分隔。

更适用于一次性链接多个库,并且不需要精细的目标控制的情况。它适用于简单的项目或需要快速链接库的情况。

记住唯一一种就行,target_link_libraries万能链接,要写在add_executable之后,作用于指定的目标。

添加子目录 :add_subdirectory

add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

查找指定依赖库文件:find_xxx

find_library() 用于查找库文件的路径

用于在系统或用户指定的路径 /path/to/custom/lib 中查找指定的库文件 libmylibrary.so,并将结果保存在变量 MY_LIBRARY中

通常用于查找并指定需要链接的库文件的路径,以便在后续的链接阶段使用

NAMES 可选参数

find_library(MY_LIBRARY NAMES mylibrary PATHS /path/to/custom/lib)

使用 MY_LIBRARY 作为默认的库文件名称进行查找,使用默认的系统搜索路径 /usr/lib, /usr/local/lib, /lib(/lib待验证)

find_library(MY_LIBRARY)

find_path() 用于查找头文件或文件夹的路径

用于在系统或用户指定的路径 /path/to/include1 /path/to/include2 中查找指定的头文件 myheader.h(或文件夹),并将结果保存在变量HEADER_PATH中

通常用于查找所需的头文件路径,以便在编译阶段使用

find_path(HEADER_PATH myheader.h PATHS /path/to/include1 /path/to/include2)

find_package() 用于查找和导入外部包的配置信息。

find_package命令有两种工作模式,这两种工作模式的不同决定了其搜包路径的不同:

  • Module模式( 默认工作模式**)**

Module模式基本语法

find_package(<package_name> [version] [EXACT] [QUIET] [MODULE] [REQUIRED] [COMPONENTS <component1> <component2> ...])

<package_name> 必填参数;需要查找的包名,注意大小写。例如 OpenCV、Boost 等

version 可选参数;指定所需的版本号

常见选项包括:

EXACT 可选参数;要求找到的包的版本与指定的版本完全匹配,必须完全匹配的版本而不是兼容版本

QUIET 可选参数; 静默模式,不会显示详细的查找信息,表示如果查找失败,不会在屏幕进行输出

REQUIRED 可选参数;要求找到指定的包,如果找不到会产生错误,停掉整个CMake。而如果不指定REQUIRED则CMake会继续执行,必须检查找到的包的版本是否和version兼容

COMPONENTS 可选字段; 指定要加载的包的组件,如果有任何一个找不到就算失败

MODULE 可选字段;"如果Module模式查找失败则回退到Config模式进行查找",但是假如设定了MODULE选项,那么就只在Module模式查找,如果Module模式下查找失败并不回落到Config模式查找。

  • Config模式( 高级工作模式**)**

只有在find_package()中指定CONFIGNO_MODULE 等关键字,或者Module 模式查找失败后才会进入到Config模式

其中具体查找库并给XXX_INCLUDE_DIRS和XXX_LIBRARIES两个变量赋值的操作由XXXConfig.cmake模块完成

两种模式看起来似乎差不多,不过CMake默认采取Module模式,如果Module模式未找到库,才会采取Config模式。如果XXX_DIR路径下找不到XXXConfig.cmake文件,则会找/usr/local/lib/cmake/XXX/中的XXXConfig.cmake文件。总之,Config模式是一个备选策略。通常,库安装时会拷贝一份XXXConfig.cmake到系统目录中,因此在没有显式指定搜索路径时也可以顺利找到。

具体查找顺序为:

1、名为<PackageName>_DIR的CMake变量或环境变量路径默认为空。

这个路径是非根目录路径,需要指定到<PackageName>Config.cmake文件所在目录才能找到。

2、名为CMAKE_PREFIX_PATH、CMAKE_FRAMEWORK_PATH、CMAKE_APPBUNDLE_PATH的CMake变量或环境变量路径根目录,默认都为空。

#注意如果你电脑中安装了ROS并配置好之后,你在终端执行echo $CMAKE_PREFIX_PATH会发现ROS会将CMAKE_PREFIX_PATH这个变量设置为ROS中的库的路径/opt/ros/noetic,意思是会首先查找ROS安装的库,如果恰好你在ROS中安装了OpenCV库,就会发现首先找到的是ROS中的OpenCV,而不是你自己安装到系统中的OpenCV。

3、PATH环境变量路径根目录,默认为系统环境PATH环境变量值。

其实这个路径才是Config模式大部分情况下能够查找到安装到系统中各种库的原因。

这个路径的查找规则为:遍历PATH环境变量中的各路径,如果该路径如果以bin或sbin结尾,则自动回退到上一级目录得到根目录。

打印:message

message(打印内容)

message(STATUS "OpenCV library status:")

STATUS 是打印 -- 用来区分这是完整运行一条语句后的分割

例:find_package(Eigen3 REQUIRED)

message(STATUS "Eigen3_INCLUDE_DIR = ${EIGEN3_INCLUDE_DIR}")

结果为:

加了STATUS

-- Eigen3_INCLUDE_DIR = /usr/include/eigen3

没加STATUS

Eigen3_INCLUDE_DIR = /usr/include/eigen3

添加编译选项

添加编译选项(add_definitions的功能和C/C++中的#define是一样的)

add_definitions(编译选项)

添加编译选项,包括使用C++11标准、启用调试信息和生成位置无关代码

add_compile_options(-std=c++11 -g -fPIC)

设定最低版本

例:cmake_minimum_required(VERSION 3.4.0)

条件控制

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 ISNEWER 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)

while ...endwhile

例:while(condition)

...

endwhile

foreach...endforeach

例:foreach(loop_var RANGE start stop [step])

...

endforeach

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

相关推荐
HinsCoder28 分钟前
【渗透测试】——Upload靶场实战(1-5关)
笔记·学习·安全·web安全·渗透测试·测试·upload靶场
听风若依31 分钟前
排序学习笔记
笔记·学习
Filotimo_35 分钟前
【自然语言处理】实验三:新冠病毒的FAQ问答系统
人工智能·经验分享·笔记·python·学习·自然语言处理·pycharm
IM_DALLA42 分钟前
【Verilog学习日常】—牛客网刷题—Verilog快速入门—VL21
学习·fpga开发
狐心kitsune44 分钟前
erlang学习:Linux常用命令1
linux·学习·erlang
小游鱼KF1 小时前
Spring学习前置知识
java·学习·spring
mez_Blog1 小时前
个人小结(2.0)
前端·javascript·vue.js·学习·typescript
Rookie也要加油2 小时前
WebRtc一对一视频通话_New_peer信令处理
笔记·学习·音视频·webrtc
David猪大卫2 小时前
数据结构修炼——顺序表和链表的区别与联系
c语言·数据结构·学习·算法·leetcode·链表·蓝桥杯
honey ball2 小时前
仪表放大器AD620
运维·单片机·嵌入式硬件·物联网·学习