Allow passing target config to generator invocation

So the code generator 'sees' the source code in the same
way as the compiler does.
This commit is contained in:
Martchus 2017-11-17 21:42:49 +01:00
parent 19cab9c791
commit 227d3f3942
6 changed files with 66 additions and 10 deletions

View File

@ -76,6 +76,7 @@ Note that the header included at the bottom must be generated by invoking the co
reflective_rapidjson_generator -i "$srcdir/code-defining-structs.cpp" -o "$builddir/reflection/code-defining-structs.h"
```
#### Invoking code generator with CMake macro
It is possible to use the provided CMake macro to automate this task:
```
find_package(reflective-rapidjson REQUIRED)
@ -99,6 +100,15 @@ will always have the extension "`.h`", independently of the extension of the inp
The full paths of the generated files are also appended to the variable `LIST_OF_GENERATED_HEADERS` which then can be added
to the sources of your target. Of course this can be skipped if not required/wanted.
#### Passing Clang options
It is possible to pass additional options to the Clang tool invocation used by the code generator.
This can be done using the `--clang-opt` argument or the `CLANG_OPTIONS` argument when using the CMake macro.
It makes most sense to specify the same options as during compilation so the code generator uses the same flags,
defines and include directories as the compiler and hence behaves like the compiler.
When using the CMake macro it is possible to automatically pass all compile flags, compile definitions and include directories
from certain targets to the code generator. The targets can ge specified using the `CLANG_OPTIONS_FROM_TARGETS` argument.
### Using Boost.Hana instead of the code generator
The same example as above. However, this time Boost.Hana is used - so it doesn't require invoking the generator.

View File

@ -59,6 +59,8 @@ add_reflection_generator_invocation(
json
OUTPUT_LISTS
TEST_HEADER_FILES
CLANG_OPTIONS_FROM_TARGETS
reflective_rapidjson_generator_tests
JSON_CLASSES
OtherNotJsonSerializable # test specifying classes for JSON (de)serialization manually
SomeOtherClassName # specifying a class that does not exist should not cause any problems

View File

@ -25,8 +25,7 @@ CodeFactory::ToolInvocation::ToolInvocation(CodeFactory &factory)
fileManager.Retain();
}
CodeFactory::CodeFactory(
const char *applicationPath, const std::vector<const char *> &sourceFiles, const std::vector<const char *> &clangOptions, std::ostream &os)
CodeFactory::CodeFactory(const char *applicationPath, const std::vector<const char *> &sourceFiles, const std::vector<string> &clangOptions, std::ostream &os)
: m_applicationPath(applicationPath)
, m_sourceFiles(sourceFiles)
, m_clangOptions(clangOptions)

View File

@ -29,7 +29,7 @@ class CodeFactory {
public:
CodeFactory(
const char *applicationPath, const std::vector<const char *> &sourceFiles, const std::vector<const char *> &clangOptions, std::ostream &os);
const char *applicationPath, const std::vector<const char *> &sourceFiles, const std::vector<std::string> &clangOptions, std::ostream &os);
~CodeFactory();
const std::vector<std::unique_ptr<CodeGenerator>> &generators() const;
@ -48,7 +48,7 @@ private:
const char *const m_applicationPath;
const std::vector<const char *> &m_sourceFiles;
const std::vector<const char *> &m_clangOptions;
const std::vector<std::string> &m_clangOptions;
std::ostream &m_os;
std::vector<std::unique_ptr<CodeGenerator>> m_generators;
std::unique_ptr<ToolInvocation> m_toolInvocation;

View File

