From ee0ca561c0fd54562275fb2b85591dab028c6ffb Mon Sep 17 00:00:00 2001 From: Martchus Date: Sat, 11 Nov 2017 12:37:24 +0100 Subject: [PATCH] Allow exporting generated functions and don't inline by default --- TODOs.md | 1 + generator/CMakeLists.txt | 2 ++ generator/jsonserializationcodegenerator.cpp | 21 ++++++++++++++----- generator/jsonserializationcodegenerator.h | 10 ++++++++- generator/main.cpp | 5 +++-- .../some_structs_json_serialization.h | 8 +++---- lib/cmake/modules/ReflectionGenerator.cmake | 18 ++++++++++------ 7 files changed, 47 insertions(+), 18 deletions(-) diff --git a/TODOs.md b/TODOs.md index 55cfa68..46fe563 100644 --- a/TODOs.md +++ b/TODOs.md @@ -13,6 +13,7 @@ - [x] Add additional parameter for code generator to allow specifying relevant classes explicitely - [x] Fix traits currently relying on `JsonSerializable` being base class +- [x] Allow exporting symbols ## Library-only - [ ] Support `std::unique_ptr` and `std::shared_ptr` diff --git a/generator/CMakeLists.txt b/generator/CMakeLists.txt index 07977ea..34edc25 100644 --- a/generator/CMakeLists.txt +++ b/generator/CMakeLists.txt @@ -63,6 +63,8 @@ add_reflection_generator_invocation( JSON_CLASSES OtherNotJsonSerializable # test specifying classes for JSON (de)serialization manually SomeOtherClassName # specifying a class that does not exist should not cause any problems + JSON_VISIBILITY + LIB_EXPORT # not required, just to test setting visibility ) # include modules to apply configuration diff --git a/generator/jsonserializationcodegenerator.cpp b/generator/jsonserializationcodegenerator.cpp index fcba484..137260d 100644 --- a/generator/jsonserializationcodegenerator.cpp +++ b/generator/jsonserializationcodegenerator.cpp @@ -13,12 +13,17 @@ using namespace ApplicationUtilities; namespace ReflectiveRapidJSON { +/*! + * \brief Initializes the CLI arguments which are specific to the JsonSerializationCodeGenerator. + * \todo Find a more general approach to pass CLI arguments from main() to the particular code generators. + */ JsonSerializationCodeGenerator::Options::Options() - : additionalClassesArg("json-classes", '\0', "specifies additional classes to consider for JSON serialization") + : additionalClassesArg("json-classes", '\0', "specifies additional classes to consider for JSON serialization", { "class-name" }) + , visibilityArg("json-visibility", '\0', "specifies the \"visibility attribute\" for generated functions", { "attribute" }) { - additionalClassesArg.setCombinable(true); - additionalClassesArg.setValueNames({ "class-name" }); additionalClassesArg.setRequiredValueCount(Argument::varValueCount); + additionalClassesArg.setValueCompletionBehavior(ValueCompletionBehavior::None); + visibilityArg.setPreDefinedCompletionValues("LIB_EXPORT"); } /*! @@ -86,6 +91,12 @@ void JsonSerializationCodeGenerator::generate(ostream &os) const os << "namespace ReflectiveRapidJSON {\n" "namespace JsonReflector {\n\n"; + // determine visibility attribute + const char *visibility = m_options.visibilityArg.firstValue(); + if (!visibility) { + visibility = ""; + } + // add push and pull functions for each class, for an example of the resulting // output, see ../lib/tests/jsonserializable.cpp (code under comment "pretend serialization code...") for (const RelevantClass &relevantClass : relevantClasses) { @@ -117,7 +128,7 @@ void JsonSerializationCodeGenerator::generate(ostream &os) const const vector relevantBases = findRelevantBaseClasses(relevantClass, relevantClasses); // print push method - os << "template <> inline void push<::" << relevantClass.qualifiedName << ">(const ::" << relevantClass.qualifiedName + os << "template <> " << visibility << " void push<::" << relevantClass.qualifiedName << ">(const ::" << relevantClass.qualifiedName << " &reflectable, ::RAPIDJSON_NAMESPACE::Value::Object &value, ::RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)\n{\n" " // push base classes\n"; for (const RelevantClass *baseClass : relevantBases) { @@ -132,7 +143,7 @@ void JsonSerializationCodeGenerator::generate(ostream &os) const os << "}\n"; // print pull method - os << "template <> inline void pull<::" << relevantClass.qualifiedName << ">(::" << relevantClass.qualifiedName + os << "template <> " << visibility << " void pull<::" << relevantClass.qualifiedName << ">(::" << relevantClass.qualifiedName << " &reflectable, const ::RAPIDJSON_NAMESPACE::GenericValue<::RAPIDJSON_NAMESPACE::UTF8>::ConstObject &value, " "JsonDeserializationErrors " "*errors)\n{\n" diff --git a/generator/jsonserializationcodegenerator.h b/generator/jsonserializationcodegenerator.h index a011cb1..136eca7 100644 --- a/generator/jsonserializationcodegenerator.h +++ b/generator/jsonserializationcodegenerator.h @@ -15,8 +15,10 @@ class JsonSerializationCodeGenerator : public CodeGenerator { public: struct Options { Options(); + void appendTo(ApplicationUtilities::Argument *arg); - ApplicationUtilities::Argument additionalClassesArg; + ApplicationUtilities::ConfigValueArgument additionalClassesArg; + ApplicationUtilities::ConfigValueArgument visibilityArg; }; private: @@ -43,6 +45,12 @@ private: const Options &m_options; }; +inline void JsonSerializationCodeGenerator::Options::appendTo(ApplicationUtilities::Argument *arg) +{ + arg->addSubArgument(&additionalClassesArg); + arg->addSubArgument(&visibilityArg); +} + inline JsonSerializationCodeGenerator::JsonSerializationCodeGenerator(CodeFactory &factory, const Options &options) : CodeGenerator(factory) , m_options(options) diff --git a/generator/main.cpp b/generator/main.cpp index 8e2eeee..c5c2705 100644 --- a/generator/main.cpp +++ b/generator/main.cpp @@ -38,10 +38,11 @@ int main(int argc, char *argv[]) generatorsArg.setCombinable(true); ConfigValueArgument clangOptionsArg("clang-opt", 'c', "specifies arguments/options to be passed to Clang", { "option" }); clangOptionsArg.setRequiredValueCount(Argument::varValueCount); - JsonSerializationCodeGenerator::Options jsonOptions; HelpArgument helpArg(parser); NoColorArgument noColorArg; - generateArg.setSubArguments({ &inputFileArg, &outputFileArg, &generatorsArg, &clangOptionsArg, &jsonOptions.additionalClassesArg }); + generateArg.setSubArguments({ &inputFileArg, &outputFileArg, &generatorsArg, &clangOptionsArg }); + JsonSerializationCodeGenerator::Options jsonOptions; + jsonOptions.appendTo(&generateArg); parser.setMainArguments({ &generateArg, &noColorArg, &helpArg }); // parse arguments diff --git a/generator/testfiles/some_structs_json_serialization.h b/generator/testfiles/some_structs_json_serialization.h index 23ad972..53e3e0d 100644 --- a/generator/testfiles/some_structs_json_serialization.h +++ b/generator/testfiles/some_structs_json_serialization.h @@ -2,14 +2,14 @@ namespace ReflectiveRapidJSON { namespace JsonReflector { // define code for (de)serializing TestNamespace1::Person objects -template <> inline void push<::TestNamespace1::Person>(const ::TestNamespace1::Person &reflectable, ::RAPIDJSON_NAMESPACE::Value::Object &value, ::RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) +template <> void push<::TestNamespace1::Person>(const ::TestNamespace1::Person &reflectable, ::RAPIDJSON_NAMESPACE::Value::Object &value, ::RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) { // push base classes // push members push(reflectable.age, "age", value, allocator); push(reflectable.alive, "alive", value, allocator); } -template <> inline void pull<::TestNamespace1::Person>(::TestNamespace1::Person &reflectable, const ::RAPIDJSON_NAMESPACE::GenericValue<::RAPIDJSON_NAMESPACE::UTF8>::ConstObject &value, JsonDeserializationErrors *errors) +template <> void pull<::TestNamespace1::Person>(::TestNamespace1::Person &reflectable, const ::RAPIDJSON_NAMESPACE::GenericValue<::RAPIDJSON_NAMESPACE::UTF8>::ConstObject &value, JsonDeserializationErrors *errors) { // pull base classes // set error context for current record @@ -28,14 +28,14 @@ template <> inline void pull<::TestNamespace1::Person>(::TestNamespace1::Person } // define code for (de)serializing TestNamespace2::ThirdPartyStruct objects -template <> inline void push<::TestNamespace2::ThirdPartyStruct>(const ::TestNamespace2::ThirdPartyStruct &reflectable, ::RAPIDJSON_NAMESPACE::Value::Object &value, ::RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) +template <> void push<::TestNamespace2::ThirdPartyStruct>(const ::TestNamespace2::ThirdPartyStruct &reflectable, ::RAPIDJSON_NAMESPACE::Value::Object &value, ::RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) { // push base classes // push members push(reflectable.test1, "test1", value, allocator); push(reflectable.test2, "test2", value, allocator); } -template <> inline void pull<::TestNamespace2::ThirdPartyStruct>(::TestNamespace2::ThirdPartyStruct &reflectable, const ::RAPIDJSON_NAMESPACE::GenericValue<::RAPIDJSON_NAMESPACE::UTF8>::ConstObject &value, JsonDeserializationErrors *errors) +template <> void pull<::TestNamespace2::ThirdPartyStruct>(::TestNamespace2::ThirdPartyStruct &reflectable, const ::RAPIDJSON_NAMESPACE::GenericValue<::RAPIDJSON_NAMESPACE::UTF8>::ConstObject &value, JsonDeserializationErrors *errors) { // pull base classes // set error context for current record diff --git a/lib/cmake/modules/ReflectionGenerator.cmake b/lib/cmake/modules/ReflectionGenerator.cmake index 130df0c..123f71c 100644 --- a/lib/cmake/modules/ReflectionGenerator.cmake +++ b/lib/cmake/modules/ReflectionGenerator.cmake @@ -31,7 +31,7 @@ include(CMakeParseArguments) function(add_reflection_generator_invocation) # parse arguments set(OPTIONAL_ARGS) - set(ONE_VALUE_ARGS OUTPUT_DIRECTORY) + set(ONE_VALUE_ARGS OUTPUT_DIRECTORY JSON_VISIBILITY) set(MULTI_VALUE_ARGS INPUT_FILES GENERATORS OUTPUT_LISTS CLANG_OPTIONS JSON_CLASSES) cmake_parse_arguments(ARGS "${OPTIONAL_ARGS}" "${ONE_VALUE_ARGS}" "${MULTI_VALUE_ARGS}" ${ARGN}) @@ -45,14 +45,20 @@ function(add_reflection_generator_invocation) 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}") + set(CLI_ARGUMENTS + --output-file "${OUTPUT_FILE}" + --input-file "${INPUT_FILE}" + --generators ${ARGS_GENERATORS} + --clang-opt ${ARGS_CLANG_OPTIONS} + --json-classes ${ARGS_JSON_CLASSES} + ) + if(ARGS_JSON_VISIBILITY) + list(APPEND CLI_ARGUMENTS --json-visibility "${ARGS_JSON_VISIBILITY}") + endif() add_custom_command( OUTPUT "${OUTPUT_FILE}" COMMAND "${REFLECTION_GENERATOR_EXECUTABLE}" - --output-file "${OUTPUT_FILE}" - --input-file "${INPUT_FILE}" - --generators ${ARGS_GENERATORS} - --clang-opt ${ARGS_CLANG_OPTIONS} - --json-classes ${ARGS_JSON_CLASSES} + ARGS ${CLI_ARGUMENTS} DEPENDS "${INPUT_FILE}" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMMENT "Generating reflection code for ${INPUT_FILE}"