Improve README and make it work with md2pdf

This commit is contained in:
Martchus 2018-02-05 21:32:05 +01:00
parent 9e11d805c1
commit e6c54a37e4
1 changed files with 48 additions and 43 deletions

View File

@ -18,27 +18,28 @@ The reflection implementation used behind the scenes of this library is exchange
## Current state
The basic functionality is implemented, tested and documented:
* serialization and deserialization of datatypes listed under "Supported datatypes"
* nesting and inheritance is possible
* adapting 3rdparty structs/classes is supported
* basic error handling when deserializing
* Serialization and deserialization of datatypes listed under "Supported datatypes"
* Nesting and inheritance is possible
* Adapting 3rdparty structs/classes is supported
* Basic error handling when deserializing
* CMake macro to conveniently include the code generator into the build process
* allow to use Boost.Hana
* Allow to use Boost.Hana
### TODOs
There are still things missing which would likely be very useful in practise. The following list contains the open TODOs which are supposed to be most relevant in practise:
### Planned features and TODOs
There are still things missing which would likely be very useful in practise. The following list contains the
open TODOs which are supposed to be most relevant in practise:
* [ ] Allow to specify which member variables should be considered
* This could work similar to Qt's Signals & Slots macros.
* but there should also be a way to do this for 3rdparty types.
* Note that currently, *all* public member variables are (de)serialized.
* But there should also be a way to do this for 3rdparty types.
* Note that currently all public, non-static member variables are (de)serialized.
* [ ] Support getter/setter methods
* [ ] Allow to serialize the result of methods
* [ ] Allow to pass a deserialized value to a method
* [ ] Validate enum values when deserializing
* [ ] Untie serialization and deserialization
For a full list of TODOs, see [TODOs.md](./TODOs.md).
For a full list of further ideas, see [TODOs.md](./TODOs.md).
## Supported datatypes
The following table shows the mapping of supported C++ types to supported JSON types:
@ -74,7 +75,7 @@ The following table shows the mapping of supported C++ types to supported JSON t
## Usage
This example shows how the library can be used to make a `struct` serializable:
```
<pre>
#include <reflective_rapidjson/json/serializable.h>
// define structures, eg.
@ -103,22 +104,26 @@ const auto obj = NestingArray::fromJson(...);
// in exactly one of the project's translation units
#include "reflection/code-defining-structs.h"
```
</pre>
Note that the header included at the bottom must be generated by invoking the code generator appropriately, eg.:
```
reflective_rapidjson_generator --input-file "$srcdir/code-defining-structs.cpp" --output-file "$builddir/reflection/code-defining-structs.h"
```
<pre>
reflective_rapidjson_generator \
--input-file "$srcdir/code-defining-structs.cpp" \
--output-file "$builddir/reflection/code-defining-structs.h"
</pre>
#### Invoking code generator with CMake macro
It is possible to use the provided CMake macro to automate the code generator invocation:
```
<pre>
# find the package and make macro available
find_package(reflective-rapidjson REQUIRED)
list(APPEND CMAKE_MODULE_PATH ${REFLECTIVE_RAPIDJSON_MODULE_DIRS})
include(ReflectionGenerator)
# "link" against reflective_rapidjson (it is a header-only lib so this will only add the required include paths to your target)
# "link" against reflective_rapidjson
# it is a header-only lib so this will only add the required include paths
# to your target
target_link_libraries(mytarget PRIVATE reflective_rapidjson)
# invoke macro
@ -128,14 +133,14 @@ add_reflection_generator_invocation(
OUTPUT_LISTS LIST_OF_GENERATED_HEADERS
CLANG_OPTIONS_FROM_TARGETS mytarget
)
```
</pre>
This will produce the file `code-defining-structs.h` in the directory `reflection` in the current build directory. So
make sure the current build directory is added to the include directories of your target. The default output directory can
also be overridden by passing `OUTPUT_DIRECTORY custom/directory` to the arguments.
It is possible to specify multiple input files at once. A separate output file is generated for each input. The output files
will always have the extension "`.h`", independently of the extension of the input file.
will always have the extension `.h`, independently of the extension of the input file.
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.
@ -164,23 +169,24 @@ To adjust the default location, just add eg. `--clang-opt -resource-dir /usr/lib
It makes most sense to specify the same options for the code generator as during the actual compilation. This way 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 be specified using the `CLANG_OPTIONS_FROM_TARGETS` argument.
from certain targets to the code generator. Those targets can be specified using the
Macro's `CLANG_OPTIONS_FROM_TARGETS` argument.
#### Notes regarding cross-compilation
* For cross compilation, it is required to build the code generator for the platform you're building on.
* Since the code generator is likely not required under the target platform, you should add `-DNO_GENERATOR:BOOL=ON` to the CMake
arguments when building Reflective RapidJSON for the target platform.
* When using the `add_reflection_generator_invocation` macro, you need to set the following CMake cache variables:
* `REFLECTION_GENERATOR_EXECUTABLE:FILEPATH=/path/to/executable`
* `REFLECTION_GENERATOR_EXECUTABLE:FILEPATH=/path/to/reflective_rapidjson_generator`
* specifies the path of the code generator executable built for the platform you're building on
* only required if executable not in path anyways
* only required if the executable is not in the path anyways
* `REFLECTION_GENERATOR_TRIPLE:STRING=machine-vendor-operatingsystem`
* specifies the GNU platform triple for the target platform
* examples for cross compiling with mingw-w64 under GNU/Linux:
* examples for cross compiling with mingw-w64 under GNU/Linux:
`x86_64-w64-mingw32`, `i686-w64-mingw32`
* `REFLECTION_GENERATOR_INCLUDE_DIRECTORIES:STRING=/custom/prefix/include`
* directories containing header files for target platform
* example for cross compiling with mingw-w64 under GNU/Linux:
* implicit include directories for target platform
* example for cross compiling with mingw-w64 under GNU/Linux:
`/usr/lib/gcc/x86_64-w64-mingw32/7.2.1/include;/usr/x86_64-w64-mingw32/include/c++/7.2.1/x86_64-w64-mingw32;/usr/x86_64-w64-mingw32/include`
* The Arch Linux packages mentioned at the end of the README file also include `mingw-w64` variants which give a concrete example how
cross-compilation can be done.
@ -188,7 +194,7 @@ from certain targets to the code generator. The targets can be specified using t
### 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.
```
<pre>
#include "<reflective_rapidjson/json/serializable-boosthana.h>
// define structures using BOOST_HANA_DEFINE_STRUCT, eg.
@ -220,7 +226,7 @@ cout << "JSON: " << obj.toJson().GetString();
// deserialize from JSON
const auto obj = NestingArray::fromJson(...);
```
</pre>
So beside the `BOOST_HANA_DEFINE_STRUCT` macro, the usage remains the same.
@ -229,7 +235,6 @@ So beside the `BOOST_HANA_DEFINE_STRUCT` macro, the usage remains the same.
* No context information for errors like type-mismatch available
* Inherited members not considered
* Proper support for enums is unlikely
* Attempt to access private members can not be prevented
### Enable reflection for 3rd party classes/structs
It is obvious that the previously shown examples do not work for classes
@ -240,7 +245,7 @@ To work around this issue, one can use the `REFLECTIVE_RAPIDJSON_MAKE_JSON_SERIA
macro. It will enable the `toJson` and `fromJson` methods for the specified class
in the `ReflectiveRapidJSON::JsonReflector` namespace:
```
<pre>
// somewhere in included header
struct ThridPartyStruct
{ ... };
@ -251,7 +256,7 @@ REFLECTIVE_RAPIDJSON_MAKE_JSON_SERIALIZABLE(ThridPartyStruct)
// (de)serialization
ReflectiveRapidJSON::JsonReflector::toJson(...).GetString();
ReflectiveRapidJSON::JsonReflector::fromJson<ThridPartyStruct>("...");
```
</pre>
The code generator will emit the code in the same way as if `JsonSerializable` was
used.
@ -264,7 +269,7 @@ By default, private members are not considered for (de)serialization. However, i
to enable this by adding `friend` methods for the helper functions of Reflective RapidJSON.
To make things easier, there's a macro provided:
```
<pre>
struct SomeStruct : public JsonSerializable<SomeStruct> {
REFLECTIVE_RAPIDJSON_ENABLE_PRIVATE_MEMBERS(SomeStruct);
@ -274,7 +279,7 @@ public:
private:
std::string privateMember = "will be (de)serialized with the help of REFLECTIVE_RAPIDJSON_ENABLE_PRIVATE_MEMBERS macro";
};
```
</pre>
#### Caveats
* It will obviously not work for 3rd party structs.
@ -285,15 +290,15 @@ private:
### Custom (de)serialization
Sometimes it is appropriate to implement custom (de)serialization. For instance, a
custom object representing a time value should likey be serialized as a string rather
than an object with the internal data members.
than an object containing the internal structure.
An example for such custom (de)serialization can be found in the file
`json/reflector-chronoutilities.h`. It provides (de)serialization of `DateTime` and
`TimeSpan` objects from the C++ utilities library.
`TimeSpan` objects from the C++ utilities library mentioned under dependencies.
### Remarks
* Static member variables are currently ignored by the generator.
* It is currently not possible to ignore a specific member.
* Static member variables and member functions are currently ignored by the generator.
* It is currently not possible to ignore a specific member variable.
### Further examples
* Checkout the test cases for further examples. Relevant files are in
@ -340,7 +345,7 @@ Reflective RapidJSON.
provided (so far).
* I usually develop using the latest version of those dependencies. So it is recommend to get the
the latest versions as well. I tested the following versions so far:
* GCC 7.2.1 or Clang 5.0 as compiler
* GCC 7.2.1/7.3.0 or Clang 5.0 as compiler
* libstdc++ from GCC 7.2.1
* CMake 3.10.1
* Clang 5.0.0/5.0.1 for LibTooling
@ -370,12 +375,12 @@ you can skip this step of course.
To specify custom locations, just set some environment variables before invoking CMake. This
can likely be done in your IDE settings and of course at command line. Here is a Bash example:
```
<pre>
export PATH=$CUSTOM_INSTALL_PREFIX/bin:$PATH
export CMAKE_PREFIX_PATH=$CUSTOM_INSTALL_PREFIX:$CMAKE_PREFIX_PATH
export CMAKE_LIBRARY_PATH=$CUSTOM_INSTALL_PREFIX/lib:$CMAKE_LIBRARY_PATH
export CMAKE_INCLUDE_PATH=$CUSTOM_INSTALL_PREFIX/include:$CMAKE_INCLUDE_PATH
```
</pre>
There are also a lot of [useful variables](https://cmake.org/Wiki/CMake_Useful_Variables)
that can be specified as CMake arguments. It is also possible to create a
@ -383,17 +388,17 @@ that can be specified as CMake arguments. It is also possible to create a
#### 3. Get sources, eg. using Git:
```
<pre>
cd $SOURCES
git clone https://github.com/Martchus/cpp-utilities.git c++utilities
git clone https://github.com/Martchus/reflective-rapidjson.git
```
</pre>
If you don't want to build the development version, just checkout the desired version tag.
#### 4. Run the build script
Here is an example for building with GNU Make:
```
<pre>
cd $BUILD_DIR
# generate Makefile
cmake \
@ -411,7 +416,7 @@ make tests
make apidoc
# install header files, libraries and generator
make install DESTDIR="/temporary/install/location"
```
</pre>
Add eg. `-j$(nproc)` to `make` arguments for using all cores.
### Packages