Allow exporting generated functions and don't inline by default
This commit is contained in:
parent
9f0f208f28
commit
ee0ca561c0
1
TODOs.md
1
TODOs.md
|
@ -13,6 +13,7 @@
|
||||||
- [x] Add additional parameter for code generator to allow specifying relevant classes
|
- [x] Add additional parameter for code generator to allow specifying relevant classes
|
||||||
explicitely
|
explicitely
|
||||||
- [x] Fix traits currently relying on `JsonSerializable` being base class
|
- [x] Fix traits currently relying on `JsonSerializable` being base class
|
||||||
|
- [x] Allow exporting symbols
|
||||||
|
|
||||||
## Library-only
|
## Library-only
|
||||||
- [ ] Support `std::unique_ptr` and `std::shared_ptr`
|
- [ ] Support `std::unique_ptr` and `std::shared_ptr`
|
||||||
|
|
|
@ -63,6 +63,8 @@ add_reflection_generator_invocation(
|
||||||
JSON_CLASSES
|
JSON_CLASSES
|
||||||
OtherNotJsonSerializable # test specifying classes for JSON (de)serialization manually
|
OtherNotJsonSerializable # test specifying classes for JSON (de)serialization manually
|
||||||
SomeOtherClassName # specifying a class that does not exist should not cause any problems
|
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
|
# include modules to apply configuration
|
||||||
|
|
|
@ -13,12 +13,17 @@ using namespace ApplicationUtilities;
|
||||||
|
|
||||||
namespace ReflectiveRapidJSON {
|
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()
|
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.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"
|
os << "namespace ReflectiveRapidJSON {\n"
|
||||||
"namespace JsonReflector {\n\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
|
// 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...")
|
// output, see ../lib/tests/jsonserializable.cpp (code under comment "pretend serialization code...")
|
||||||
for (const RelevantClass &relevantClass : relevantClasses) {
|
for (const RelevantClass &relevantClass : relevantClasses) {
|
||||||
|
@ -117,7 +128,7 @@ void JsonSerializationCodeGenerator::generate(ostream &os) const
|
||||||
const vector<const RelevantClass *> relevantBases = findRelevantBaseClasses(relevantClass, relevantClasses);
|
const vector<const RelevantClass *> relevantBases = findRelevantBaseClasses(relevantClass, relevantClasses);
|
||||||
|
|
||||||
// print push method
|
// 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"
|
<< " &reflectable, ::RAPIDJSON_NAMESPACE::Value::Object &value, ::RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)\n{\n"
|
||||||
" // push base classes\n";
|
" // push base classes\n";
|
||||||
for (const RelevantClass *baseClass : relevantBases) {
|
for (const RelevantClass *baseClass : relevantBases) {
|
||||||
|
@ -132,7 +143,7 @@ void JsonSerializationCodeGenerator::generate(ostream &os) const
|
||||||
os << "}\n";
|
os << "}\n";
|
||||||
|
|
||||||
// print pull method
|
// 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, "
|
<< " &reflectable, const ::RAPIDJSON_NAMESPACE::GenericValue<::RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value, "
|
||||||
"JsonDeserializationErrors "
|
"JsonDeserializationErrors "
|
||||||
"*errors)\n{\n"
|
"*errors)\n{\n"
|
||||||
|
|
|
@ -15,8 +15,10 @@ class JsonSerializationCodeGenerator : public CodeGenerator {
|
||||||
public:
|
public:
|
||||||
struct Options {
|
struct Options {
|
||||||
Options();
|
Options();
|
||||||
|
void appendTo(ApplicationUtilities::Argument *arg);
|
||||||
|
|
||||||
ApplicationUtilities::Argument additionalClassesArg;
|
ApplicationUtilities::ConfigValueArgument additionalClassesArg;
|
||||||
|
ApplicationUtilities::ConfigValueArgument visibilityArg;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -43,6 +45,12 @@ private:
|
||||||
const Options &m_options;
|
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)
|
inline JsonSerializationCodeGenerator::JsonSerializationCodeGenerator(CodeFactory &factory, const Options &options)
|
||||||
: CodeGenerator(factory)
|
: CodeGenerator(factory)
|
||||||
, m_options(options)
|
, m_options(options)
|
||||||
|
|
|
@ -38,10 +38,11 @@ int main(int argc, char *argv[])
|
||||||
generatorsArg.setCombinable(true);
|
generatorsArg.setCombinable(true);
|
||||||
ConfigValueArgument clangOptionsArg("clang-opt", 'c', "specifies arguments/options to be passed to Clang", { "option" });
|
ConfigValueArgument clangOptionsArg("clang-opt", 'c', "specifies arguments/options to be passed to Clang", { "option" });
|
||||||
clangOptionsArg.setRequiredValueCount(Argument::varValueCount);
|
clangOptionsArg.setRequiredValueCount(Argument::varValueCount);
|
||||||
JsonSerializationCodeGenerator::Options jsonOptions;
|
|
||||||
HelpArgument helpArg(parser);
|
HelpArgument helpArg(parser);
|
||||||
NoColorArgument noColorArg;
|
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 });
|
parser.setMainArguments({ &generateArg, &noColorArg, &helpArg });
|
||||||
|
|
||||||
// parse arguments
|
// parse arguments
|
||||||
|
|
|
@ -2,14 +2,14 @@ namespace ReflectiveRapidJSON {
|
||||||
namespace JsonReflector {
|
namespace JsonReflector {
|
||||||
|
|
||||||
// define code for (de)serializing TestNamespace1::Person objects
|
// 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 base classes
|
||||||
// push members
|
// push members
|
||||||
push(reflectable.age, "age", value, allocator);
|
push(reflectable.age, "age", value, allocator);
|
||||||
push(reflectable.alive, "alive", 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
|
// pull base classes
|
||||||
// set error context for current record
|
// 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
|
// 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 base classes
|
||||||
// push members
|
// push members
|
||||||
push(reflectable.test1, "test1", value, allocator);
|
push(reflectable.test1, "test1", value, allocator);
|
||||||
push(reflectable.test2, "test2", 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
|
// pull base classes
|
||||||
// set error context for current record
|
// set error context for current record
|
||||||
|
|
|
@ -31,7 +31,7 @@ include(CMakeParseArguments)
|
||||||
function(add_reflection_generator_invocation)
|
function(add_reflection_generator_invocation)
|
||||||
# parse arguments
|
# parse arguments
|
||||||
set(OPTIONAL_ARGS)
|
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)
|
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})
|
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)
|
get_filename_component(OUTPUT_NAME "${INPUT_FILE}" NAME_WE)
|
||||||
set(OUTPUT_FILE "${ARGS_OUTPUT_DIRECTORY}/${OUTPUT_NAME}.h")
|
set(OUTPUT_FILE "${ARGS_OUTPUT_DIRECTORY}/${OUTPUT_NAME}.h")
|
||||||
message(STATUS "Adding generator command for ${INPUT_FILE} producing ${OUTPUT_FILE}")
|
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(
|
add_custom_command(
|
||||||
OUTPUT "${OUTPUT_FILE}"
|
OUTPUT "${OUTPUT_FILE}"
|
||||||
COMMAND "${REFLECTION_GENERATOR_EXECUTABLE}"
|
COMMAND "${REFLECTION_GENERATOR_EXECUTABLE}"
|
||||||
--output-file "${OUTPUT_FILE}"
|
ARGS ${CLI_ARGUMENTS}
|
||||||
--input-file "${INPUT_FILE}"
|
|
||||||
--generators ${ARGS_GENERATORS}
|
|
||||||
--clang-opt ${ARGS_CLANG_OPTIONS}
|
|
||||||
--json-classes ${ARGS_JSON_CLASSES}
|
|
||||||
DEPENDS "${INPUT_FILE}"
|
DEPENDS "${INPUT_FILE}"
|
||||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
COMMENT "Generating reflection code for ${INPUT_FILE}"
|
COMMENT "Generating reflection code for ${INPUT_FILE}"
|
||||||
|
|
Loading…
Reference in New Issue