CMake 基础使用

CMAKE_PREFIX_PATH

CMAKE_PREFIX_PATH 用于定义额外的 bin/lib(64)/include 搜索路径(默认为空)。

如果 CMAKE_PREFIX_PATH 指定的路径中没有 /bin, /lib(64), /include 后缀,cmake 的 find_xxx 命令会为每个路径自动加上 /bin, /lib(64), /include 目录。

CMAKE_PREFIX_PATH 既可以通过环境变量导出:

$ export CMAKE_PREFIX_PATH=/home/runsisi:/usr/local:/opt/runsisi/python3/bin

同时它也是一个 CMake 内置的变量,因此还可以在命令行上通过 -D 选项或者在 CMakeList.txt 中通过 set 或者 list 命令显式定义。

$ cmake .. -DPythonInterp_FIND_VERSION=3.6 -DPythonInterp_FIND_VERSION_MAJOR=3 -DCMAKE_PREFIX_PATH=/home/runsisi\;/usr/local\;/opt/runsisi/python3/bin
$ cmake .. -DPythonInterp_FIND_VERSION=3.6 -DPythonInterp_FIND_VERSION_MAJOR=3 -DCMAKE_PREFIX_PATH='/home/runsisi;/usr/local;/opt/runsisi/python3/bin'
$ cmake .. -DPythonInterp_FIND_VERSION=3.6 -DPythonInterp_FIND_VERSION_MAJOR=3 -DCMAKE_PREFIX_PATH="/home/runsisi;/usr/local;/opt/runsisi/python3/bin"
set(CMAKE_PREFIX_PATH "/home/runsisi;/usr/local;/opt/runsisi/python3/bin")

或:

list(APPEND CMAKE_PREFIX_PATH "/home/runsisi;/usr/local;/opt/runsisi/python3/bin")

注意冒号、分号、带转义的分号三种方式分隔符的使用(带转义是 shell 的限制而已),CMake 通过分号定义列表,空白分隔参数。

CMAKE_MODULE_PATH

CMAKE_PREFIX_PATH 不同,CMAKE_MODULE_PATH 不支持通过环境变量导出(默认为空),因此必须在命令行上通过 -D 选项或者在 CMakeList.txt 中通过 set 或者 list 命令显式定义:

$ cmake .. -DPythonInterp_FIND_VERSION=3.6 -DPythonInterp_FIND_VERSION_MAJOR=3 -DCMAKE_PREFIX_PATH="/home/runsisi;/usr/local;/opt/runsisi/python3/bin" -DCMAKE_MODULE_PATH=~/working/test/pyleak/cmake/modules

或:

set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules")

或:

list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules")

增加多个路径的方式与 CMAKE_PREFIX_PATH 类似,通过分号进行分隔。

调试打印

message 调试打印,如:

message("_Python_NAMES: " "${_Python_NAMES}")
message("_Python_NAMES: ${_Python_NAMES}")
message("PYTHON_EXECUTABLE: " "${PYTHON_EXECUTABLE}")
message("PYTHON_EXECUTABLE: ${PYTHON_EXECUTABLE}")

find-package 模式

调试 FindXxx 模块时可以使用 find-package 模式,这样就不用每次都删除 cmake 生成的中间文件:

$ cmake .. -DPythonInterp_FIND_VERSION=3.6 -DPythonInterp_FIND_VERSION_MAJOR=3 -DCMAKE_PREFIX_PATH="/home/runsisi;/usr/local;/opt/runsisi/python3/bin" -DNAME=PythonInterp -DCOMPILER_ID=GNU -DLANGUAGE=C -DMODE=EXIST --find-package

不过需要注意的是,find-package 模式与项目无关,如果需要测试用户自定义的 FindXxx 模块,有两种方法:

  1. 拷贝至 CMake 自带的模块目录中,如:
/usr/share/cmake-3.10/Modules/
/usr/share/cmake/Modules/
  1. 在命令行上显式定义 CMAKE_MODULE_PATH
