在 CMake 中使用来自 C/C++ 宏的值

Use value from C/C++ macro in CMake

将 C/C++ 宏的值放入 CMake 变量的最简单方法是什么?

假设我用 header foo.h 检查库 libfoo。我知道 foo.h 包含宏 #define FOO_VERSION_MAJOR <version>,其中版本是整数或字符串值。要提取找到的库的主要版本,我想使用此宏中的值。

作为奖励,如果找不到宏,这可能表明版本比引入版本宏的特定版本更早。

我会用 file(READ ...) 阅读 header,然后 string(REGEX ...) 来提取所需的定义。

示例代码:

file(READ "foo.h" header)
string(REGEX MATCH "#define FOO_MAJOR_VERSION [0-9]+" macrodef "${header}")
string(REGEX MATCH "[0-9]+" FooMajorVersion "${macrodef}")

使用try_compile和正确的编译指示可以在编译时输出预处理器宏的值。 CMake 可以解析输出以获得所需的值。

CMake 片段:

try_compile(result "${CMAKE_BINARY_DIR}"
  SOURCES "${CMAKE_SOURCE_DIR}/foo-version.cpp"
  OUTPUT_VARIABLE fooversion)
string(REGEX MATCH ": [0-9]+" fooversionshort "${fooversion}")
string(REGEX MATCH "[0-9]+" FooMajorVersion "${fooversionshort}")

foo-version.cpp:

#include "foo.h"

/* definition to expand macro then apply to pragma message */
#define VALUE_TO_STRING(x) #x
#define VALUE(x) VALUE_TO_STRING(x)
#pragma message(VALUE(FOO_MAJOR_VERSION))

int main()
{
    return 0;
}

好:

  • 来自变量的实际值,可能会计算出来。

差:

  • 只有一些较新的编译器支持宏的输出。
  • 对于未经测试的编译器,输出解析可能会中断,因为格式会随着编译器版本的不同而变化。
  • 那种复杂的代码,冗长的代码,难以阅读。

可以使用C 预处理器提取宏展开。 我使用这种方法提取特定的 typedef,而无需知道定义在文件层次结构中的确切位置。

假设我们在 foo.h

的某处定义了这个宏
#define FOO_VERSION_MAJOR 666

您需要使用此内容创建帮助文件helper.c

#include "foo.h"
int __READ_FOO_MAJOR__ = FOO_VERSION_MAJOR  ;

请注意,我使用了一个特定的模式 __READ_FOO_MAJOR__,稍后我将使用它作为 grep 命令的模式

CMakeLists.txt 开始,您必须像这样调用 C(C++ 等)预处理器并过滤其输出

cmake_minimum_required(VERSION 3.0)
execute_process(
      COMMAND           bash "-c" "${CMAKE_C_COMPILER} -E ${CMAKE_CURRENT_SOURCE_DIR}/helper.cpp | grep __READ_FOO_MAJOR__ | awk '{    print }'"
      OUTPUT_VARIABLE   FOO_VERSION_MAJOR )
message("From CMake: FOO_VERSION_MAJOR=${FOO_VERSION_MAJOR}")

请注意,awk '{ print }' 提取所选行的第 4 个单词。

当运行宁cmake我们得到这个结果

From CMake: FOO_VERSION_MAJOR=666

使用的短 shell 管道是用 Unix 系统 V 基本命令构建的,应该 运行 无处不在。