diff --git a/README.md b/README.md index 2774e47..c0bdee8 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,6 @@ The basic functionality is implemented, tested and documented: ### 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: -* [ ] Fix the massive number of warnings which are currently being created by the code generator * [ ] 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. @@ -157,13 +156,17 @@ from certain targets to the code generator. The targets can be specified using t * 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`: path of the code generator executable built for the platform - you're building on - * `REFLECTION_GENERATOR_INCLUDE_DIRECTORIES:STRING=/custom/prefix/include`: directories containing header files for target - platform (not required if you set `CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES` anyways since it defaults to that variable) -* It is likely required to pass additional options for the target platform. For example, to cross compile with MingGW, is is - required to add `-fdeclspec`, `-D_WIN32` and some more options (see `lib/cmake/modules/ReflectionGenerator.cmake`). The - `add_reflection_generator_invocation` macro is supposed to take care of this, but currently only MingGW under GNU/Linux is supported. + * `REFLECTION_GENERATOR_EXECUTABLE:FILEPATH=/path/to/executable` + * specifies the path of the code generator executable built for the platform you're building on + * only required if executable not in 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: + `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: + `/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. diff --git a/TODOs.md b/TODOs.md index 352a1ea..806890a 100644 --- a/TODOs.md +++ b/TODOs.md @@ -10,7 +10,7 @@ explicitely - [x] Fix traits currently relying on `JsonSerializable` being base class - [x] Allow exporting symbols -- [ ] Fix the massive number of warnings which are currently being created by the code generator +- [x] Fix the massive number of warnings which are currently being created by the code generator (missing `-resource-dir` was the problem) - [ ] Test with libc++ (currently only tested with libstdc++) - [ ] Support templated classes - [ ] Allow (de)serialization of static members (if that makes sense?) diff --git a/generator/CMakeLists.txt b/generator/CMakeLists.txt index 52a6cf2..21f9e07 100644 --- a/generator/CMakeLists.txt +++ b/generator/CMakeLists.txt @@ -91,6 +91,9 @@ if(RapidJSON_FOUND) string(APPEND META_CUSTOM_CONFIG "#define RAPIDJSON_INCLUDE_DIRS \"${RAPIDJSON_INCLUDE_DIRS}\"\n") endif() +# add path of Clang's resource dir to config header so test cases can use it +string(APPEND META_CUSTOM_CONFIG "#define REFLECTION_GENERATOR_CLANG_RESOURCE_DIR \"${REFLECTION_GENERATOR_CLANG_RESOURCE_DIR}\"\n") + # make config header include(ConfigHeader) diff --git a/generator/tests/jsongenerator.cpp b/generator/tests/jsongenerator.cpp index d6cb3ea..3164dbb 100644 --- a/generator/tests/jsongenerator.cpp +++ b/generator/tests/jsongenerator.cpp @@ -67,7 +67,8 @@ void JsonGeneratorTests::testGeneratorItself() { const string inputFilePath(testFilePath("some_structs.h")); const vector inputFiles{ inputFilePath.data() }; - const vector clangOptions{ "-I" CPP_UTILITIES_INCLUDE_DIRS, "-I" RAPIDJSON_INCLUDE_DIRS }; + const vector clangOptions{ "-resource-dir", REFLECTION_GENERATOR_CLANG_RESOURCE_DIR, "-I", CPP_UTILITIES_INCLUDE_DIRS, "-I", + RAPIDJSON_INCLUDE_DIRS }; stringstream buffer; JsonSerializationCodeGenerator::Options jsonOptions; @@ -90,8 +91,9 @@ void JsonGeneratorTests::testCLI() string stdout, stderr; const string inputFilePath(testFilePath("some_structs.h")); - const char *const args1[] = { PROJECT_NAME, "--input-file", inputFilePath.data(), "--json-classes", "TestNamespace2::ThirdPartyStruct", "--clang-opt", - "-I" CPP_UTILITIES_INCLUDE_DIRS, "-I" RAPIDJSON_INCLUDE_DIRS, nullptr }; + const char *const args1[] + = { PROJECT_NAME, "--input-file", inputFilePath.data(), "--json-classes", "TestNamespace2::ThirdPartyStruct", "--clang-opt", "-resource-dir", + REFLECTION_GENERATOR_CLANG_RESOURCE_DIR, "-I", CPP_UTILITIES_INCLUDE_DIRS, "-I", RAPIDJSON_INCLUDE_DIRS, nullptr }; TESTUTILS_ASSERT_EXEC(args1); assertEqualityLinewise(m_expectedCode, toArrayOfLines(stdout)); #endif diff --git a/lib/cmake/modules/ReflectionGenerator.cmake b/lib/cmake/modules/ReflectionGenerator.cmake index 330e94f..78f87bf 100644 --- a/lib/cmake/modules/ReflectionGenerator.cmake +++ b/lib/cmake/modules/ReflectionGenerator.cmake @@ -28,9 +28,30 @@ if(NOT REFLECTION_GENERATOR_EXECUTABLE) message(FATAL_ERROR "Unable to find executable of generator for reflection code. Set REFLECTION_GENERATOR_EXECUTABLE to specify the path.") endif() -# allow to specify a custom include path and use first implicit include directory as default -# (useful for cross-compilation when header files are under custom prefix) -set(REFLECTION_GENERATOR_INCLUDE_DIRECTORIES "${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}" CACHE FILEPATH "include directories for code generator") +# determine Clang's resource directory +set(REFLECTION_GENERATOR_CLANG_RESOURCE_DIR "" CACHE PATH "directory containing Clang's builtin headers, usually /usr/lib/clang/version") +if(NOT REFLECTION_GENERATOR_CLANG_RESOURCE_DIR) + if(NOT REFLECTION_GENERATOR_CLANG_BIN) + find_program(REFLECTION_GENERATOR_CLANG_BIN clang + NAMES clang++ + PATHS "/usr/bin" "/bin" + ) + if(NOT REFLECTION_GENERATOR_CLANG_BIN) + message(FATAL_ERROR "Unable to find the clang executable to determine Clang's resource directory") + endif() + endif() + exec_program(${REFLECTION_GENERATOR_CLANG_BIN} ARGS -print-resource-dir OUTPUT_VARIABLE REFLECTION_GENERATOR_CLANG_RESOURCE_DIR) +endif() +if(NOT REFLECTION_GENERATOR_CLANG_RESOURCE_DIR OR NOT IS_DIRECTORY "${REFLECTION_GENERATOR_CLANG_RESOURCE_DIR}") + message(FATAL_ERROR "Unable to find Clang's resource directory. Set REFLECTION_GENERATOR_CLANG_RESOURCE_DIR manually to the corresponding path (usually /usr/lib/clang/\$version).") +endif() +message(STATUS "Using ${REFLECTION_GENERATOR_CLANG_RESOURCE_DIR} as Clang's resource directory for Reflective RapidJSON") + +# allow to specify a custom include paths (useful for cross-compilation when header files are under custom prefix) +set(REFLECTION_GENERATOR_INCLUDE_DIRECTORIES "" CACHE FILEPATH "include directories for code generator") + +# allow to specify a custom platform tiple (useful for cross-compilation to specify the target platform) +set(REFLECTION_GENERATOR_TRIPLE "" CACHE STRING "platform triple for code generator") # define helper function to add a reflection generator invocation for a specified list of source files include(CMakeParseArguments) @@ -57,34 +78,38 @@ function(add_reflection_generator_invocation) file(MAKE_DIRECTORY "${ARGS_OUTPUT_DIRECTORY}") endif() + # specify Clang's resource directory + list(APPEND ARGS_CLANG_OPTIONS -resource-dir "${REFLECTION_GENERATOR_CLANG_RESOURCE_DIR}") + + # apply specified REFLECTION_GENERATOR_TRIPLET + if(REFLECTION_GENERATOR_TRIPLE) + list(APPEND ARGS_CLANG_OPTIONS + -Xclang -triple + -Xclang "${REFLECTION_GENERATOR_TRIPLE}" + ) + endif() + # apply specified REFLECTION_GENERATOR_INCLUDE_DIRECTORIES foreach(INCLUDE_DIR ${REFLECTION_GENERATOR_INCLUDE_DIRECTORIES}) - list(APPEND ARGS_CLANG_OPTIONS "-isystem ${INCLUDE_DIR}") + list(APPEND ARGS_CLANG_OPTIONS -I "${INCLUDE_DIR}") endforeach() - # add options required for cross compiling with mingw-w64 + # add workaround for cross compiling with mingw-w64 to prevent host stdlib.h being included + # (not sure why specifying REFLECTION_GENERATOR_INCLUDE_DIRECTORIES is not enough to let it find this particular header file) if(MINGW) - # find MinGW version of stdlib.h to ensure that only this version is processed + # find MinGW version of stdlib.h find_file(MINGW_W64_STDLIB_H stdlib.h ${REFLECTION_GENERATOR_INCLUDE_DIRECTORIES}) if(NOT EXISTS "${MINGW_W64_STDLIB_H}") message(FATAL_ERROR "Unable to locate MinGW version of stdlib.h. Ensure it is in REFLECTION_GENERATOR_INCLUDE_DIRECTORIES.") endif() + # ensure libtooling includes the MinGW version of stdlib.h rather than the host version list(APPEND ARGS_CLANG_OPTIONS - # allow __declspec - "-fdeclspec" - # make sure platform detection works as expected - "-D_WIN32" - # ensure libtooling processes the MinGW version of stdlib.h rather than the host version - # (not sure why specifying REFLECTION_GENERATOR_INCLUDE_DIRECTORIES is not enough to let it find the correct header file) - "-include ${MINGW_W64_STDLIB_H}" - # prevent processing of host stdlib.h - "-D_STDLIB_H" + -include "${MINGW_W64_STDLIB_H}" + -D_STDLIB_H # prevent processing of host stdlib.h ) endif() - # TODO: add options for other targets - # 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})