Beginner

Grammar

  • 指令大小写无关(如 add_library 等价于 ADD_LIBRARY

  • 参数和变量、OPTION大小写敏感(如REQUIRED不能写成required)

Alias target

  • target,根据上下文,应该指的是library这种target,而不是executable file;且是 alias target ;采用 taget-based 的方法可以不用再include_directory ,只需要 target_link_libraries 就能完成编译(link

  • 案例1:

img

等价于

img img img

Macro

add_dependencies

  • 指明依赖:即指明在target生成前,需要先生成某些target

add_dependencies(<target> [<target-dependency>]...)

add_definitions

  • 添加宏

add_definitions(-DPERFORMANCE_LOG)

add_executable

  • 构建可执行文件

add_executable(target_name 文件名)

add_library

  • 构建库文件,构建的 library 可以不写全名字,如只写hello,cmake会自动补全为 libhello.solibhello.a

add_library(target_name STATIC 文件名)     # 静态库
add_library(target_name SHARED 文件名)     # 动态库
add_library(target_name OBJECT 文件名)     # 生成目标文件但是不进行链接

cuda

cuda_add_executable(target_name <...cu>)
cuda_add_library(target_name <library_name>)

compile_options

  • 编译项

# 设置相关标准
set(CMAKE_CXX_STANDARD 17) # 具有最强的覆盖作用
add_compile_options(-std=c++14)

# 设置DEBUG时的编译选项
SET(CMAKE_BUILD_TYPE "RELEASE")
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O0 -g")
# 设置DEBUG时的编译选项
SET(CMAKE_BUILD_TYPE "DEBUG")
SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O3 -Wall")

# 设置GDB编译项
add_compile_options("-O0" "-g") # for gdb(注意一项对应一个编译项)
target_compile_options(<target_name> PUBLIC "-O0" "-g")

# 保留中间产物
target_compile_options(<target_name> PUBLIC "-save-temps")

# 屏蔽deprecated消息
set(CMAKE_CXX_FLAGS "-Wno-error=deprecated-declarations -Wno-deprecated-declarations")

# -Wno-deprecated
# -march=native:使用本机的编译指令(代码运行速度或会提高)

# 设置优化项
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O3")

备注

该选项会覆盖CMAKE_BUILD_TYPE

备注

add_compile_options() 作用于所有编译器, CMAKE_CXX_FLAGSCMAKE_C_FLAGS 分别只针对c++,c编译器

optimization

-O0:(default) 屏蔽所有的优化
-0g:suppresses many optimization passes
-O3:优化等级为3
CMAKE_BUILD_TYPE:
-O3:Release
-O0:for Debug
-Os:for MinRelSize

warning

# -Wconversion: e.g double -> float (narrowing conversion)

configure_file

  • 拷贝一个文件,并用cmake文件的变量替换输入文件中形如@VAR@${VAR}的变量

  • 让普通文件使用CMake的变量

configure_file(
  ${PROJECT_SOURCE_DIR}/header.hpp.in
  ${PROJECT_SOURCE_DIR}/include/global_definition/header.hpp)
  • 用例可参考任老的仓库(detail

execute_process

  • 执行命令行

# 相关待执行的命令; 存储标准输出的变量
execute_process(COMMAND python -c "from sysconfig import get_paths;print(get_paths()['include'])" OUTPUT_VARIABLE DUMMY)
execute_process(COMMAND python3 -c "import torch; print(f'{torch.utils.cmake_prefix_path}/Torch', end='')" OUTPUT_VARIABLE Torch_DIR)

file

  • 使用通配符找文件

# e.g. file(GLOB source_files ${TENSORRT_INSTALL_DIR}/samples/common/*.cpp)
file(GLOB <outPUT-var> [<globbing-expr>...])

find_library

# find_library (<VAR> name1 [path1 path2 ...])
find_library(NVPARSERS NAMES nvparsers)
find_library(NVCAFFE_PARSER NAMES nvcaffe_parser)
find_library(NVINFER_PLUGIN NAMES nvinfer_plugin)
  • 要添加搜索路径,可修改CMAKE_LIBRARY_PATHCMAKE_PREFIX_PATH

# e.g.
set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "$ENV{HOME}/application/TensorRT-8.0.0.3/lib")

find_package

find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE]
             [REQUIRED] [[COMPONENTS] [components...]]
             [OPTIONAL_COMPONENTS components...]
             [NAMES name1 [name2 ...]]
             # If the NAMES option is given the names following it are used instead of <PackageName>
             [NO_POLICY_SCOPE])
  • 指定路径

