Allow to disable jsoncpp
If a software tries to integrate rapidlib but already uses jsoncpp, then this is undefined behaviour which gets flagged by addresssanitizer for instance.
I encountered this while trying to integrate RapidLib with https://ossia.io : ossia integrates sh4lt which is a completely different package for sharing video frames across processes on Linux. sh4lt also uses jsoncpp as part of its implementation thus jsoncpp symbols are defined twice (and the unlucky software crashes on startup).
Does it work if json.cpp is included privately? Like:
target_sources(${PROJECT_NAME} PRIVATE ${JSON_SRC})
?
oops, I should fix that on my PR, a .cpp should never be target_sources(PUBLIC)
I was wondering if there was a conflict if RapidLib integrates json.cpp privately. I think it should not conflict with sh4lt then. That's what "private" means, right?
I just pushed some changes that might resolve your issue.
heya!
sadly this is not what target_sources(... PRIVATE ...) does. this is the default mode of adding sources when doing add_library(...)
target_sources(target PUBLIC foo.cpp bar.cpp) is only relevant when building INTERFACE libraries (e.g. "virtual" cmake targets that do not directly build anything themselves but can be useful to easily make other targets inherit a set of properties)
For instance if I do, given example.cpp:
int main() { return VARIABLE; }
add_library(foo INTERFACE)
target_sources(foo PUBLIC example.cpp)
add_executable(exe1)
add_executable(exe2)
add_executable(exe3)
target_compile_definitions(exe1 PRIVATE VARIABLE=10)
target_compile_definitions(exe2 PRIVATE VARIABLE=20)
target_compile_definitions(exe3 PRIVATE VARIABLE=30)
target_link_libraries(exe1 PRIVATE foo)
target_link_libraries(exe2 PRIVATE foo)
target_link_libraries(exe3 PRIVATE foo)
then the following build commands will be run:
/usr/bin/c++ -DVARIABLE=10 -MD -MT CMakeFiles/exe1.dir/example.cpp.o -MF CMakeFiles/exe1.dir/example.cpp.o.d -o CMakeFiles/exe1.dir/example.cpp.o -c /tmp/x/example.cpp
/usr/bin/c++ -DVARIABLE=20 -MD -MT CMakeFiles/exe2.dir/example.cpp.o -MF CMakeFiles/exe2.dir/example.cpp.o.d -o CMakeFiles/exe2.dir/example.cpp.o -c /tmp/x/example.cpp
/usr/bin/c++ -DVARIABLE=30 -MD -MT CMakeFiles/exe3.dir/example.cpp.o -MF CMakeFiles/exe3.dir/example.cpp.o.d -o CMakeFiles/exe3.dir/example.cpp.o -c /tmp/x/example.cpp
e.g. each target will build the file independently just like if I had done
add_executable(exe1 example.cpp)
add_executable(exe2 example.cpp)
add_executable(exe3 example.cpp)
In the case of building a library like rapidlib we never want this because this will cause duplicate symbols and the build will just fail: if you do:
add_library(rapidlib)
target_sources(rapidlib PUBLIC source.cpp)
add_executable(app)
target_link_libraries(app PRIVATE rapidlib)
then librapidlib.a will contains the symbols of source.cpp, but app will ALSO have its copy of source.cpp built along with it, and those symbols will clash (if it even builds).
There's really zero way to have multiple times the same symbol in a given single C++ executable, this is against the standard: https://en.wikipedia.org/wiki/One_Definition_Rule
At the root this isn't even a C++ issue but an operating system issue: the operating systems' executable formats (PE on windows, ELF on Linux and MachO on Mac) only support one symbol with a given name per binary as those are basically just a hashmap (symbol name -> offset in the binary) ; if a build creates two symbols with the same name at best one gets picked at random, and if it's from two versions of say, jsoncpp, then you could have one method taken from version A and another from version B and if the data structures have changed between versions then crashes will 100% happen.
The two options are:
1/ allow to enable / disable the third-party libraries 2/ make sure that every dependency can be obtained through find_package instead of vendored.
What I do in my libs is leave the choice so that people using them can either use the quick way or have more control depending on their needs and the existing libraries they may already have in their build infrastructure:
https://github.com/ossia/libossia/blob/master/cmake/deps/ctre.cmake
Thanks for the excellent response, and thanks for your patience.
I've just pushed a version on the dev branch that only exports symbols from the library. Does that help?