Issue
For unit testing my functions, i have auto-generated the name, like it:
test_implode test_range
into a CMake variable.
I want to call all automatically in C. I also used config file (.in.c) in CMake
set(CONFIG configuration)
configure_file(${CONFIG}.in.c ${CONFIG}.c)
set(CONFIG_SRC ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG}.c)
But the name of the function are just in a List in CMake, the C syntax is not valid. I could generate a variable in CMake with appropriate syntax, but generating output in config file would let the CMake source file clean and could be possibly very powerful.
Concretly, what I would like to do is that (imaginary syntax):
#include "tests.h"
void all_tests() {
void(*tests)()[] = {
@FOREACH(FUNC FUNCTIONS)@
test_@FUNC@,
@ENDFOREACH()@
NULL
};
void(*test_function)() = tests[0];
while(test_function) {
test_function();
test_function++;
}
}
Similarly to blade or php. Can I use CMake as a scripting language (or a foreach) or is it mandatory to put this in the CMake source file and store it into a variable ?
What I currently do, which is acceptable, works. But I'm learning and I would like to know if it's still possible or not
foreach(PHP_FUNCTION ${PHP_FUNCTIONS})
list(APPEND GENERATED_C_CODE_RUN_TEST "\n\ttest_${PHP_FUNCTION}()")
endforeach()
set(GENERATED_C_CODE_RUN_TEST "${GENERATED_C_CODE_RUN_TEST};")
set(CONFIG configuration)
configure_file(${CONFIG}.in.c ${CONFIG}.c)
set(CONFIG_SRC ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG}.c)
add_executable(...);
#include "tests.h"
void all_tests() {
@GENERATED_C_CODE_RUN_TEST@
}
Solution
One solution is to append the test_
prefix to each test name in a list, then use list(JOIN ...)
to construct a string representing a comma-separated list (which is valid C syntax).
list(APPEND PHP_FUNCTIONS
func1
func2
func3
)
# Append the 'test_' prefix to each test function name.
foreach(PHP_FUNCTION ${PHP_FUNCTIONS})
list(APPEND FUNCTION_NAMES_LIST "test_${PHP_FUNCTION}")
endforeach()
message(STATUS "FUNCTION_NAMES_LIST: ${FUNCTION_NAMES_LIST}")
# Construct a comma-separated string from the list.
list(JOIN FUNCTION_NAMES_LIST "," FUNCTION_NAMES_STRING)
message(STATUS "FUNCTION_NAMES_STRING: ${FUNCTION_NAMES_STRING}")
This prints the following:
FUNCTION_NAMES_LIST: test_func1;test_func2;test_func3
FUNCTION_NAMES_STRING: test_func1,test_func2,test_func3
Then, you can modify your configuration.in.c
file so only one variable needs to be substituted:
void all_tests() {
void(*tests)()[] = {
@FUNCTION_NAMES_STRING@,
NULL
};
void(*test_function)() = tests[0];
while(test_function) {
test_function();
test_function++;
}
}
You can play around with the "glue" or separator string used to join the CMake list together. In my example, I used ","
but you can use ", "
or ",\n\t"
to make the resultant C code more visually pleasing. CMake list()
(and string()
) have lots of manipulation options to play around with, so I encourage you to check them out.
Answered By - Kevin