find_package(PCL REQUIRED
PATHS  库路径
NO_DEFAULT_PATH)  # 只在PATHS路径下寻找,不使用默认的搜索路径
  • find_package宏执行后会产生相关的变量,例如,<package_name>_INCLUDE_DIRS or <package_name>_INCLUDES or <package_name>_INCLUDE_DIR 具体看相关模块的设计

  • cmake modules 指文件FindXXX.cmake,要指定 cmake module的搜索路径,可以配置如下参数;不过它也有默认的搜索路径即cmake安装路径下的Module目录(e.g. /usr/share/cmake-3.16/Modules),在默认路径下没找到,才去CMAKE_MODULE_PATH下找

set(CMAKE_MODULE_PATH 路径名)
# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "/usr/share/cmake/geographiclib/")
  • find_packaege还有一种Config Mode,当没找到FindXXX.cmake时将按特定的规则进行搜寻,具体可参考英文文档中文说明(PATH环境变量也会起作用),

  • 该种模式下找的是... LibConfig.cmake...lib_config.cmake。可添加的搜索路径为

<package>_DIR
CMAKE_PREFIX_PATH
CMAKE_FRAMEWORK_PATH
CMAKE_APPBUNDLE_PATH
PATH

function

  • 自定义函数

# abstract from https://github.com/tier4/AutowareArchitectureProposal.iv/blob/use-autoware-auto-msgs/perception/object_recognition/detection/lidar_centerpoint/CMakeLists.txt

function(download FILE_NAME GFILE_ID FILE_HASH)
# https://drive.google.com/file/d/GFILE_ID/view
message(STATUS "Checking and downloading ${FILE_NAME}")
set(FILE_PATH ${DATA_PATH}/${FILE_NAME})
if(EXISTS ${FILE_PATH})
    file(MD5 ${FILE_PATH} EXISTING_FILE_HASH)
    if(NOT ${FILE_HASH} EQUAL ${EXISTING_FILE_HASH})
    message(STATUS "... file hash changes. Downloading now ...")
    execute_process(COMMAND gdown --quiet https://drive.google.com//uc?id=${GFILE_ID} -O ${FILE_PATH})
    endif()
else()
    message(STATUS "... file doesn't exists. Downloading now ...")
    execute_process(COMMAND gdown --quiet https://drive.google.com//uc?id=${GFILE_ID} -O ${FILE_PATH})
endif()
endfunction()

# default model
download(pts_voxel_encoder_default.onnx 1_8OCQmrPm_R4ZVh70QsS9HZo6uGrlbgz 01b860612e497591c4375d90dff61ef7)

include_directories

  • 添加链接库文件搜索路径(文件夹)

方法一:

# 当前包的头文件目录要放在前面
include_directories(
 include  # 相对于当前CMakeLists所在的文件目录
 ${catkin_INCLUDE_DIRS}
)
  • 控制追加的路径是放在原来的前面还是后面(设置参数 ON)

set(cmake_include_directorirs_before ON)
set(cmake_include_directorirs_after ON)

提示

#include <file.h> 时对应的位置是相对于 include_directories 中导入的路径例如: include_directories 的路径是/include/;头文件在/include/package_name/header.h则最终的编写应为 #include <package_name/header.h>

方法二:

target_include_directories(target_name
    PUBLIC
        头文件目录)

方法二的头文件路径仅适用特定的 target ,方法一的适用于所有 target

link_directories

  • 添加链接库文件搜索路径(文件夹),不起链接作用

link_directories(dir_path)

list

  • 正则移除catkin_LIBRARIES中的系统pcl库

# remove pcl installed from apt
list(FILTER catkin_LIBRARIES EXCLUDE REGEX /usr/lib/x86_64-linux-gnu/libpcl*)
list(FILTER catkin_LIBRARIES EXCLUDE REGEX optimized)
list(FILTER catkin_LIBRARIES EXCLUDE REGEX debug)

list(FILTER catkin_INCLUDE_DIRS EXCLUDE hREGEX /usr/include/pcl-1.8)

message

message(STATUS|WARNING|FATAL|SEND_ERROR ${})# 这种形式一定要加STATUS这些option
message("...")

# 显示列表数据时带分隔符;
message("${...}")
# 替换分隔符
string(REPLACE ";"  ", " new_str "${old_str}")

properties

  • 修改属性

set_target_properties(target1 target2 ...
                      PROPERTIES prop1 value1
                      prop2 value2 ...)
set_property(<GLOBAL                      |
              DIRECTORY [<dir>]           |
              TARGET    [<target1> ...]   |
              SOURCE    [<src1> ...]
                        [DIRECTORY <dirs> ...]
                        [TARGET_DIRECTORY <targets> ...] |
              INSTALL   [<file1> ...]     |
              TEST      [<test1> ...]     |
              CACHE     [<entry1> ...]    >
             [APPEND] [APPEND_STRING]
             PROPERTY <name> [<value1> ...])
  • 修改文件生成名前/后缀等

set_target_properties(lib_cpp PROPERTIES PREFIX "")               #  指定前缀
set_target_properties(lib_cpp PROPERTIES OUTPUT_NAME "lib_cpp")   #  指定文件名
set_target_properties(lib_cpp PROPERTIES SUFFIX ".so")            #  指定后缀
set_target_properties(lib_cpp PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})  # 指定库的输出路径
set_target_properties(lib_cpp PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})  # 指定可执行文件的输出路径

