【问题标题】:Generate custom header file with CMake使用 CMake 生成自定义头文件
【发布时间】:2020-06-23 19:08:27
【问题描述】:

我想生成一个自定义头文件,并且想知道 CMake 是否有一些我可以在不编写自己的生成器的情况下使用的东西。它会有一些“一次性”项目和一些我需要基于循环生成的项目。

例如,所需的输出如下所示:

//One time stuff
#define ABC 1
#define DEF 2
#define GHI 3
#define JKL 4

//Stuff generated in loop

//Iteration with params Item1, 1, 2 
const int prefix_Item1_1 = 2;
const int prefix2_1_2 = 0;

//Iteration with params Item2, 3, 4 
const int prefix_Item2_3 = 4;
const int prefix2_3_4 = 0;

//Iteration with params Item5, 6, 7 
const int prefix_Item5_6 = 7;
const int prefix2_6_7 = 0;

对于输入,我会以某种形式提供以下内容:

Item1, 1, 2 
Item2, 3, 4
Item5, 6, 7

【问题讨论】:

  • 不,它支持生成文件:cmake.org/cmake/help/v3.11/prop_sf/GENERATED.html 但你需要编写自己的生成器
  • 您是否打算将“输入”放在某个 CSV 文件中,当您运行 cmake .. 时可用?
  • 如果我不必编写生成器,我可以将输入设置为所需的任何格式:)

标签: c++ cmake code-generation


【解决方案1】:

CMake 提供了一些实用程序,用于在配置阶段生成和写入文件。首先,我们可以将“One time stuff”放在模板文件中,并使用configure_file() 从中生成头文件:

# Generate header.hpp from your template file header.hpp.in
configure_file(${CMAKE_CURRENT_LIST_DIR}/header.hpp.in 
    ${CMAKE_CURRENT_LIST_DIR}/header.hpp COPYONLY
)

模板文件header.hpp.in 可以简单地包含这个:

//One time stuff
#define ABC 1
#define DEF 2
#define GHI 3
#define JKL 4

//Stuff generated in loop

接下来,我们可以使用 CMake 的 file()string() 实用程序读取输入文件(在本例中为 CSV 格式),解析内容,然后写入头文件的其余部分。所以,test.csv 将包含输入,我们可以这样做:

# Read the entire CSV file.
file(READ ${CMAKE_CURRENT_LIST_DIR}/test.csv CSV_CONTENTS)

# Split the CSV by new-lines.
string(REPLACE "\n" ";" CSV_LIST ${CSV_CONTENTS})

# Loop through each line in the CSV file.
foreach(CSV_ROW ${CSV_LIST})
    # Get a list of the elements in this CSV row.
    string(REPLACE "," ";" CSV_ROW_CONTENTS ${CSV_ROW})

    # Get variables to each element.
    list(GET CSV_ROW_CONTENTS 0 ELEM0)
    list(GET CSV_ROW_CONTENTS 1 ELEM1)
    list(GET CSV_ROW_CONTENTS 2 ELEM2)

    # Append these lines to header.hpp, using the elements from the current CSV row.
    file(APPEND ${CMAKE_CURRENT_LIST_DIR}/header.hpp
    "
//Iteration with params ${ELEM0}, ${ELEM1}, ${ELEM2}
const int prefix_${ELEM0}_${ELEM1} = ${ELEM2};
const int prefix2_${ELEM1}_${ELEM2} = 0;
    "
    )
endforeach()

这将适用于输入 CSV 文件中的任意数量的行。虽然这是一种解决方案,但使用正则表达式肯定可以实现一些不那么冗长的事情。请注意,如果您的 CSV 不包含空格,则此方法效果最佳!

已完成的header.hpp

//One time stuff
#define ABC 1
#define DEF 2
#define GHI 3
#define JKL 4

//Stuff generated in loop

//Iteration with params Item1, 1, 2
const int prefix_Item1_1 = 2;
const int prefix2_1_2 = 0;

//Iteration with params Item2, 3, 4
const int prefix_Item2_3 = 4;
const int prefix2_3_4 = 0;

//Iteration with params Item5, 6, 7
const int prefix_Item5_6 = 7;
const int prefix2_6_7 = 0;

【讨论】:

  • 甜蜜!如何通过 .csv 更改强制重新生成?我可以添加对它的依赖吗?还有一种方法可以强制 Elem1、ELEM2 为数字吗?
  • 如果数字是十六进制怎么办?我希望 const int 的名称保持一致。
  • @scoplexian 强制 CMake 重新运行以生成标头的一种简单方法是使用 configure_file(test.csv dummy.csv)。此命令将识别对 CSV 输入的更改,并在必要时重新运行。十六进制会更复杂,但也许您可以使用math 将十六进制输入重新格式化为十进制。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-17
  • 2021-12-11
  • 2015-05-17
  • 2017-12-06
  • 1970-01-01
  • 2014-11-10
  • 1970-01-01
相关资源
最近更新 更多