Allow exporting generated functions and don't inline by default

This commit is contained in:
Martchus 2017-11-11 12:37:24 +01:00
parent 9f0f208f28
commit ee0ca561c0
7 changed files with 47 additions and 18 deletions

View File

@ -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`

View File

@ -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

View File

@ -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<const RelevantClass *> 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<char>>::ConstObject &value, "
"JsonDeserializationErrors "
"*errors)\n{\n"

View File

@ -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)

View File

@ -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

View File

@ -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<char>>::ConstObject &value, JsonDeserializationErrors *errors)
template <> void pull<::TestNamespace1::Person>(::TestNamespace1::Person &reflectable, const ::RAPIDJSON_NAMESPACE::GenericValue<::RAPIDJSON_NAMESPACE::UTF8<char>>::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<char>>::ConstObject &value, JsonDeserializationErrors *errors)
template <> void pull<::TestNamespace2::ThirdPartyStruct>(::TestNamespace2::ThirdPartyStruct &reflectable, const ::RAPIDJSON_NAMESPACE::GenericValue<::RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value, JsonDeserializationErrors *errors)
{
// pull base classes
// set error context for current record

View File

@ -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}"