1.“~” 表示主目录,也就是当前登录用户的用户目录

比如用户是“zheng”,则mac电脑的用户目录就是/users/zheng;

2.“/”是指根目录,所有目录最顶层的目录;

3.“./”表示当前目录,一般和其他文件夹或者文件结合使用,指当前目录下的东西.

CMake Reference Documentation — CMake 3.28.0-rc2 Documentation

这个是官方文档,英语好的,已经有基础的可以直接看这个

Linux下CMake简明教程_爱就是恒久忍耐的博客-CSDN博客_cmake

CMake教程(常见变量)_project_source_dir_开始沸腾了的博客-CSDN博客

  • CMakeLists:在catkin_make期间生成文件,如xxxConfig.Cmake导出本包的资源 加入到catkin_INCLUDE_DIRScatkin_LIBRARIESfind_package本包依赖所需依赖(包含依赖包并不会递归其依赖的子包为依赖,因为CMakeLists是独立的)

  • Package.xml:是了解一个包的所有入口,依赖项可以用来解决包之间的编译和执行顺序,包含某个包会自动递归其所依赖的子包作为依赖

  • 因此在Package.xml声明依赖(包间依赖关系)和CMakeLists中find_package(包所需依赖)都要有,否则前者导致编译顺序出错,后者导致无头文件目标文件链接失败

  • CMakeLists.txt是cmake编译框架下的文件,而catkin是cmake加入了一些宏命令来适配ROS(个人理解)。因此在CMakeLists中写入catkin支持的宏如catkin_package add_service_files generate_messages等会自动帮你生成一些文件

  • package.xml才是ROS包的命根子,无论是rospack rosruncatkin_make等ros中用的命令,甚至是roslaucnh 中的$(find package)都是通过搜索ros_path下的所有文件夹中的package.xml的。然后通过该文件来获取程序包信息。

流程

main

库的头文件导入

生成可执行文件

库的可执行文件链接

头文件导入

库文件

生成动态链接库(.c)

头文件导入(.h)

文件夹命名规则

build

cmake的地方

lib

编译生成的库文件存放处

bin

二进制文件存放的地方,也就是可执行文件

常用命令

set

Cmake入门之——Set方法(六)_cmake cache string_PGzxc的博客-CSDN博客

用来将一些文件 和一个自定义名称绑定

1
set(OpenCV_DIR /home/xing/opencv-4.5.3/build)

用于简洁代码作用和aux_source_directory一样

aux_source_directory(dir var)

第一个参数dir是指定目录,第二个参数var是用于存放源文件列表的变量。

1
2
3
4
5
6
7
8
9
cmake_minimum_required (VERSION 2.8)

project (demo)

aux_source_directory(. SRC_LIST)


add_executable(main ${SRC_LIST})

install

cmake使用教(二) install的使用_cmakelist install-CSDN博客

用于配置安装路径

1
2
3
4
5
INSTALL(TARGETS myrun mylib mystaticlib
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION libstatic
)

上面的例子会将:

可执行二进制myrun 安装到${CMAKE_INSTALL_PREFIX}/bin 目录

动态库libmylib安装到${CMAKE_INSTALL_PREFIX}/lib目录

静态库libmystaticlib 安装到${CMAKE_INSTALL_PREFIX}/libstatic目录

特别注意的是你不需要关心TARGETS具体生成的路径,只需要写上TARGETS名称就可以

了。

要写成相对路径,即不要以/开头

如果不填数据类型就默认是二进制

指定安装路径

include_directories

作用的target_include_library类似,官方推荐使用后者。

这个相对target_include_library的区别在于这个是直接给这个工程提供头文件路径,而include_directories是给具体的目标添加头文件,比如已经生成的库文件

该命令是用来向工程添加多个指定头文件的搜索路径,路径之间用空格分隔。

1
2
3
4
5
6
7
8
9
10
cmake_minimum_required (VERSION 2.8)

project (demo)

include_directories (test_func test_func1)

aux_source_directory (test_func SRC_LIST)
aux_source_directory (test_func1 SRC_LIST1)

add_executable (main main.c ${SRC_LIST} ${SRC_LIST1})

add_executable

使用指定的源文件创建出一个可执行文件

CMake系列讲解(入门篇)1.4 基础命令CMake-add_executable()_在下马农的博客-CSDN博客_cmake add_ex

1
2
3
4
5
6
7
8
9
10
11
12
cmake_minimum_required (VERSION 2.8)

project (demo)

include_directories (test_func test_func1)

aux_source_directory (test_func SRC_LIST)
aux_source_directory (test_func1 SRC_LIST1)

add_executable (main main.c ${SRC_LIST} ${SRC_LIST1})


add_subdirectory