原来默认生成 lib_cpp.cpython-37m-x86_64-linux-gnu.so 现在是 lib_cpp.so ;更多属性配置可参考link

option

option(<variable> "<help_text>" [value])

set

设置变量

set(SOURCES
    src/Hello.cpp
    src/main.cpp
)
message(${SOURCES})   # src/Hello.cppsrc/main.cpp
set(ENV{变量名} )    # 获取环境变量(注意ENV需要大写)
message($ENV{HOME})   # 使用环境变量

提示

单个variable有多个arguments时,用分号将argument进行concatenate后再进行赋值;然而message显示时,不会出现分号;使用一个变量时,不同于 bash可以不加上{},在 CMakelists中一定要加上

include

  • 导入额外的cmake文件

  • 方法一:

include(<file|module> [OPTIONAL] [RESULT_VARIABLE <var>]
                      [NO_POLICY_SCOPE])

从某个文件(CMakeLists.txt)或模块(.cmake)中导入cmake代码;未指定地址时,首先在内置的模块库目录下寻找( CMake builtin module directory ),其次在CMAKE_MODULE_PATH中寻找

set(VTK_CMAKE_DIR "${VTK_SOURCE_DIR}/CMake")
set(CMAKE_MODULE_PATH ${VTK_CMAKE_DIR} ${CMAKE_MODULE_PATH})
include(vtkCompilerChecks)  # /VTK-8.2.0/CMake/vtkCompilerChecks.cmake
  • 方法二:导入CMakeLists.txt,source_dir对应CMakeLists.txt的所在目录

add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
  • includeadd_subdirectory的区别?(details)

add_subdirectory会有不同的变量作用域;

外面的编译选项会传递到add_subdirectory中(子工程可以覆盖它)

install

  • 可以安装的内容:编译产生的target文件(即可执行文件、库文件);其他文件

  • 若要指定安装路径:

方法一:命令行

cmake .. -DCMAKE_INSTALL_PREFIX=install

方法二:cmake-gui等图形界面进行:

img
  • 指定安装的内容和相对路径:

# 安装可执行文件,并安装到到指定目录:${CMAKE_INSTALL_PREFIX}/bin
install (TARGETS <target_name>
    DESTINATION bin)

# 安装库文件,并安装到指定目录:${CMAKE_INSTALL_PREFIX}/lib
install (TARGETS <target_name>
    LIBRARY DESTINATION lib)

# 安装库文件(挪整个文件夹),并安装到指定目录:${CMAKE_INSTALL_PREFIX}/include
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/
    DESTINATION include)

# 安装配置文件,拷贝到:${CMAKE_INSTALL_PREFIX}/etc
install (FILES <file_name>
    DESTINATION etc)

