diff --git a/CMakeLists.txt b/CMakeLists.txt index 9887657f..1b0bca9f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,8 +23,7 @@ option(JSON_MultipleHeaders "Use non-amalgamated version of the library." OFF) ## CONFIGURATION ## set(NLOHMANN_JSON_TARGET_NAME ${PROJECT_NAME}) -set(NLOHMANN_JSON_CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}" - CACHE INTERNAL "") +set(NLOHMANN_JSON_CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}" CACHE INTERNAL "") set(NLOHMANN_JSON_INCLUDE_INSTALL_DIR "include") set(NLOHMANN_JSON_TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets") set(NLOHMANN_JSON_CMAKE_CONFIG_TEMPLATE "cmake/config.cmake.in") @@ -47,7 +46,7 @@ endif() ## add_library(${NLOHMANN_JSON_TARGET_NAME} INTERFACE) add_library(${PROJECT_NAME}::${NLOHMANN_JSON_TARGET_NAME} ALIAS ${NLOHMANN_JSON_TARGET_NAME}) -if (${CMAKE_VERSION} VERSION_LESS "3.8.0") +if (${CMAKE_VERSION} VERSION_LESS "3.8.0") target_compile_features(${NLOHMANN_JSON_TARGET_NAME} INTERFACE cxx_range_for) else() target_compile_features(${NLOHMANN_JSON_TARGET_NAME} INTERFACE cxx_std_11) diff --git a/Makefile b/Makefile index 24c77f51..127bafd8 100644 --- a/Makefile +++ b/Makefile @@ -1,44 +1,31 @@ -.PHONY: pretty clean ChangeLog.md +.PHONY: pretty clean ChangeLog.md release -SRCS = include/nlohmann/json.hpp \ - include/nlohmann/json_fwd.hpp \ - include/nlohmann/adl_serializer.hpp \ - include/nlohmann/detail/conversions/from_json.hpp \ - include/nlohmann/detail/conversions/to_chars.hpp \ - include/nlohmann/detail/conversions/to_json.hpp \ - include/nlohmann/detail/exceptions.hpp \ - include/nlohmann/detail/input/binary_reader.hpp \ - include/nlohmann/detail/input/input_adapters.hpp \ - include/nlohmann/detail/input/json_sax.hpp \ - include/nlohmann/detail/input/lexer.hpp \ - include/nlohmann/detail/input/parser.hpp \ - include/nlohmann/detail/input/position_t.hpp \ - include/nlohmann/detail/iterators/internal_iterator.hpp \ - include/nlohmann/detail/iterators/iter_impl.hpp \ - include/nlohmann/detail/iterators/iteration_proxy.hpp \ - include/nlohmann/detail/iterators/json_reverse_iterator.hpp \ - include/nlohmann/detail/iterators/primitive_iterator.hpp \ - include/nlohmann/detail/json_pointer.hpp \ - include/nlohmann/detail/json_ref.hpp \ - include/nlohmann/detail/macro_scope.hpp \ - include/nlohmann/detail/macro_unscope.hpp \ - include/nlohmann/detail/meta/cpp_future.hpp \ - include/nlohmann/detail/meta/detected.hpp \ - include/nlohmann/detail/meta/type_traits.hpp \ - include/nlohmann/detail/meta/void_t.hpp \ - include/nlohmann/detail/output/binary_writer.hpp \ - include/nlohmann/detail/output/output_adapters.hpp \ - include/nlohmann/detail/output/serializer.hpp \ - include/nlohmann/detail/value_t.hpp - -UNAME = $(shell uname) -CXX=clang++ - -AMALGAMATED_FILE=single_include/nlohmann/json.hpp +########################################################################## +# configuration +########################################################################## # directory to recent compiler binaries COMPILER_DIR=/Users/niels/Documents/projects/compilers/local/bin +# find GNU sed to use `-i` parameter +SED:=$(shell command -v gsed || which sed) + + +########################################################################## +# source files +########################################################################## + +# the list of sources in the include folder +SRCS=$(shell find include -type f | sort) + +# the single header (amalgamated from the source files) +AMALGAMATED_FILE=single_include/nlohmann/json.hpp + + +########################################################################## +# documentation of the Makefile's targets +########################################################################## + # main target all: @echo "amalgamate - amalgamate file single_include/nlohmann/json.hpp from the include/nlohmann sources" @@ -64,6 +51,7 @@ all: @echo "pretty - beautify code with Artistic Style" @echo "run_benchmarks - build and run benchmarks" + ########################################################################## # unit tests ########################################################################## @@ -76,25 +64,19 @@ json_unit: check: $(MAKE) check -C test +# run unit tests and skip expensive tests check-fast: $(MAKE) check -C test TEST_PATTERN="" -# clean up -clean: - rm -fr json_unit json_benchmarks fuzz fuzz-testing *.dSYM test/*.dSYM - rm -fr benchmarks/files/numbers/*.json - rm -fr build_coverage build_benchmarks - $(MAKE) clean -Cdoc - $(MAKE) clean -Ctest - ########################################################################## # coverage ########################################################################## coverage: + rm -fr build_coverage mkdir build_coverage - cd build_coverage ; CXX=g++-7 cmake .. -GNinja -DJSON_Coverage=ON -DJSON_MultipleHeaders=ON + cd build_coverage ; CXX=$(COMPILER_DIR)/g++ cmake .. -GNinja -DJSON_Coverage=ON -DJSON_MultipleHeaders=ON cd build_coverage ; ninja cd build_coverage ; ctest -E '.*_default' -j10 cd build_coverage ; ninja lcov_html @@ -372,9 +354,10 @@ pedantic_gcc: ########################################################################## run_benchmarks: + rm -fr build_benchmarks mkdir build_benchmarks - cd build_benchmarks ; cmake ../benchmarks - cd build_benchmarks ; make + cd build_benchmarks ; cmake ../benchmarks -GNinja -DCMAKE_BUILD_TYPE=Release + cd build_benchmarks ; ninja cd build_benchmarks ; ./json_benchmarks ########################################################################## @@ -436,28 +419,39 @@ fuzzing-stop: -killall fuzzer -killall afl-fuzz + ########################################################################## -# static analyzer +# Static analysis ########################################################################## -# call cppcheck on the main header file +# call cppcheck +# Note: this target is called by Travis cppcheck: cppcheck --enable=warning --inline-suppr --inconclusive --force --std=c++11 $(SRCS) --error-exitcode=1 -# compile and check with Clang Static Analyzer +# call Clang Static Analyzer clang_analyze: rm -fr clang_analyze_build mkdir clang_analyze_build cd clang_analyze_build ; CCC_CXX=$(COMPILER_DIR)/clang++ CXX=$(COMPILER_DIR)/clang++ $(COMPILER_DIR)/scan-build cmake .. -GNinja - cd clang_analyze_build ; $(COMPILER_DIR)/scan-build -enable-checker alpha.core.BoolAssignment,alpha.core.CallAndMessageUnInitRefArg,alpha.core.CastSize,alpha.core.CastToStruct,alpha.core.Conversion,alpha.core.DynamicTypeChecker,alpha.core.FixedAddr,alpha.core.PointerArithm,alpha.core.PointerSub,alpha.core.SizeofPtr,alpha.core.StackAddressAsyncEscape,alpha.core.TestAfterDivZero,alpha.deadcode.UnreachableCode,core.builtin.BuiltinFunctions,core.builtin.NoReturnFunctions,core.CallAndMessage,core.DivideZero,core.DynamicTypePropagation,core.NonnilStringConstants,core.NonNullParamChecker,core.NullDereference,core.StackAddressEscape,core.UndefinedBinaryOperatorResult,core.uninitialized.ArraySubscript,core.uninitialized.Assign,core.uninitialized.Branch,core.uninitialized.CapturedBlockVariable,core.uninitialized.UndefReturn,core.VLASize,cplusplus.InnerPointer,cplusplus.Move,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,cplusplus.SelfAssignment,deadcode.DeadStores,nullability.NullableDereferenced,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull --use-c++=$(COMPILER_DIR)/clang++ --view -analyze-headers -o clang_analyze_build/report.html ninja + cd clang_analyze_build ; \ + $(COMPILER_DIR)/scan-build \ + -enable-checker alpha.core.BoolAssignment,alpha.core.CallAndMessageUnInitRefArg,alpha.core.CastSize,alpha.core.CastToStruct,alpha.core.Conversion,alpha.core.DynamicTypeChecker,alpha.core.FixedAddr,alpha.core.PointerArithm,alpha.core.PointerSub,alpha.core.SizeofPtr,alpha.core.StackAddressAsyncEscape,alpha.core.TestAfterDivZero,alpha.deadcode.UnreachableCode,core.builtin.BuiltinFunctions,core.builtin.NoReturnFunctions,core.CallAndMessage,core.DivideZero,core.DynamicTypePropagation,core.NonnilStringConstants,core.NonNullParamChecker,core.NullDereference,core.StackAddressEscape,core.UndefinedBinaryOperatorResult,core.uninitialized.ArraySubscript,core.uninitialized.Assign,core.uninitialized.Branch,core.uninitialized.CapturedBlockVariable,core.uninitialized.UndefReturn,core.VLASize,cplusplus.InnerPointer,cplusplus.Move,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,cplusplus.SelfAssignment,deadcode.DeadStores,nullability.NullableDereferenced,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull \ + --use-c++=$(COMPILER_DIR)/clang++ -analyze-headers -o report ninja + open clang_analyze_build/report/*/index.html -# call cpplint (some errors expected due to false positives) +# call cpplint +# Note: some errors expected due to false positives cpplint: - third_party/cpplint/cpplint.py --filter=-whitespace,-legal,-readability/alt_tokens,-runtime/references,-runtime/explicit --quiet --recursive include + third_party/cpplint/cpplint.py \ + --filter=-whitespace,-legal,-readability/alt_tokens,-runtime/references,-runtime/explicit \ + --quiet --recursive $(SRCS) +# call Clang-Tidy clang_tidy: $(COMPILER_DIR)/clang-tidy $(SRCS) -- -Iinclude -std=c++11 +# call PVS-Studio Analyzer pvs_studio: rm -fr pvs_studio_build mkdir pvs_studio_build @@ -466,45 +460,70 @@ pvs_studio: cd pvs_studio_build ; plog-converter -a'GA:1,2;64:1;CS' -t fullhtml PVS-Studio.log -o pvs open pvs_studio_build/pvs/index.html +# call Infer static analyzer infer: rm -fr infer_build mkdir infer_build cd infer_build ; infer compile -- cmake .. ; infer run -- make -j 4 +# call OCLint static analyzer oclint: oclint $(SRCS) -report-type html -enable-global-analysis -o oclint_report.html -max-priority-1=10000 -max-priority-2=10000 -max-priority-3=10000 -- -std=c++11 -Iinclude open oclint_report.html +# execute the test suite with Clang sanitizers (address and undefined behavior) +clang_sanitize: + rm -fr clang_sanitize_build + mkdir clang_sanitize_build + cd clang_sanitize_build ; CXX=$(COMPILER_DIR)/clang++ cmake .. -DJSON_Sanitizer=On -DJSON_MultipleHeaders=ON -GNinja + cd clang_sanitize_build ; ninja + cd clang_sanitize_build ; ctest -E '.*_default' -j10 + + ########################################################################## -# maintainer targets +# Code format and source amalgamation ########################################################################## -# pretty printer +# call the Artistic Style pretty printer on all source files pretty: - astyle --style=allman --indent=spaces=4 --indent-modifiers \ - --indent-switches --indent-preproc-block --indent-preproc-define \ - --indent-col1-comments --pad-oper --pad-header --align-pointer=type \ - --align-reference=type --add-brackets --convert-tabs --close-templates \ - --lineend=linux --preserve-date --suffix=none --formatted \ - $(SRCS) $(AMALGAMATED_FILE) test/src/*.cpp \ - benchmarks/src/benchmarks.cpp doc/examples/*.cpp + astyle \ + --style=allman \ + --indent=spaces=4 \ + --indent-modifiers \ + --indent-switches \ + --indent-preproc-block \ + --indent-preproc-define \ + --indent-col1-comments \ + --pad-oper \ + --pad-header \ + --align-pointer=type \ + --align-reference=type \ + --add-brackets \ + --convert-tabs \ + --close-templates \ + --lineend=linux \ + --preserve-date \ + --suffix=none \ + --formatted \ + $(SRCS) $(AMALGAMATED_FILE) test/src/*.cpp benchmarks/src/benchmarks.cpp doc/examples/*.cpp # create single header file amalgamate: $(AMALGAMATED_FILE) +# call the amalgamation tool and pretty print $(AMALGAMATED_FILE): $(SRCS) third_party/amalgamate/amalgamate.py -c third_party/amalgamate/config.json -s . --verbose=yes $(MAKE) pretty -# check if single_include/nlohmann/json.hpp has been amalgamated from the nlohmann sources +# check if file single_include/nlohmann/json.hpp has been amalgamated from the nlohmann sources +# Note: this target is called by Travis check-amalgamation: @mv $(AMALGAMATED_FILE) $(AMALGAMATED_FILE)~ @$(MAKE) amalgamate @diff $(AMALGAMATED_FILE) $(AMALGAMATED_FILE)~ || (echo "===================================================================\n Amalgamation required! Please read the contribution guidelines\n in file .github/CONTRIBUTING.md.\n===================================================================" ; mv $(AMALGAMATED_FILE)~ $(AMALGAMATED_FILE) ; false) @mv $(AMALGAMATED_FILE)~ $(AMALGAMATED_FILE) -# check if every header in nlohmann includes sufficient headers to be compiled -# individually +# check if every header in nlohmann includes sufficient headers to be compiled individually check-single-includes: @for x in $(SRCS); do \ echo "Checking self-sufficiency of $$x..." ; \ @@ -513,29 +532,79 @@ check-single-includes: rm -f single_include_test.cpp single_include_test; \ done + ########################################################################## -# changelog +# CMake ########################################################################## +# grep "^option" CMakeLists.txt test/CMakeLists.txt | sed 's/(/ /' | awk '{print $2}' | xargs + +# check if all flags of our CMake files work +check_cmake_flags_do: + $(CMAKE_BINARY) --version + for flag in '' JSON_BuildTests JSON_Install JSON_MultipleHeaders JSON_Sanitizer JSON_Valgrind JSON_NoExceptions JSON_Coverage; do \ + rm -fr cmake_build; \ + mkdir cmake_build; \ + echo "$(CMAKE_BINARY) .. -D$$flag=On" ; \ + cd cmake_build ; \ + CXX=g++-8 $(CMAKE_BINARY) .. -D$$flag=On -DCMAKE_CXX_COMPILE_FEATURES="cxx_std_11;cxx_range_for" -DCMAKE_CXX_FLAGS="-std=gnu++11" ; \ + test -f Makefile || exit 1 ; \ + cd .. ; \ + done; + +# call target `check_cmake_flags_do` twice: once for minimal required CMake version 3.1.0 and once for the installed version +check_cmake_flags: + wget https://github.com/Kitware/CMake/releases/download/v3.1.0/cmake-3.1.0-Darwin64.tar.gz + tar xfz cmake-3.1.0-Darwin64.tar.gz + CMAKE_BINARY=$(abspath cmake-3.1.0-Darwin64/CMake.app/Contents/bin/cmake) $(MAKE) check_cmake_flags_do + CMAKE_BINARY=$(shell which cmake) $(MAKE) check_cmake_flags_do + + +########################################################################## +# ChangeLog +########################################################################## + +# Create a ChangeLog based on the git log using the GitHub Changelog Generator +# (). + +# variable to control the diffs between the last released version and the current repository state NEXT_VERSION ?= "unreleased" ChangeLog.md: github_changelog_generator -o ChangeLog.md --simple-list --release-url https://github.com/nlohmann/json/releases/tag/%s --future-release $(NEXT_VERSION) - gsed -i 's|https://github.com/nlohmann/json/releases/tag/HEAD|https://github.com/nlohmann/json/tree/HEAD|' ChangeLog.md - gsed -i '2i All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/).' ChangeLog.md + $(SED) -i 's|https://github.com/nlohmann/json/releases/tag/HEAD|https://github.com/nlohmann/json/tree/HEAD|' ChangeLog.md + $(SED) -i '2i All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/).' ChangeLog.md ########################################################################## -# release +# Release files ########################################################################## +# Create the files for a release and add signatures and hashes. We use `--no-extra` to make the resulting ZIP file +# reproducible, see . + release: + rm -fr release_files mkdir release_files - zip -9 -r include.zip include/* + zip -9 --recurse-paths --no-extra include.zip $(SRCS) gpg --armor --detach-sig include.zip mv include.zip include.zip.asc release_files - gpg --armor --detach-sig single_include/nlohmann/json.hpp - cp single_include/nlohmann/json.hpp release_files - mv single_include/nlohmann/json.hpp.asc release_files + gpg --armor --detach-sig $(AMALGAMATED_FILE) + cp $(AMALGAMATED_FILE) release_files + mv $(AMALGAMATED_FILE).asc release_files cd release_files ; shasum -a 256 json.hpp > hashes.txt cd release_files ; shasum -a 256 include.zip >> hashes.txt + + +########################################################################## +# Maintenance +########################################################################## + +# clean up +clean: + rm -fr json_unit json_benchmarks fuzz fuzz-testing *.dSYM test/*.dSYM oclint_report.html + rm -fr benchmarks/files/numbers/*.json + rm -fr cmake-3.1.0-Darwin64.tar.gz cmake-3.1.0-Darwin64 + rm -fr build_coverage build_benchmarks fuzz-testing clang_analyze_build pvs_studio_build infer_build clang_sanitize_build cmake_build + $(MAKE) clean -Cdoc + $(MAKE) clean -Ctest diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5f253bff..496c154e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -6,7 +6,7 @@ option(JSON_Coverage "Build test suite with coverage information" OFF) if(JSON_Sanitizer) message(STATUS "Building test suite with Clang sanitizer") if(NOT MSVC) - set(CMAKE_CXX_FLAGS "-g -O2 -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer") + set(CMAKE_CXX_FLAGS "-g -O2 -fsanitize=address -fsanitize=undefined -fsanitize=implicit-conversion -fsanitize=integer -fsanitize=nullability -fno-omit-frame-pointer") endif() endif() @@ -64,7 +64,7 @@ set_target_properties(catch_main PROPERTIES COMPILE_DEFINITIONS "$<$:_SCL_SECURE_NO_WARNINGS>" COMPILE_OPTIONS "$<$:/EHsc;$<$:/Od>>" ) -if (${CMAKE_VERSION} VERSION_LESS "3.8.0") +if (${CMAKE_VERSION} VERSION_LESS "3.8.0") target_compile_features(catch_main PUBLIC cxx_range_for) else() target_compile_features(catch_main PUBLIC cxx_std_11)