@ -6,6 +6,7 @@
#include <c++utilities/application/argumentparser.h>
#include <c++utilities/application/commandlineutils.h>
#include <c++utilities/application/failure.h>
#include <c++utilities/conversion/stringconversion.h>
#include <c++utilities/io/ansiescapecodes.h>
#include <c++utilities/io/catchiofailure.h>
#include <c++utilities/io/misc.h>
@ -16,6 +17,7 @@
using namespace std;
using namespace ApplicationUtilities;
using namespace ConversionUtilities;
using namespace EscapeCodes;
using namespace IoUtilities;
using namespace ReflectiveRapidJSON;
@ -63,10 +65,23 @@ int main(int argc, char *argv[])
os = &cout;
}
// compose options passed to the clang tool invocation
vector<string> clangOptions;
if(clangOptionsArg.isPresent()) {
// add additional options specified via CLI argument
for(const auto *const value : clangOptionsArg.values(0)) {
// split options by ";" - not nice but this eases using CMake generator expressions
const auto splittedValues(splitString<vector<string>>(value, ";", EmptyPartsTreat::Omit));
clangOptions.reserve(clangOptions.size() + splittedValues.size());
for(const auto &splittedValue : splittedValues) {
clangOptions.emplace_back(move(splittedValue));
}
}
}
// configure code generator
vector<const char *> defaultClangOptions;
CodeFactory factory(
parser.executable(), inputFileArg.values(0), clangOptionsArg.isPresent() ? clangOptionsArg.values(0) : defaultClangOptions, *os);
parser.executable(), inputFileArg.values(0), clangOptions, *os);
// add only specified generators if the --generator argument is present
if (generatorsArg.isPresent()) {
// find and construct generators by name

View File

@ -26,13 +26,23 @@ if(NOT REFLECTION_GENERATOR_EXECUTABLE)
message(FATAL_ERROR "Unable to find executable of generator for reflection code.")
endif()
# define helper functions
# define helper function to add a reflection generator invocation for a specified list of source files
include(CMakeParseArguments)
function(add_reflection_generator_invocation)
# parse arguments
set(OPTIONAL_ARGS)
set(ONE_VALUE_ARGS OUTPUT_DIRECTORY JSON_VISIBILITY)
set(MULTI_VALUE_ARGS INPUT_FILES GENERATORS OUTPUT_LISTS CLANG_OPTIONS JSON_CLASSES)
set(OPTIONAL_ARGS
)
set(ONE_VALUE_ARGS
OUTPUT_DIRECTORY
JSON_VISIBILITY
)
set(MULTI_VALUE_ARGS
INPUT_FILES
GENERATORS
OUTPUT_LISTS
CLANG_OPTIONS
CLANG_OPTIONS_FROM_TARGETS
JSON_CLASSES)
cmake_parse_arguments(ARGS "${OPTIONAL_ARGS}" "${ONE_VALUE_ARGS}" "${MULTI_VALUE_ARGS}" ${ARGN})
# determine file name or file path if none specified
@ -41,10 +51,29 @@ function(add_reflection_generator_invocation)
file(MAKE_DIRECTORY "${ARGS_OUTPUT_DIRECTORY}")
endif()
# add options to be passed to clang from the specified targets
if(ARGS_CLANG_OPTIONS_FROM_TARGETS)
foreach(TARGET_NAME ${ARGS_CLANG_OPTIONS_FROM_TARGETS})
# add compile flags
set(PROP "$<TARGET_PROPERTY:${TARGET_NAME},COMPILE_FLAGS>")
list(APPEND ARGS_CLANG_OPTIONS "$<$<BOOL:${PROP}>:$<JOIN:${PROP},$<SEMICOLON>>>")
# add compile definitions
set(PROP "$<TARGET_PROPERTY:${TARGET_NAME},COMPILE_DEFINITIONS>")
list(APPEND ARGS_CLANG_OPTIONS "$<$<BOOL:${PROP}>:-D$<JOIN:${PROP},$<SEMICOLON>-D>>")
# add include directories
set(PROP "$<TARGET_PROPERTY:${TARGET_NAME},INCLUDE_DIRECTORIES>")
list(APPEND ARGS_CLANG_OPTIONS "$<$<BOOL:${PROP}>:-I$<JOIN:${PROP},$<SEMICOLON>-I>>")
endforeach()
endif()
# create a custom command for each input file
foreach(INPUT_FILE ${ARGS_INPUT_FILES})
# determine the output file
get_filename_component(OUTPUT_NAME "${INPUT_FILE}" NAME_WE)
set(OUTPUT_FILE "${ARGS_OUTPUT_DIRECTORY}/${OUTPUT_NAME}.h")
message(STATUS "Adding generator command for ${INPUT_FILE} producing ${OUTPUT_FILE}")
# compose the CLI arguments and actually add the custom command
set(CLI_ARGUMENTS
--output-file "${OUTPUT_FILE}"
--input-file "${INPUT_FILE}"
@ -62,6 +91,7 @@ function(add_reflection_generator_invocation)
DEPENDS "${INPUT_FILE}"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
COMMENT "Generating reflection code for ${INPUT_FILE}"
VERBATIM
)
# append the output file to lists specified via OUTPUT_LISTS