作用是添加编译子目录

add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

一共有三个参数,后两个是可选参数.

source_dir 源代码目录

指定一个包含CMakeLists.txt和代码文件所在的目录,该目录可以是绝对路径,也可以是相对路径,对于后者相对路径的起点是CMAKE_CURRENT_SOURCE_DIR。此外,如果子目录再次包含的CMakeLists.txt,则将继续处理里层的CMakeLists.txt,而不是继续处理当前源代码。

binary_dir 二进制代码目录

这个目录是可选的,如果指定,cmake命令执行后的输出文件将会存放在此处,若没有指定,默认情况等于source_dir没有进行相对路径计算前的路径,也就是CMAKE_BINARY_DIR。

EXCLUDE_FROM_ALL标记

这个标志是可选的,如果传递了该参数表示新增加的子目录将会排除在ALL目录之外(可能是make系统中的make all?),表示这个目录将从IDE的工程中排除。用户必须显式在子文件这个编译目标(手动cmake之类的)。指定了这个文件夹,表示这个文件夹是独立于源工程的,这些函数是有用但是不是必要的,比如说我们一系列的例子。

1
2
3
4
5
6
cmake_minimum_required (VERSION 2.8)

project (demo)

add_subdirectory (src)

1
2
3
4
5
6
7
8
aux_source_directory (. SRC_LIST)

include_directories (../include)

add_executable (main ${SRC_LIST})

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

find_package

作用

他主要是寻找.cmake文件。根据.cmake生成对应的头文件目录和库文件路径。

我看了几个.cmake文件。里面有对于路径的定义 比如OpenCV_INCLUDE_DIRS

不管哪种方式安装的库文件,如果我们需要自己的项目中使用这些库,首先面临的第一个问题就是如何找到这些库。所谓“找到”这些库,其实是根据我们的需要找到指定版本的库头文件包含路径、链接库路径等,从而能够满足我们开发项目的编译链接需要。

是用于查找当前功能包所依赖的包

1
2
3
4
5
6
7
8
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
# 需要加入 message_generation,必须有 std_msgs

1
2
3
4
5
6
7
set(CMAKE_CXX_COMPILER /usr/bin/g++)
set(Eigen3_DIR /home/dji/apps/eigen-3.4.0/cmake)
SET(OpenCV_DIR /home/dji/apps/opencv-4.5.3/cmake)
# set(CMAKE_BUILD_TYPE "Debug")
FIND_PACKAGE(OpenCV REQUIRED)
FIND_PACKAGE(Eigen3 REQUIRED)

1
2
3
4
5
6
7
8
9
10
11
set(OpenCV_INCLUDE_DIRS "")
foreach(d ${__OpenCV_INCLUDE_DIRS})
get_filename_component(__d "${d}" REALPATH)
if(NOT EXISTS "${__d}")
if(NOT OpenCV_FIND_QUIETLY)
message(WARNING "OpenCV: Include directory doesn't exist: '${d}'. OpenCV installation may be broken. Skip...")
endif()
else()
list(APPEND OpenCV_INCLUDE_DIRS "${__d}")
endif()
endforeach()

从这些路径之后可以直接找到动态库或者静态库的位置。之后执行target_link_libraries

有两种配置方式。一种是set,一种是list

他会到这两个配置方式指定的路径下进行搜索

如果没有配置set list

他会直接从默认路径中进行寻找默认路径

find_library

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
cmake_minimum_required (VERSION 3.5)

project (demo)


set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

set (SRC_LIST ${PROJECT_SOURCE_DIR}/src/main.c)

# find testFunc.h
include_directories (${PROJECT_SOURCE_DIR}/testFunc/inc)

find_library(TESTFUNC_LIB testFunc HINTS ${PROJECT_SOURCE_DIR}/testFunc/lib)

add_executable (main ${SRC_LIST})

target_link_libraries (main ${TESTFUNC_LIB})

在指定目录下查找指定库,并把库的绝对路径存放到变量里,其第一个参数是变量名称,第二个参数是库名称,第三个参数是HINTS,第4个参数是路径,其它用法可以参考cmake文档

add_library

生成对象库(也就是.so或者.a文件)

windows下就是dll和lib文件

1
add_library(hello hello.cpp)

target_include_directories

可执行文件生成的库中添加头文件目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cmake_minimum_required (VERSION 3.12.1)

project (Demo)

# 生成对象库文件
add_library(hello hello.cpp)

# 添加头文件目录
target_include_directories(hello PUBLIC ${CMAKE_SOURCE_DIR}/public)

# 生成可执行文件
add_executable(Demo main.cpp)

# 链接对象库
target_link_libraries(Demo hello)

target_link_directories

这个和下面target_link_libraries的区别在于