# ROS2
install(
  DIRECTORY include/
  DESTINATION include
)

# ROS_PKG/lib
# ROS_PKG/bin
# ROS_PKG/include
install(
  TARGETS my_library
  EXPORT my_libraryTargets
  LIBRARY DESTINATION lib
  ARCHIVE DESTINATION lib
  RUNTIME DESTINATION bin
  INCLUDES DESTINATION include
)
  • make install后 CMake 会生成install_manifest.txt文件(含安装的文件路径,到时可基于这个文件删除安装文件)

e.g.
/usr/local/include/ceres/autodiff_cost_function.h
/usr/local/include/ceres/autodiff_first_order_function.h
/usr/local/include/ceres/autodiff_local_parameterization.h

提示

默认安装路径: /usr/local/include ; /usr/local/bin ; /usr/local/lib/cmake

ament

  • ament_target_dependenciestarget_link_libraries 更具优势,It will also ensure that the include directories of all dependencies are ordered correctly when using overlay workspaces

find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
# 链接库
ament_target_dependencies()
# 导出库
ament_export_targets()
ament_export_dependencies()
# The project setup is done by ament_package() and this call must occur exactly once per package. ament_package() installs the package.xml, registers the package with the ament index, and installs config (and possibly target) files for CMake so that it can be found by other packages using find_package
ament_package()

ament auto

ament的高级封装

find_package(ament_cmake_auto REQUIRED)
# automatically link the dependency according to the xml (without find_package)
ament_auto_find_build_dependencies()

# 生成目标文件
ament_auto_add_library(listener_node SHARED src/listener_node.cpp)
ament_auto_add_executable(listener_node_exe src/listener_main.cpp)

# replace the export, install and ament_package command
ament_auto_package()

catkin_package

  • 官方文档 wiki官方文档 api

  • 作用:安装package.xml;生成可被其他package调用的配置文件(即.config或.cmake文件)。使其他包find_package时可以获取这个包的相关信息,如依赖的头文件、库、CMake变量

catkin_package(
  INCLUDE_DIRS include
  CATKIN_DEPENDS cloud_msgs
  DEPENDS PCL
)
add_executable(imageProjection src/imageProjection.cpp)
add_executable(featureAssociation src/featureAssociation.cpp)
add_executable(mapOptmization src/mapOptmization.cpp)
add_executable(transformFusion src/transformFusion.cpp)
  • 实测其并不会将当前的include等文件夹拷贝到devel目录中

  • 必须要在声明targets前(即使用add_library()add_executable()前)调用该宏

Module CheatSheet

EIGEN

find_package(Eigen3 REQUIRED)
include_directories(${EIGEN3_INCLUDE_DIRS})

OpenCV

find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
target_link_libraries(<target> ${OpenCV_LIBS})

Variables CheatSheet

python

FindPythonLibs / FindPythonInterp

-DPYTHON_EXECUTABLE=/opt/conda/bin/python3
-DPYTHON_EXECUTABLE=$(python -c "import sys;print(sys.executable)")

-DPYTHON_INCLUDE_DIR=$(python -c "from sysconfig import get_paths;print(get_paths()['include'])")
-DPYTHON_LIBRARY=/opt/conda/lib/libpython3.8.so

-DPYBIND11_PYTHON_VERSION=3.7
-DPYTHON_VERSION=3.7

compiler

指定使用c++14标准
set(CMAKE_CXX_FLAGS "-std=c++14")

ros

path

Variable

Info

CMAKE_SOURCE_DIR

The root source directory

CMAKE_CURRENT_SOURCE_DIR

The current source directory if using sub-projects and directories.

PROJECT_SOURCE_DIR

当前CMake工程的源文件路径(.cmake文件所在路径)

PROJECT_BINARY_DIR

当前工程的build目录

CMAKE_BINARY_DIR

执行cmake命令的所在目录

CMAKE_CURRENT_BINARY_DIR

The build directory you are currently in.

LIBRARY_OUTPUT_PATH (deprecated)LIBRARY_OUTPUT_DIRECTORY

库的输出路径(要设置在add_library之前)

CMAKE_PREFIX_PATH

find_packaeg 搜索.cmake .config的搜索路径(初始为空)

EXECUTABLE_OUTPUT_PATH

可执行文件的输出路径

Reference