Set Clang's resource dir and platform triple correctly

* The option `-resource-dir` must be specified to
  point to Clang's resource directory containing built-in
  header files. Then the massive warnings are gone.
* Setting the platform triple seems to be the right way
  for cross-compilation. Note that the stdlib.h still needs
  to be worked around.
This commit is contained in:
Martchus 2018-02-03 15:44:10 +01:00
parent 4ae20cf38b
commit 54d4a15d4f
5 changed files with 62 additions and 29 deletions

View File

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

View File

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

View File

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

View File

@ -67,7 +67,8 @@ void JsonGeneratorTests::testGeneratorItself()
{
const string inputFilePath(testFilePath("some_structs.h"));
const vector<const char *> inputFiles{ inputFilePath.data() };
const vector<string> clangOptions{ "-I" CPP_UTILITIES_INCLUDE_DIRS, "-I" RAPIDJSON_INCLUDE_DIRS };
const vector<string> 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

View File

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