如何使用 cmake 生成包含的文件?

How do I generate included files using cmake?

我有一个工具可以生成包含定义和声明的文件。这些文件需要从其他源文件或 headers 中包含 - 它们不能单独使用。

显而易见的事情是使用自定义命令来生成它们。我的 CMakeLists.txt 是这样做的,如下所示。我目前正在将其与 GNU makefile 生成器一起使用。

project(test_didl)
cmake_minimum_required(VERSION 3.0)

add_custom_command(
  OUTPUT test_didl_structs.h test_didl_structs.c
  COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/didl.py --decls=test_didl_structs.h --defs=test_didl_structs.c ${CMAKE_CURRENT_SOURCE_DIR}/test_didl_structs.py
  DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/didl.py ${CMAKE_CURRENT_SOURCE_DIR}/test_didl_structs.py
  MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/test_didl_structs.py)

add_executable(test_didl test_didl.c)
target_include_directories(test_didl PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_link_libraries(test_didl shared_lib)

test_didl.c很简单:

#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include "test_didl_structs.h"
#include "test_didl_structs.c"

int main(void) {
}

但是在第一次构建时,make 尝试构建 test_didl.c,当然失败了,因为 test_didl_structs.* 还没有生成。自然地,在 test_didl.c 的第一次成功构建之前,依赖信息是未知的,所以 make 不知道 运行 先执行 python 命令。

我尝试了自定义目标,但这并不好,因为假设自定义目标总是脏的。这意味着在每次构建时都会重新编译 C 文件并链接 EXE。此方法无法扩展。

我最终的解决方案是将输出 .h 文件作为可执行文件的输入:

add_executable(test_didl test_didl.c test_didl_structs.h)

.h 文件输入被视为依赖项,但不会为 makefile 生成器做任何有趣的事情。 (我目前对其他发电机不感兴趣。)

这样可行,但感觉有点难看。它实际上并没有明确声明自定义命令首先需要 运行 ,尽管在实践中这似乎发生了。不过,我不太确定如何(但我还没有跟上阅读 CMake-generated Makefile 的速度)。

这是它应该的工作方式吗?还是我应该做一些更整洁的事情?

(我想,我想像的是 Visual Studio pre-build 步骤,因为在正常依赖之前,每个构建都会考虑 运行ning检查。但我希望此 pre-build 步骤具有依赖性检查,以便在其输入早于其输出时跳过它。)

您可以尝试告诉 cmake 您正在使用外部源,请参阅有关 set_source_files_properties, see this past post

的文档

My eventual solution was to make the output .h file an input to the executable.

这种方式是正确的。

它实际上指出,构建可执行文件 取决于 给定文件,并且,如果该文件是某些 add_custom_command() 的 OUTPUT,则将执行此命令 构建可执行文件之前。


另一种方法是在 configuration 阶段使用 execute_process() 生成所需的 headers。在这种情况下,无需添加 header 文件作为 add_executable() 的源:CMake 具有自动检测编译依赖项的概念,因此 test_didl 将在 test_didl_structs.h 重新生成后重建.

execute_process(COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/didl.py --decls=test_didl_structs.h --defs=test_didl_structs.c ${CMAKE_CURRENT_SOURCE_DIR}/test_didl_structs.py)
# ...
add_executable(test_didl test_didl.c)

此方法的缺点是您需要在更改 .py 文件后手动重新运行 配置阶段。另见 question 并回答它。 另一个问题是 header 文件将被更新 每次 配置是 运行.