From eafd702a17163160a911368f0a3475b49f673738 Mon Sep 17 00:00:00 2001 From: Baptiste Lepilleur Date: Wed, 8 May 2013 20:21:11 +0000 Subject: [PATCH] - New CMake based build system. Based in part on contribution from Igor Okulist and Damien Buhl (Patch #14). Added support for running tests and building with DLL on Windows. - added missing JSON_API - Visual Studio DLL: suppressed warning "C4251: : needs to have dll-interface to be used by..." via pragma push/pop in json-cpp headers. - New header json/version.h now contains version number macros (JSONCPP_VERSION_MAJOR, JSONCPP_VERSION_MINOR, JSONCPP_VERSION_PATCH and JSONCPP_VERSION_HEXA). While this header is generated by CMake, it is committed to ease build with alternate build system (CMake only update the file when it changes avoid issues with VCS). --- CMakeLists.txt | 71 +++++++++++++++++++++++++++++++ NEWS.txt | 19 +++++++-- README.txt | 70 ++++++++++++++++++++++++------ amalgamate.py | 1 + include/CMakeLists.txt | 2 + include/json/config.h | 13 ++++-- include/json/reader.h | 14 +++++- include/json/value.h | 12 ++++++ include/json/version.h | 14 ++++++ include/json/writer.h | 13 +++++- src/CMakeLists.txt | 5 +++ src/jsontestrunner/CMakeLists.txt | 23 ++++++++++ src/lib_json/CMakeLists.txt | 43 +++++++++++++++++++ src/lib_json/version.h.in | 14 ++++++ src/test_lib_json/CMakeLists.txt | 21 +++++++++ 15 files changed, 314 insertions(+), 21 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 include/CMakeLists.txt create mode 100644 include/json/version.h create mode 100644 src/CMakeLists.txt create mode 100644 src/jsontestrunner/CMakeLists.txt create mode 100644 src/lib_json/CMakeLists.txt create mode 100644 src/lib_json/version.h.in create mode 100644 src/test_lib_json/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..21c0ebe --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,71 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(jsoncpp) +ENABLE_TESTING() + +OPTION(JSONCPP_WITH_TESTS "Compile and run JsonCpp test executables" ON) +OPTION(JSONCPP_WITH_POST_BUILD_UNITTEST "Automatically run unit-tests as a post build step" ON) + +# Ensures that CMAKE_BUILD_TYPE is visible in cmake-gui on Unix +IF(NOT WIN32) + IF(NOT CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE Release CACHE STRING + "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel Coverage." + FORCE) + ENDIF(NOT CMAKE_BUILD_TYPE) +ENDIF(NOT WIN32) + +# This ensures shared DLL are in the same dir as executable on Windows. +# Put all executables / libraries are in a project global directory. +SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib + CACHE PATH "Single directory for all static libraries.") +SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib + CACHE PATH "Single directory for all dynamic libraries on Unix.") +SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin + CACHE PATH "Single directory for all executable and dynamic libraries on Windows.") +MARK_AS_ADVANCED( CMAKE_RUNTIME_OUTPUT_DIRECTORY CMAKE_LIBRARY_OUTPUT_DIRECTORY CMAKE_ARCHIVE_OUTPUT_DIRECTORY ) + +# Set variable named ${VAR_NAME} to value ${VALUE} +FUNCTION(set_using_dynamic_name VAR_NAME VALUE) + SET( "${VAR_NAME}" "${VALUE}" PARENT_SCOPE) +ENDFUNCTION(set_using_dynamic_name) + +# Extract major, minor, patch and qualifier from version text +# Parse a version string "X.Y.Z[-qualifier]" and outputs +# version parts in ${OUPUT_PREFIX}_MAJOR, _MINOR, _PATCH, _QUALIFIER. +# If parse succed then ${OUPUT_PREFIX}_FOUND is TRUE. +MACRO(jsoncpp_parse_version VERSION_TEXT OUPUT_PREFIX) + SET(VERSION_REGEX "[0-9]+\\.[0-9]+\\.[0-9]+(-[a-zA-Z0-9_]+)?") + IF( ${VERSION_TEXT} MATCHES ${VERSION_REGEX} ) + STRING(REGEX MATCHALL "[0-9]+|-([A-Za-z0-9_]+)" VERSION_PARTS ${VERSION_TEXT}) + list(APPEND VERSION_PARTS "") # empty qualifier to handle no qualifier case + LIST(GET VERSION_PARTS 0 ${OUPUT_PREFIX}_MAJOR) + LIST(GET VERSION_PARTS 1 ${OUPUT_PREFIX}_MINOR) + LIST(GET VERSION_PARTS 2 ${OUPUT_PREFIX}_PATCH) + LIST(GET VERSION_PARTS 3 ${OUPUT_PREFIX}_QUALIFIER) + set_using_dynamic_name( "${OUPUT_PREFIX}_FOUND" TRUE ) + ELSE( ${VERSION_TEXT} MATCHES ${VERSION_REGEX} ) + set_using_dynamic_name( "${OUPUT_PREFIX}_FOUND" FALSE ) + ENDIF( ${VERSION_TEXT} MATCHES ${VERSION_REGEX} ) +ENDMACRO(jsoncpp_parse_version) + +# Read out version from "version" file +FILE(STRINGS "version" JSONCPP_VERSION) + +jsoncpp_parse_version( ${JSONCPP_VERSION} JSONCPP_VERSION ) +IF(NOT JSONCPP_VERSION_FOUND) + MESSAGE(FATAL_ERROR "Failed to parse version string properly. Expect X.Y.Z[-qualifier]") +ENDIF(NOT JSONCPP_VERSION_FOUND) + +MESSAGE(STATUS "JsonCpp Version: ${JSONCPP_VERSION_MAJOR}.${JSONCPP_VERSION_MINOR}.${JSONCPP_VERSION_PATCH}${JSONCPP_VERSION_QUALIFIER}") +# File version.h is only regenerated on CMake configure step +CONFIGURE_FILE( "${PROJECT_SOURCE_DIR}/src/lib_json/version.h.in" + "${PROJECT_SOURCE_DIR}/include/json/version.h" ) + +# Include our configuration header +INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/include ) + +# Build the different applications +ADD_SUBDIRECTORY( src ) + +#install the includes +ADD_SUBDIRECTORY( include ) diff --git a/NEWS.txt b/NEWS.txt index ae4005d..193d166 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -32,21 +32,32 @@ New in SVN maxInt64 to figure out whether it is approximately representable. * Value - - Patch #3393345: BOOST_FOREACH compatibility. Made Json::iterator more + - Patch #10: BOOST_FOREACH compatibility. Made Json::iterator more standard compliant, added missing iterator_category and value_type typedefs (contribued by Robert A. Iannucci). * Compilation - - Patch #3474563: added missing JSON_API on some classes causing link issues + - New CMake based build system. Based in part on contribution from + Igor Okulist and Damien Buhl (Patch #14). + + - New header json/version.h now contains version number macros + (JSONCPP_VERSION_MAJOR, JSONCPP_VERSION_MINOR, JSONCPP_VERSION_PATCH + and JSONCPP_VERSION_HEXA). + + - Patch #11: added missing JSON_API on some classes causing link issues when building as a dynamic library on Windows (contributed by Francis Bolduc). + + - Visual Studio DLL: suppressed warning "C4251: : + needs to have dll-interface to be used by..." via pragma push/pop + in json-cpp headers. * Bug fixes - - Patch #3539678: Copy constructor does not initialize allocated_ for stringValue + - Patch #15: Copy constructor does not initialize allocated_ for stringValue (contributed by rmongia). - - Patch #3600941: Missing field copy in Json::Value::iterator causing infinite + - Patch #16: Missing field copy in Json::Value::iterator causing infinite loop when using experimental internal map (#define JSON_VALUE_USE_INTERNAL_MAP) (contributed by Ming-Lin Kao). diff --git a/README.txt b/README.txt index 88c1178..ca3a486 100644 --- a/README.txt +++ b/README.txt @@ -13,9 +13,65 @@ making it a convenient format to store user input files. Unserialization parsing is user friendly and provides precise error reports. +* Using json-cpp in your project: + =============================== -* Building/Testing: - ================= +The recommended approach to integrate json-cpp in your project is to +build the the amalgamated source (a single .cpp) with your own build +system. This ensures compilation flags consistency and ABI compatibility. + +See section "Generating amalgamated source and header" to generate them +from the source distribution. + +Directory include/ should be added to your compiler include path. +json-cpp headers should be included as follow: + + #include + +If json-cpp was build as a dynamic library on Windows, then your project +need to define macro "JSON_DLL" to JSON_API should import exported symbols. + +* Building/Testing with new CMake build system: + ============================================= + +CMake is a C++ Makefiles/Solution generator that can be downloaded from: + http://www.cmake.org + +It is usually available on most Linux system as package. On Ubuntu: + sudo apt-get install cmake + +Notes that python is also required to run JSON reader/writer tests. If +missing, the build will skip running those tests. + +When running CMake, a few parameters are required: +- a build directory where the makefiles/solution are generated. It is + also used to store objects, libraries and executables files. +- the generator to use: makefiles or Visual Studio solution? What version + or Visual Studio, 32 or 64 bits solution? + +Generating solution/makefiles using cmake-gui: +- Makes "source code" points the source directory +- Makes "where to build the binary" points to the directory to use for + the build. +- Click on the "Grouped" check box +- Review JsonCpp build option (tick JSONCPP_LIB_BUILD_SHARED to build as + a dynamic library) +- Click configure button at the bottom, then the generate button. +- The generated solution/makefiles can be found in the binary directory. + +Alternatively, from the command-line on Unix in the source directory: + + mkdir -p ../build/debug + cmake -DCMAKE_BUILD_TYPE=debug -DJSONCPP_LIB_BUILD_SHARED=OFF -G "Unix Makefiles" ../build/debug + (cd ../build/debug && make) + +Running "cmake -h" will display the list of available generators (passed as -G option). + +By default CMake hides compilation command-line. This can be modified by specifying: +-DCMAKE_VERBOSE_MAKEFILE=true when generating makefiles. + +* Building/Testing with the legacy build system based on SCons: + ============================================================= JsonCpp uses Scons (http://www.scons.org) as a build system. Scons requires python to be installed (http://www.python.org). @@ -47,7 +103,6 @@ to do so. and TARGET may be: check: build library and run unit tests. - * Running the test manually: ========================== @@ -115,15 +170,6 @@ The amalgamated sources are generated by concatenating JsonCpp source in the correct order and defining macro JSON_IS_AMALGAMATION to prevent inclusion of other headers. -* Using json-cpp in your project: - =============================== - -include/ should be added to your compiler include path. jsoncpp headers -should be included as follow: - -#include - - * Adding a reader/writer test: ============================ diff --git a/amalgamate.py b/amalgamate.py index 2ced51b..5222655 100644 --- a/amalgamate.py +++ b/amalgamate.py @@ -66,6 +66,7 @@ def amalgamate_source( source_top_dir=None, header.add_text( '/// If defined, indicates that the source file is amalgated' ) header.add_text( '/// to prevent private header inclusion.' ) header.add_text( '#define JSON_IS_AMALGAMATION' ) + header.add_file( 'include/json/version.h' ) header.add_file( 'include/json/config.h' ) header.add_file( 'include/json/forwards.h' ) header.add_file( 'include/json/features.h' ) diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt new file mode 100644 index 0000000..7d832a0 --- /dev/null +++ b/include/CMakeLists.txt @@ -0,0 +1,2 @@ +FILE(GLOB INCLUDE_FILES "json/*.h") +INSTALL(FILES ${INCLUDE_FILES} DESTINATION include/json) diff --git a/include/json/config.h b/include/json/config.h index 72437c4..c9b298d 100644 --- a/include/json/config.h +++ b/include/json/config.h @@ -46,10 +46,17 @@ # ifdef JSON_IN_CPPTL # define JSON_API CPPTL_API # elif defined(JSON_DLL_BUILD) -# define JSON_API __declspec(dllexport) +# if defined(_MSC_VER) +# define JSON_API __declspec(dllexport) +# define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +# endif // if defined(_MSC_VER) # elif defined(JSON_DLL) -# define JSON_API __declspec(dllimport) -# else +# if defined(_MSC_VER) +# define JSON_API __declspec(dllimport) +# define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +# endif // if defined(_MSC_VER) +# endif // ifdef JSON_IN_CPPTL +# if !defined(JSON_API) # define JSON_API # endif diff --git a/include/json/reader.h b/include/json/reader.h index a3023b3..189da57 100644 --- a/include/json/reader.h +++ b/include/json/reader.h @@ -14,6 +14,13 @@ # include # include +// Disable warning C4251: : needs to have dll-interface to be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +# pragma warning(push) +# pragma warning(disable:4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + + namespace Json { /** \brief Unserialize a JSON document into a Value. @@ -206,8 +213,13 @@ namespace Json { \throw std::exception on parse error. \see Json::operator<<() */ - std::istream& operator>>( std::istream&, Value& ); + JSON_API std::istream& operator>>( std::istream&, Value& ); } // namespace Json +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +# pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + + #endif // CPPTL_JSON_READER_H_INCLUDED diff --git a/include/json/value.h b/include/json/value.h index 6daa8d1..bd7f181 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -21,6 +21,13 @@ # include # endif +// Disable warning C4251: : needs to have dll-interface to be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +# pragma warning(push) +# pragma warning(disable:4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + + /** \brief JSON (JavaScript Object Notation). */ namespace Json { @@ -1109,4 +1116,9 @@ public: // overridden from ValueArrayAllocator } // namespace Json +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +# pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + + #endif // CPPTL_JSON_H_INCLUDED diff --git a/include/json/version.h b/include/json/version.h new file mode 100644 index 0000000..9e1efcc --- /dev/null +++ b/include/json/version.h @@ -0,0 +1,14 @@ +// DO NOT EDIT. This file is generated by CMake from "version" +// and "version.h.in" files. +// Run CMake configure step to update it. +#ifndef JSON_VERSION_H_INCLUDED +# define JSON_VERSION_H_INCLUDED + +# define JSONCPP_VERSION_STRING "0.6.0-dev" +# define JSONCPP_VERSION_MAJOR 0 +# define JSONCPP_VERSION_MINOR 6 +# define JSONCPP_VERSION_PATCH 0 +# define JSONCPP_VERSION_QUALIFIER -dev +# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8)) + +#endif // JSON_VERSION_H_INCLUDED diff --git a/include/json/writer.h b/include/json/writer.h index 46d5ccc..23ebd50 100644 --- a/include/json/writer.h +++ b/include/json/writer.h @@ -12,6 +12,13 @@ # include # include +// Disable warning C4251: : needs to have dll-interface to be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +# pragma warning(push) +# pragma warning(disable:4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + + namespace Json { class Value; @@ -183,10 +190,14 @@ namespace Json { /// \brief Output using the StyledStreamWriter. /// \see Json::operator>>() - std::ostream& operator<<( std::ostream&, const Value &root ); + JSON_API std::ostream& operator<<( std::ostream&, const Value &root ); } // namespace Json +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +# pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + #endif // JSON_WRITER_H_INCLUDED diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..608d3f7 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,5 @@ +ADD_SUBDIRECTORY(lib_json) +IF(JSONCPP_WITH_TESTS) + ADD_SUBDIRECTORY(jsontestrunner) + ADD_SUBDIRECTORY(test_lib_json) +ENDIF(JSONCPP_WITH_TESTS) diff --git a/src/jsontestrunner/CMakeLists.txt b/src/jsontestrunner/CMakeLists.txt new file mode 100644 index 0000000..7ab2f00 --- /dev/null +++ b/src/jsontestrunner/CMakeLists.txt @@ -0,0 +1,23 @@ +FIND_PACKAGE(PythonInterp 2.6 REQUIRED) + +IF(JSONCPP_LIB_BUILD_SHARED) + ADD_DEFINITIONS( -DJSON_DLL ) +ENDIF(JSONCPP_LIB_BUILD_SHARED) + +ADD_EXECUTABLE(jsontestrunner_exe + main.cpp + ) +TARGET_LINK_LIBRARIES(jsontestrunner_exe jsoncpp_lib) +SET_TARGET_PROPERTIES(jsontestrunner_exe PROPERTIES OUTPUT_NAME jsontestrunner_exe) + +IF(PYTHONINTERP_FOUND) + # Run end to end parser/writer tests + GET_PROPERTY(JSONTESTRUNNER_EXE_PATH TARGET jsontestrunner_exe PROPERTY LOCATION) + SET(TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../test) + SET(RUNJSONTESTS_PATH ${TEST_DIR}/runjsontests.py) + ADD_CUSTOM_TARGET(jsoncpp_readerwriter_tests ALL + "${PYTHON_EXECUTABLE}" -B "${RUNJSONTESTS_PATH}" "${JSONTESTRUNNER_EXE_PATH}" "${TEST_DIR}/data" + DEPENDS jsontestrunner_exe jsoncpp_test + ) + ADD_CUSTOM_TARGET(jsoncpp_check DEPENDS jsoncpp_readerwriter_tests) +ENDIF(PYTHONINTERP_FOUND) diff --git a/src/lib_json/CMakeLists.txt b/src/lib_json/CMakeLists.txt new file mode 100644 index 0000000..39aa0b3 --- /dev/null +++ b/src/lib_json/CMakeLists.txt @@ -0,0 +1,43 @@ +OPTION(JSONCPP_LIB_BUILD_SHARED "Build jsoncpp_lib as a shared library." OFF) +IF(JSONCPP_LIB_BUILD_SHARED) + SET(JSONCPP_LIB_TYPE SHARED) + ADD_DEFINITIONS( -DJSON_DLL_BUILD ) +ELSE(JSONCPP_LIB_BUILD_SHARED) + SET(JSONCPP_LIB_TYPE STATIC) +ENDIF(JSONCPP_LIB_BUILD_SHARED) + + +SET( JSONCPP_INCLUDE_DIR ../../include ) + +SET( PUBLIC_HEADERS + ${JSONCPP_INCLUDE_DIR}/json/config.h + ${JSONCPP_INCLUDE_DIR}/json/forwards.h + ${JSONCPP_INCLUDE_DIR}/json/features.h + ${JSONCPP_INCLUDE_DIR}/json/value.h + ${JSONCPP_INCLUDE_DIR}/json/reader.h + ${JSONCPP_INCLUDE_DIR}/json/writer.h + ${JSONCPP_INCLUDE_DIR}/json/assertions.h + ${JSONCPP_INCLUDE_DIR}/json/version.h + ) + +SOURCE_GROUP( "Public API" FILES ${PUBLIC_HEADERS} ) + +ADD_LIBRARY( jsoncpp_lib ${JSONCPP_LIB_TYPE} + ${PUBLIC_HEADERS} + json_tool.h + json_reader.cpp + json_batchallocator.h + json_valueiterator.inl + json_value.cpp + json_writer.cpp + version.h.in + ) +SET_TARGET_PROPERTIES( jsoncpp_lib PROPERTIES OUTPUT_NAME jsoncpp ) +SET_TARGET_PROPERTIES( jsoncpp_lib PROPERTIES VERSION ${JSON_CPP_VERSION} SOVERSION ${JSON_CPP_VERSION} ) + +# Install instructions for this target +INSTALL( TARGETS jsoncpp_lib + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib +) diff --git a/src/lib_json/version.h.in b/src/lib_json/version.h.in new file mode 100644 index 0000000..217bcff --- /dev/null +++ b/src/lib_json/version.h.in @@ -0,0 +1,14 @@ +// DO NOT EDIT. This file is generated by CMake from "version" +// and "version.h.in" files. +// Run CMake configure step to update it. +#ifndef JSON_VERSION_H_INCLUDED +# define JSON_VERSION_H_INCLUDED + +# define JSONCPP_VERSION_STRING "@JSONCPP_VERSION@" +# define JSONCPP_VERSION_MAJOR @JSONCPP_VERSION_MAJOR@ +# define JSONCPP_VERSION_MINOR @JSONCPP_VERSION_MINOR@ +# define JSONCPP_VERSION_PATCH @JSONCPP_VERSION_PATCH@ +# define JSONCPP_VERSION_QUALIFIER @JSONCPP_VERSION_QUALIFIER@ +# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8)) + +#endif // JSON_VERSION_H_INCLUDED diff --git a/src/test_lib_json/CMakeLists.txt b/src/test_lib_json/CMakeLists.txt new file mode 100644 index 0000000..563f713 --- /dev/null +++ b/src/test_lib_json/CMakeLists.txt @@ -0,0 +1,21 @@ + +IF(JSONCPP_LIB_BUILD_SHARED) + ADD_DEFINITIONS( -DJSON_DLL ) +ENDIF(JSONCPP_LIB_BUILD_SHARED) + +ADD_EXECUTABLE( jsoncpp_test + jsontest.cpp + main.cpp + ) + +TARGET_LINK_LIBRARIES(jsoncpp_test jsoncpp_lib) + +# Run unit tests in post-build +# (default cmake workflow hides away the test result into a file, resulting in poor dev workflow?!?) +IF(JSONCPP_WITH_POST_BUILD_UNITTEST) + ADD_CUSTOM_COMMAND( TARGET jsoncpp_test + POST_BUILD + COMMAND jsoncpp_test) +ENDIF(JSONCPP_WITH_POST_BUILD_UNITTEST) + +SET_TARGET_PROPERTIES(jsoncpp_test PROPERTIES OUTPUT_NAME jsoncpp_test)