I want to generate a custom header file and was wondering if CMake has something that I can use without writing my own generator. It would have some "one time" items and some items I need to generate based on a loop.
For example, the desired output would look like:
//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;
For input, I would provide the following in some form:
Item1, 1, 2
Item2, 3, 4
Item5, 6, 7
CMake provides a few utilities for generating and writing to files at the configure stage. To start off, we can put the "One time stuff" in a template file, and use configure_file()
to generate a header file from it:
# 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
)
The template file header.hpp.in
can simply contain this:
//One time stuff
#define ABC 1
#define DEF 2
#define GHI 3
#define JKL 4
//Stuff generated in loop
Next, we can use CMake's file()
and string()
utilities to read an input file (CSV-formatted in this example), parse the contents, and write the rest of the header file. So, test.csv
would contain the input, and we can do something like this:
# 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()
This will work for an arbitrary number of rows in the input CSV file. While this is one solution, something less verbose is certainly possible using regex. Note, this works best if your CSV doesn't contain spaces!
The completed 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;