$ cmake -DCMAKE_MODULE_PATH=~/working/test/pyleak/pybind11/tools -DNAME=PythonLibsNew -DCOMPILER_ID=GNU -DLANGUAGE=C -DMODE=EXIST --find-package

如果开启 --trace 等调试选项,需要在把这些选项放在 --find-package 之前。

注意:CMake 自带的 FindXxx 模块具有最低优先级

运行

最后,可以以 verbose 模式运行 make 以检验 CMake 生成的 Makefile 结果:

$ make VERBOSE=1

构建并使用 gdb 调试 cmake

在分析 CMake 工程的 make install 行为时,需要使用 gdb 调试 cmake,但是发行版默认的 cmake 都是没有 debug 信息的,因此需要自己进行构建:

$ ./bootstrap -- -DCMAKE_BUILD_TYPE:STRING=Debug
$ sudo make install
$ cd build/
$ export DESTDIR=xxx
$ gdb cmake
(gdb) set args -P cmake_install.cmake

cmake 工程 make install 行为

CMake 工程中 make install 过程中的文件的拷贝操作直接使用的是 cmake 命令自身的实现,文件拷贝并不会遵守 umask 的约束(文件所在路径上的文件夹创建在 Posix 平台使用的是 mkdir 接口,因此文件夹本身遵守 umask 约束)。

CMake install 拷贝文件操作时文件权限设置实现:

https://github.com/Kitware/CMake/blob/v3.19.1/Source/cmFileInstaller.cxx#L28

https://github.com/Kitware/CMake/blob/v3.19.1/Source/cmFileInstaller.cxx#L85

https://github.com/Kitware/CMake/blob/v3.19.1/Source/kwsys/SystemTools.cxx#L2411

https://github.com/Kitware/CMake/blob/v3.19.1/Source/cmFileCopier.cxx#L626

参考资料

Learn CMake’s Scripting Language in 15 Minutes

https://preshing.com/20170522/learn-cmakes-scripting-language-in-15-minutes/

Some CMake tips

https://samthursfield.wordpress.com/2015/10/20/some-cmake-tips/

CMake: dependencies between targets and files and custom commands

https://samthursfield.wordpress.com/2015/11/21/cmake-dependencies-between-targets-and-files-and-custom-commands/

CMake stuff i wish i knew earlier

http://www.brianlheim.com/2018/04/09/cmake-cheat-sheet.html

Displaying CMake variables

https://stackoverflow.com/questions/31343813/displaying-cmake-variables

overriding CMAKE_MODULE_PATH

https://mail.kde.org/pipermail/kde-buildsystem/2010-August/007285.html

How to get CMake find what you want it to

https://blogs.kde.org/2008/12/12/how-get-cmake-find-what-you-want-it

CMake Useful Variables

https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/Useful-Variables

It’s Time To Do CMake Right

https://pabloariasal.github.io/2018/02/19/its-time-to-do-cmake-right/

An Introduction to Modern CMake

https://cliutils.gitlab.io/modern-cmake/

Does set_target_properties in CMake override CMAKE_CXX_FLAGS?

https://stackoverflow.com/questions/5096881/does-set-target-properties-in-cmake-override-cmake-cxx-flags

What is the modern method for setting general compile flags in CMake?

https://stackoverflow.com/questions/23995019/what-is-the-modern-method-for-setting-general-compile-flags-in-cmake

Does cmake have something like target_link_options?

https://stackoverflow.com/questions/25043458/does-cmake-have-something-like-target-link-options

Tutorial: Managing Compiler Warnings with CMake

https://foonathan.net/2018/10/cmake-warnings/

cmake_dependent_option 详解

http://www.up4dev.com/2019/12/12/cmake_dependent_option/

RPATH handling

https://gitlab.kitware.com/cmake/community/-/wikis/doc/cmake/RPATH-handling


最后修改于 2019-08-29