> 文章列表 > CMake命令笔记

CMake命令笔记

CMake命令笔记

1. add_definitions

比如要在代码中有进行宏判断的地方

#ifdefine _IMAGE_PNGxxx
#endif
#ifdefine _IMAGE_JPGxxx
#endif
#ifdefine _IMAGE_TIFFxxx
#endif

你需要通过宏执行响应代码
那么在CMakelists中就要使用add_definitions命令,这和在代码中使用#define _IMAGE_PNG是一样的效果
add_definitions(-D_IMAGE_PNG)
如果要添加多个宏,在这个命令中用空格隔开
add_definitions(-D_IMAGE_PNG -D_IMAGE_JPG)

2. get_filename_component

cmake文档地址
这个命令用于获取一个全文件名(这里感觉可以理解为绝对路径)的某个特定组分,比如目录、文件名、文件扩展名(取最长的,a.b.c的文件扩展名是.b.c)、文件名不带扩展名(a.b.c取a)、最后一个扩展名(a.b.c取.c)、文件名不带路径及最后一个扩展名等等。

3. target_compile_options

编译basalt时碰到这个命令,basalt使用的第三方库pangolin老是报错:

CMake Error at thirdparty/CMakeLists.txt:67 (target_compile_options):Cannot specify compile options for target "pangolin" which is not built bythis project.CMake Error at thirdparty/CMakeLists.txt:118 (get_target_property):get_target_property() called with non-existent target "pangolin".CMake Error at thirdparty/CMakeLists.txt:134 (get_target_property):get_target_property() called with non-existent target "pangolin".CMake Error at thirdparty/CMakeLists.txt:142 (set_target_properties):set_target_properties Can not find target to add properties to: pangolin

但是这和这个命令并没有什么关系,这个错误貌似是因为我在下载第三方库的时候,不是使用的git clone --recursive,而是手动下载的第三方库到thirdparty目录下,因此可能没有感知到pangolin的存在,然后我在basalt项目根目录下使用git submodule init和git submodule update,问题愉快地解决了。

这里记录target_compile_options命令的用法

cmake原始文档地址
这个命令是为某个需要编译的目标增加编译选项,比如在前面添加的add_executable()或者add_library(),这两个命令表示你要编译一个可执行文件或者一个库,这就是编译目标(target)。
命令的参数选项如下:

target_compile_options(<target> [BEFORE]<INTERFACE|PUBLIC|PRIVATE> [items1...][<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])

target_compile_options会增加选项(options)到COMPILE_OPTIONS或者INTERFACE_COMPILE_OPOTIONS目标属性(也就是增加编译选项的意思)。这些选项会在编译给定目标(<target>)时使用,给定目标必须已经通过add_executable()或者add_library()这种命令添加到项目中,并且不能是别名目标。

下面看可选参数

如果指定了BEFORE,这个命令中的选项将放到所有属性之前(prepended)而不是之后(appended)。
INTERFACE, PUBLIC和PRIVATE关键词用于指定随后的参数的作用域。
PRIVATE和PUBLIC项将填充<target>COMPILE_OPTIONS属性。
PUBLIC和INTERFACE项将填充<target>INTERFACE_COMPILE_OPTIONS属性。
随后的参数就是指定的编译选项。
编译选项就是CMAKE调用编译器时的编译参数,每个编译器都有一些编译参数,有的是共通的,有的是编译器相关的,其实我认为所有的构建工具,编译工具,最终都是为了得到一个编译器命令行,这个命令行的执行命令是编译器的编译程序,命令参数就是这些编译参数。使用VisualStudio的同学可以查看属性配置-C/C+±命令行,里面就是VS的编译参数。

4. find_path

在编译basalt时,cmake提示需要3.4.0版本的Eigen,而且在find_package中添加了exact参数,所以还不能改。
然而我系统中使用apt安装的eigen是3.3.7版本的。因此下载安装了3.4.0版本的Eigen,但是cmake还是找不到这个版本的Eigen。
查看basalt的编译文件发现他是使用FindEigen3.cmake文件查找Eigen库的,即在CMakelists.txt中用find_package()找到库,然后findpackage使用module模式进行查找,见CMake搜索方式
因此只需要修改FindEigen3.cmake文件就可以进行查找,在FindEigen3.cmake文件中就有使用find_path。
这里将find_path命令的官方文档翻译如下
原文链接—CMake3.23.1—find_path

find_path

精简的命令签名为:

find_path (<VAR> name1 [path1 path2 ...])

一般化的命令签名为

find_path (<VAR>name | NAMES name1 [name2 ...][HINTS [path | ENV var]... ][PATHS [path | ENV var]... ][PATH_SUFFIXES suffix1 [suffix2 ...]][DOC "cache documentation string"][NO_CACHE][REQUIRED][NO_DEFAULT_PATH][NO_PACKAGE_ROOT_PATH][NO_CMAKE_PATH][NO_CMAKE_ENVIRONMENT_PATH][NO_SYSTEM_ENVIRONMENT_PATH][NO_CMAKE_SYSTEM_PATH][CMAKE_FIND_ROOT_PATH_BOTH |ONLY_CMAKE_FIND_ROOT_PATH |NO_CMAKE_FIND_ROOT_PATH])

首先需要知道命令行语法参数<>, [], | 分别表示什么意思
这个命令用于找到一个目录,这个目录包含the named file(应该就是命令参数中的name、NAMES这些参数指定的文件),如果选择了NO_CACHE参数,那么<VAR>指定的变量就会被创建以保存命令的查找结果。查找成功,那么查找结果会被保存到<VAR>中,如果没有找到,那么结果会被被保存为<VAR>-NOTFOUND

可选项包括
NAMES
这里是要么直接写name,要么写NAMES name1 [name2 …]的意思。就是需要查找的文件项。

HINTS, PATHS
除默认位置外,其他指定需要搜索的目录。ENV var子可选项从系统环境变量中读取路径。

PATH_SUFFIXS
指定额外需要检查的子目录以在每个目录下方进行检查。(otherwise considered不知道啥意思)

NO_DEFAULT_PATH
不查找默认路径

知道上面几个参数已经差不多了

以下面的命令为例,这是为了查找EIGEN3这个库所在位置,signature_of_eigen3_matrix_library是eigen3这个库中的一个文件,这个文件所在的目录就是库所在的目录,因此使用find_path查找这个文件并将结果保存到EIGEN3_INCLUDE_DIR_NAMES。
HINTS 提供了一个搜索的路径,是变量EIGEN_INCLUDE_DIR_HINTS提供的。
NO_DEFAULT_PATH表示不查找默认路径,比如/usr/local/include、/usr/include等等路径。

  find_path(EIGEN3_INCLUDE_DIR NAMES signature_of_eigen3_matrix_libraryHINTS ${EIGEN_INCLUDE_DIR_HINTS}NO_DEFAULT_PATH)