CMake 笔记 | [23] 配置时运行自定义命令

注意
本文最后更新于 2024-01-31,文中内容可能已过时。

一、导言

导言

已经好久好久没有更新这个系列了,但是无论如何这个系列一定会以较全面的形式更新完成,只是在时间上可能比较拖沓。没有更新的原因也是最近一个月在做一个项目,没日没夜的度过了一个多月的加班加点的生活。

我们言归正传,通过前面的学习,我们已经了解了CMake如何在配置时运行许多子任务,以便找到工作的编译器和必要的依赖项。本篇,我们将学习使用execute_process命令在配置时运行定制化命令。

二、项目结构

本篇比较简单,只有一个简单的CMakeLists.txt。 相关源码:

https://gitee.com/jiangli01/tutorials/tree/master/cmake-tutorial/chapter5/01

CMakeLists.txt
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)

project(test_exe_proc LANGUAGES NONE)

find_package(PythonInterp REQUIRED)

# this is set as variable to prepare for abstraction using loops or functions
set(module_name "cffi")
execute_process(
  COMMAND
      ${PYTHON_EXECUTABLE} "-c" "import ${module_name}; print(${module_name}.__version__)"
  OUTPUT_VARIABLE stdout
  ERROR_VARIABLE stderr
  OUTPUT_STRIP_TRAILING_WHITESPACE
  ERROR_STRIP_TRAILING_WHITESPACE
)

if(stderr MATCHES "ModuleNotFoundError")
    message(STATUS "Module ${module_name} not found")
else()
    message(STATUS "Found module ${module_name} v${stdout}")
endif()
代码详解

execute_process命令将从当前正在执行的CMake进程中派生一个或多个子进程,从而提供了在配置项目时运行任意命令的方法。可以在一次调用execute_process时执行多个命令。注意,每个命令的输出将通过管道传输到下一个命令中。该命令接受多个参数:

  • WORKING_DIRECTORY,指定应该在哪个目录中执行命令。
  • RESULT_VARIABLE将包含进程运行的结果。这要么是一个整数,表示执行成功,要么是一个带有错误条件的字符串。
  • OUTPUT_VARIABLEERROR_VARIABLE将包含执行命令的标准输出和标准错误。由于命令的输出是通过管道传输的,因此只有最后一个命令的标准输出才会保存到OUTPUT_VARIABLE中。
  • INPUT_FILE指定标准输入重定向的文件名
  • OUTPUT_FILE指定标准输出重定向的文件名
  • ERROR_FILE指定标准错误输出重定向的文件名
  • 设置OUTPUT_QUIETERROR_QUIET后,CMake将静默地忽略标准输出和标准错误。
  • 设置OUTPUT_STRIP_TRAILING_WHITESPACE,可以删除运行命令的标准输出中的任何尾随空格
  • 设置ERROR_STRIP_TRAILING_WHITESPACE,可以删除运行命令的错误输出中的任何尾随空格
1
2
3
4
5
6
7
8
execute_process(
  COMMAND
      ${PYTHON_EXECUTABLE} "-c" "import ${module_name}; print(${module_name}.__version__)"
  OUTPUT_VARIABLE stdout
  ERROR_VARIABLE stderr
  OUTPUT_STRIP_TRAILING_WHITESPACE
  ERROR_STRIP_TRAILING_WHITESPACE
)

该命令检查python -c "import cffi; print(cffi.__version__)"的输出。如果没有找到模块,stderr将包含ModuleNotFoundError,我们将在if语句中对其进行检查。本例中,我们将打印Module cffi not found。如果导入成功,Python代码将打印模块的版本,该模块通过管道输入stdout,这样就可以打印如下内容:

1
message(STATUS "Found module ${_module_name} v${stdout}")
运行结果
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
mkdir build
cd build
cmake ..
-- Found PythonInterp: /usr/bin/python3.8 (found version "3.8.10")
-- Module cffi not found
-- Configuring done
-- Generating done
-- Build files have been written to: /home/jiangli/repo/tutorials/cmake-tutorial/chapter5/01/build
sudo pip3 install cffi
mkdir build
cd build
cmake ..
-- Found module cffi v1.16.0
-- Configuring done
-- Generating done
-- Build files have been written to: /home/jiangli/repo/tutorials/cmake-tutorial/chapter5/01/build
补充说明

本篇,只打印了结果,但实际项目中,可以警告、中止配置,或者设置可以查询的变量,来切换某些配置选项。

Buy me a coffee~
支付宝
微信
0%