target_link_directories是链接库的目录

target_link_libraries是链接库

1
target_link_directories(mytarget PUBLIC /path/to/mylib)

link_library

历史遗留物

也是用来将main可执行文件与动态库进行链接的,不过由于无法明确链接的是谁,所以目前cmake官方不推荐使用

target_link_libraries

指定链接给定目标和/或其依赖项时要使用的库。命名的 <font style="color:rgb(77, 77, 77);"><tartget></font> 必须是由<font style="color:rgb(77, 77, 77);">add_executable()</font>或add_library()之类的命令创建的。一般与 link_directories连用(添加外部库的搜索路径 )

链接对象库到可执行文件(一般是这样的)

1
2
3
4
5
## Specify libraries to link a library or executable target against
#指定库、可执行文件的链接库
target_link_libraries(Hello_VSCode
${catkin_LIBRARIES}
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cmake_minimum_required (VERSION 3.12.1)

project (Demo)

# 生成对象库文件
add_library(hello hello.cpp)

# 添加头文件目录
target_include_directories(hello PUBLIC ${CMAKE_SOURCE_DIR}/public)

# 生成可执行文件
add_executable(Demo main.cpp)

# 链接对象库
target_link_libraries(Demo hello)

target_complie_options

对象库添加编译选项

1
target_compile_options(hello PUBLIC -Wall)

add_compile_option

这个是用来添加编译选项的

1
2
3
4
5
6
7
8
9
10
cmake_minimum_required (VERSION 2.8)

project (demo)

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

add_compile_options(-std=c++11 -Wall)

add_executable(main main.cpp)

option

类似添加宏定义,用于条件编译,就是满足条件才编译这个文件,甚至可以直接控制程序的输出(这里功能和宏定义相同)

1
2
3
4
5
6
7
8
9
10
cmake_minimum_required(VERSION 3.5)

project(demo)

option(MYDEBUG "enable debug compilation" OFF)

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

add_subdirectory(src)

这里使用了option命令,其第一个参数是这个option的名字,第二个参数是字符串,用来描述这个option是来干嘛的,第三个是option的值,ON或OFF,也可以不写,不写就是默认OFF。

然后编写src目录下的CMakeLists.txt,如下:

1
2
3
4
5
6
7
8
9
10
cmake_minimum_required (VERSION 3.5)

add_executable(main1 main1.c)

if (MYDEBUG)
add_executable(main2 main2.c)
else()
message(STATUS "Currently is not in debug mode")
endif()

<font style="color:rgb(77, 77, 77);">cmake … -DMYDEBUG=ON</font>这条命令可以直接往设定的宏输入数据

add_definitions

这个主要使用修改输出的宏名称,保留原来名称,这里更像是取个别名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cmake_minimum_required(VERSION 3.5)

project(demo)

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

option(WWW1 "print one message" OFF)
option(WWW2 "print another message" OFF)

if (WWW1)
add_definitions(-DWWW1)
endif()

if (WWW2)
add_definitions(-DWWW2)
endif()

add_executable(main main.c)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>

int main(void)
{
#ifdef WWW1
printf("hello world1\n");
#endif

#ifdef WWW2
printf("hello world2\n");
#endif

return 0;
}

ros相关命令

add_service_files(这一步区别于话题通信,其用的是add_message_files指定msg文件

将创建的src文件夹加入,目的是使其在srv目录下寻找srv文件

1
2
3
4
5
add_service_files(
FILES
AddInts.srv
)

generate_messages

指定生成消息文件时的依赖项

srv文件中利用到了标准数据,所以需要std_msgs

1
2
3
4
5
generate_messages(
DEPENDENCIES
std_msgs
)

catkin_package

声明依赖的包的依赖

CATKIN_DEPENDS 选项和 DEPENDS 选项十分相似,但是你只能在其列表中放置 catkin 程序包。将 catkin 依赖设置为一个单独的选项的好处是可以让 catkin 执行一些额外的检查,然后警告你有什么不妥的做法。

catkin_package是给下游(使用该包的包)使用的,它用于向其他包导出依赖,这些依赖可能是本包给其他包提供的公共头文件、库,或者是本包依赖的其他包。

1
2
3
4
5
6
7
8
9
## The catkin_package macro generates cmake config files for your package
## Declare things to be passed to dependent projects
## INCLUDE_DIRS: uncomment this if you package contains header files
## LIBRARIES: libraries you create in this project that dependent projects also need
## CATKIN_DEPENDS: catkin_packages dependent projects also need
## DEPENDS: system dependencies of this project that dependent projects also need
## CFG_EXTRAS: Additional configuration options
catkin_package(...

DEPENDSCATKIN_DEPENDS 用来告诉 catkin 需要将你程序包的哪些依赖项,传递给使用 find_package(…) 查找你的程序包的程序包。

CATKIN_DEPENDS 选项和 DEPENDS 选项十分相似,但是你只能在其列表中放置 catkin 程序包。将 catkin 依赖设置为一个单独的选项的好处是可以让 catkin 执行一些额外的检查,然后警告你有什么不妥的做法。

是当前功能包所依赖的包所依赖的包

1
2
3
4
5
6
7
8
#执行时依赖
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES demo02_talker_listener
CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
# DEPENDS system_lib
)

add_dependencies

保证编译的文件逻辑问题不出错,举例:让自定义文件先运行,源文件后编译

  • 添加add_dependencies(res myMath),意思就是告诉编译器,我知道生成res程序要链接myMath这个库文件,但是现在我还没有这个库文件,你先生成res,我随后就把库文件myMath给你生成出来。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#指定cmake最低版本
cmake_minimum_required(VERSION 3.14)

#指定头文件位置
include_directories(${PROJECT_SOURCE_DIR}/lib)

#设置可执行文件生成目录
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

#生成可执行文件
add_executable(res ${PROJECT_SOURCE_DIR}/src/main.cpp)

#指定依赖
add_dependencies(res myMath)

#链接动态库
target_link_libraries(res ${PROJECT_BINARY_DIR}/bin/libmyMath.so)

预定义变量

catkin_LIBRARIES

catkin的基础库

如果cpp中用到第三方插件,需要在这里进行target_link 链接到第三方库文件,现在链接的库是catkin的基础库

1
2
target_link_libraries(talker  ${catkin_LIBRARIES} )

project_name

也就是功能包的名字

project的名字

EXECUTABLE_OUTPUT_PATH

目标二进制可执行文件的存放位置

1
2
3
4
5
6
7
aux_source_directory (. SRC_LIST)

include_directories (../include)

add_executable (main ${SRC_LIST})

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

常用操作

编译单个文件

VSCode编译单文件及多文件方法(基于g++,cmake,json三种方法)_vscode 多文件编译_DogDog_Shuai的博客-CSDN博客

一.改cmakelisets.txt

1
2
3
4
project(MYSWAP)//起一个项目名

add_executable(my_cmake_swap main.cpp swap.cpp)//一个是生成的可执行文件名字,其他参数是要加入编译的的cpp文件

这个意思就是生成可执行文件只参考一个文件

二.改task.json

系统自动生成的task文件默认是单文件调试,所以可以修改task.json的args部分,修改后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{
"version": "2.0.0",
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: g++.exe 生成活动文件",
"command": "D:\\mingw\\bin\\g++.exe",
"args": [
"-fdiagnostics-color=always",
"-g",
"main.cpp",//改了这里
"swap.cpp",//改了这里
"-o",
"${fileDirname}\\out.exe"//改了这里,改成想输出的文件的名字
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": "build",
"detail": "编译器: D:\\mingw\\bin\\g++.exe"
}
]
}

概念辨析

catktin_make和cmake的区别

https://www.cnblogs.com/Jessica-jie/p/6706513.html

caktin_make 就是将cmake 和make命令进行了封装

cmak 不会找package.xml文件, 但catkin需要. 依据cmakelists.txt文件编译需要清晰指出头文件和库文件的指向.

catkin_make编译指定的包

1
$ catkin_make -DCATKIN_WHITELIST_PACKAGES="package1;package2"

恢复编译所有的包

1
$ catkin_make -DCATKIN_WHITELIST_PACKAGES=""

catkin_make和catkin build 的区别

catkin build的行为类似于并行版本的catkin_make_isolatied

catkin build 就是会将pkg独立编译,而catkin_make 不会

相比catkin_make的一个改进是将工作空间下的所有的pkg进行独立编译,缺点就是编译时间比catkin_make更长。

make install

make&& make install的意思_make && make install-CSDN博客

make是编译的意思。就是把源码包编译成二进制可执行文件,make去找Makefile
make install 就是安装的意思。它也从Makefile中读取指令,然后安装到指定的位置。

源码包的安装分成一下几个过程:

  1. Tar:解压这个源码软件包。
  2. Cd:进入到这个源码包。
  3. ./configure:“configure”会在你的系统上测试存在的特性(或者bug!)然后来建立Makefile文件来完成make!
  4. Make:编译程序。
  5. Make install:安装文件!

make&& make install的意思是:
make与makeinstall是两个命令,在你./configuration生成了Makefile之后执行编译安装;
这里的./configuration用来生成makefile,这是个脚本文件,有cmake


与&&一起的还有||,不过意思不一样,&&是与,||是或;
make && makeinstall的意思就是执行make如果没有发生错误就执行make install