From 1d675cdb46973038f0087c24c0f399722e823281 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 30 Sep 2026 22:49:24 +0200 Subject: [PATCH] Fix CI jobs that check less than they claim; move arm64 to GitHub (#5733) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix the ci_cmake_flags wiring so every option is checked The CMake 3.31.6 flag list referred to itself before it was defined, so only JSON_BuildTests was checked with that version. The targets for the CMake running the build ("_2") were created but never added to ci_cmake_flags, and the three versions shared one build directory. JSON_StrictNulHandling was not in the list at all. Use the 3.5.0 list for 3.31.6, add JSON_StrictNulHandling, and create one ci_cmake_flag_ target per option for the running CMake with its own build directory. Also use the function parameter in the COMMENT, refresh the stale version comment, and let ci_clean remove the downloaded cmake- directories instead of the long-gone cmake-3.5.0-Darwin64. Part of #5715 Signed-off-by: Niels Lohmann * Fix ci_test_clang_libcxx_cxx* jobs silently building without warnings CMake only seeds CMAKE_CXX_FLAGS from the CXXFLAGS environment variable when the cache entry is unset, so the explicit -DCMAKE_CXX_FLAGS="-stdlib=libc++" argument made it ignore CXXFLAGS="${CLANG_CXXFLAGS}" entirely. The six ci_test_standards_clang (..., libcxx) jobs therefore compiled without -Weverything/-Werror while their libstdc++ siblings did use them. Pass -stdlib=libc++ through the same CXXFLAGS value instead of a separate -D argument, and give the target its own build directory (build_clang_libcxx_cxx${CXX_STANDARD}) so it no longer shares a CMake cache with the libstdc++ variant. Suppress the resulting -Wthread-safety-negative finding from libc++'s std::mutex annotations, which fires on doctest's reporters in this translation unit only. Part of #5715 Signed-off-by: Niels Lohmann * Remove the no-op AppVeyor with_win_header job The with_win_header matrix entry patched Windows.h into single_include/nlohmann/json.hpp before building, but JSON_MultipleHeaders has defaulted to ON since #3532 (2022-06), so CMakeLists.txt points the tests at include/ and the patched single header is never compiled. The job has been a no-op VS2015 build since then. Windows.h coverage already exists through tests/src/unit-windows_h.cpp (#3631), which runs in every MSVC job. Delete the dead matrix entry and its before_build steps, and cite unit-windows_h.cpp from the QA page. Part of #5715 Signed-off-by: Niels Lohmann * Remove unused ci_oclint and ci_pvs_studio targets No workflow invokes ci_oclint, ci_pvs_studio, or their tool discovery. ci_oclint also had a side effect on every JSON_CI configure: it copied the single header into src_single/all.cpp and added an add_executable() for it without EXCLUDE_FROM_ALL, so a plain build compiled a 1.2 MB translation unit that only that unused target consumed. ci_pvs_studio duplicates the Makefile's pvs_studio target, which is kept. Also drop the duplicate --check-level=exhaustive flag passed twice to the same ci_cppcheck invocation. Part of #5715 Signed-off-by: Niels Lohmann * Stop Dependabot from proposing astyle bumps astyle is deliberately pinned at 3.4.13 because newer versions reformat unrelated lines and this version defines the formatting that check_amalgamation.yml enforces. Without an ignore rule, Dependabot keeps opening PRs for every new astyle release (most recently #4580, #4942, #5445, #5448), each of which fails the amalgamation check and gets closed unmerged. Part of #5715 Signed-off-by: Niels Lohmann * Move Linux arm64 CI from dead Cirrus CI to ubuntu-24.04-arm Cirrus CI stopped reporting check runs on develop sometime after d10879bca (2026-05-26); every commit since has only github-actions check runs, so .cirrus.yml silently lost its only consumer while README.md, FILES.md and the QA page kept advertising the coverage. Add a ci_test_arm64 job to ubuntu.yml using the same pinned actions/checkout and lukka/get-cmake actions as the other jobs, on the native ubuntu-24.04-arm runner, with a step that confirms uname -m reports aarch64. Delete .cirrus.yml and its README badge and FILES.md section, and update the QA page's arm64 row. Part of #5715 Signed-off-by: Niels Lohmann * Make scan-build fail on findings and drop irrelevant checkers (#5715 item 4a) ci_clang_analyze ran scan-build without --status-bugs, so the job passed whenever the ninja build succeeded, no matter what the analyzer found ("No bugs found" in a green run gave no signal either way). It is also missing --use-analyzer=${CLANG_TOOL}, so scan-build picks whichever clang happens to be first on PATH inside the silkeh/clang:dev container instead of the one this file already selected and versioned. Add --status-bugs and --use-analyzer=${CLANG_TOOL} to the scan-build invocation. While here, drop the osx.*, webkit.*, fuchsia.*, and optin.mpi.* checkers from CLANG_ANALYZER_CHECKS: none of them apply to this portable C++ library, and leaving them enabled only adds noise once the job can actually fail on a finding. The job is currently clean (0 bugs), so this alone does not surface any new finding; it only makes the existing "no bugs found" result authoritative. This is 4a of 3 independent steps in #5715 item 4; 4b (Infer) and 4c (IWYU) still need their existing findings triaged before --fail-on-issue/-Xiwyu --error can be added, and are handled in separate commits. Signed-off-by: Niels Lohmann * Deduplicate the amalgamation/format check's file set and add BUILD.bazel (#5715 item 5) The amalgamation/format check existed three times with three different file sets: the Makefile's pretty/check-amalgamation, the pull_request-only check_amalgamation.yml workflow, and the ci_test_amalgamation CMake target that also runs on direct pushes to develop/master/release/*. The CMake target's glob was a strict subset of the workflow's (missing the docs/mkdocs/docs/examples/*.hpp headers, tests/abi/, tests/cmake_*/project/, tests/cuda_example/, tests/fmt_formatter/, and tests/module_cpp20/), and it never checked BUILD.bazel at all, so a misformatted file in any of those paths, or a stale BUILD.bazel, could reach develop through a direct push even though the PR-only workflow would have caught it. Make ci_test_amalgamation glob the same roots (docs/mkdocs/docs/examples, include, tests) and extensions (*.hpp, *.cpp, *.cu) as check_amalgamation.yml, excluding tests/thirdparty/ and tests/abi/include/nlohmann/ the same way, and regenerate and diff BUILD.bazel next to json.hpp/json_fwd.hpp. Also add docs/mkdocs/docs/examples/*.hpp to the Makefile's pretty/pretty_format targets, which were missing the four custom_*_type.hpp example headers, and drop the stale "called by Travis" comment on check-amalgamation (Travis is gone; nothing currently calls that Makefile target from CI). Leaves the workflow itself untouched: it deliberately runs amalgamate.py from a fresh develop checkout so a PR cannot change the tool that checks it. Overlaps #5610 and #5621, which each add a new amalgamated header and touch the same INDENT_FILES/ci_test_amalgamation/check_amalgamation.yml hunks. Verified with `make check-amalgamation` on this branch: clean, no diff. #5715 item 5. Signed-off-by: Niels Lohmann * Download prebuilt CMake binaries on Linux x86_64 instead of building from source (#5715 item 6) ci_get_cmake() downloaded the source tarball of CMake 3.5.0, 3.31.6, and 4.0.0 and compiled each one completely (including CMake's own test helpers) with -DCMAKE_POLICY_VERSION_MINIMUM=3.5 as a workaround for building old CMake with a newer one. On CI this made the ci_cmake_options (ci_cmake_flags) job take about 11 minutes, most of it spent building CMake itself, even though Kitware has published ready-to-run Linux x86_64 archives for all three of these releases since 3.20 (lowercase platform name). On Linux x86_64, download and unpack the prebuilt cmake--linux-x86_64.tar.gz archive instead and point the existing ${var} output at its bin/cmake, skipping the configure/build steps and CMAKE_POLICY_VERSION_MINIMUM entirely. Keep the previous source build as a fallback for any other platform (macOS, Linux aarch64), since Kitware does not publish binaries for every CMake/platform combination this project might build on. Verify the downloaded archive against Kitware's own published checksum before unpacking it: download cmake--SHA-256.txt alongside the archive and run `sha256sum -c` on the matching line. A CI job that wgets and untars a binary from a release page with no integrity check is a supply-chain gap; Kitware has published this file for every release since 3.20, so checking it costs one extra download and one grep. As a separate, mechanical change: the ci_cmake_options job's container only needed to stay on ubuntu:focal for the source build's libssl-dev dependency and its own aging toolchain; now that the Linux/x86_64 path never compiles CMake, drop libssl-dev from its apt install line and move the job to ubuntu:24.04 (Ubuntu 20.04 left standard support in May 2025). ci_clean already removes the cmake-3.5.0/cmake-3.31.6/cmake-4.0.0 directories from the #5715 item 3 fix, and the prebuilt path reuses those same directory names, so no further cleanup changes are needed. Overlaps #5598, which edits the same ci_cmake_options matrix line in ubuntu.yml; a rebase may be needed once that lands. Verified locally: `cmake -S . -B build -DJSON_CI=On` configures cleanly on macOS/arm64 (source-build fallback branch) and on Linux/x86_64 in an ubuntu:24.04 Docker container (47 `ci_cmake_flag_*` targets generated, one built and run successfully); `.github/workflows/ubuntu.yml` still parses as valid YAML; downloaded the real v3.31.6 Linux x86_64 archive and SHA-256 file from Kitware and confirmed the `grep | sha256sum -c` pipeline both accepts the genuine file and is anchored to the exact filename (not a prefix match). CI must confirm: the prebuilt-binary path actually runs on the ubuntu-latest/ubuntu:24.04 x86_64 runner, all `ci_cmake_options` entries still pass with the new container's GCC, and the job's runtime drops from roughly 11 minutes. Signed-off-by: Niels Lohmann * Make Infer fail on findings, with a type-level baseline for the ~174 pre-existing ones (#5715 item 4b) ci_infer ran `infer run` without --fail-on-issue, so the job passed regardless of what Pulse found; the last recorded run (35829411620, commit 1054b2097) logged "Found 174 issues" and still went green. report.txt was also never uploaded, so the full finding list was only ever visible in the truncated 5-issue console excerpt. Add a repository-root .inferconfig (auto-discovered by Infer; passing --project-root on the `infer run` invocation makes sure it is found even though the analysis runs from build/build_infer) that sets fail-on-issue and disables the six PULSE issue types that made up all 174 findings in that run: PULSE_UNNECESSARY_COPY_ASSIGNMENT (129), PULSE_UNNECESSARY_COPY (22), PULSE_UNNECESSARY_COPY_INTERMEDIATE (15), PULSE_RESOURCE_LEAK (5), PULSE_CONST_REFABLE (2), and PULSE_UNNECESSARY_COPY_OPTIONAL (1). This is a deliberate, narrower fix than "triage and fix everything in this PR": the visible sample is entirely doctest-macro copies in test code (for example tests/src/unit-algorithms.cpp:141 and tests/src/unit-bjdata.cpp:3706), but 169 of the 174 findings were never uploaded anywhere and this PR cannot respectably claim to have fixed issues it never saw, including the resource-leak and const-refable ones that are the most likely to be genuine bugs. Disabling by issue type is a coarser baseline than a per-finding one (Infer has no built-in per-finding baseline short of the two-run `infer reportdiff` workflow, which this repository does not have the CI infrastructure for), but it has the same effect today: the job goes from always green to green-only-when-clean-of-everything-else, so CI now fails the moment a *new* issue type appears, and report.txt is uploaded as a workflow artifact on every run (including failures) so the six disabled types can be triaged and re-enabled incrementally in follow-up PRs. #5715 item 4b. 4a (scan-build) and 4c (IWYU) are handled in separate commits. Verified: .inferconfig parses as JSON, ubuntu.yml still parses as YAML. Infer itself is not available in this environment (v1.3.0 tar.xz requires a Linux x86_64 runner), so CI must confirm that `infer run --project-root ... -- make` picks up .inferconfig, that fail-on-issue takes effect, and that the six disabled types actually suppress the existing findings without also hiding an unrelated new one. Signed-off-by: Niels Lohmann * Fix IWYU findings for json.hpp/json_fwd.hpp/ordered_map.hpp and make CI fail on new ones (#5715 item 4c) ci_single_binaries ran IWYU via CMake's CXX_INCLUDE_WHAT_YOU_USE launcher property, which only printed "Warning: include-what-you-use reported diagnostics" without failing the build: CMake's own __run_co_compile wrapper does not propagate the launched tool's exit code, so even `-Xiwyu --error` could never fail `cmake --build` this way. Verified this empirically by injecting a deliberately-unused #include and confirming the build still exited 0. Fix the findings from the last recorded run (issue #5715 item 4, log 35829411620): - ordered_map.hpp: add (placement new) and nlohmann/detail/abi_macros.hpp; drop (std::allocator is still visible transitively via , confirmed by full local and containerized test suite runs). - json_fwd.hpp: drop (same reasoning). Keep every forward declaration IWYU wanted removed (adl_serializer, basic_json, json_pointer, ordered_map): this file's only job is to forward-declare them for downstream users, so "nothing in this TU uses them" is expected, not a real finding. Mark each with `// IWYU pragma: keep`. - json.hpp: add , , , , , and the detail/abi_macros.hpp, detail/input/json_sax.hpp, detail/meta/detected.hpp, thirdparty/hedley/hedley.hpp includes IWYU says it needs. Do NOT remove adl_serializer.hpp, detail/conversions/from_json.hpp, detail/conversions/to_json.hpp, detail/macro_unscope.hpp, or ordered_map.hpp as IWYU suggests: nothing else in include/nlohmann includes adl_serializer.hpp or ordered_map.hpp, so basic_json<>'s own default template arguments (JSONSerializer = adl_serializer, and ordered_json = basic_json) would lose their complete type; detail/macro_unscope.hpp is what undoes the JSON_* macros detail/macro_scope.hpp defines earlier in this same file, and removing it leaks those macros into every translation unit that includes . Verified by actually removing them in a scratch test: the header still "compiles" stand-alone but ordered_json and every macro-using translation unit break. Marked each `// IWYU pragma: keep`. Enforce it with `iwyu_tool` (ships with IWYU, e.g. as /usr/bin/iwyu_tool on Debian/Ubuntu) instead of relying on the launcher property: it reads compile_commands.json (now exported project-wide under JSON_CI) and does return a real exit code for its own analysis, independent of CMake's wrapper. ci_single_binaries now runs it over every src_single/*.cpp with `-Xiwyu --error`, so a *new* finding fails CI. json.hpp itself is excluded from that hard gate: even after every fix above, IWYU's suggestion for one remaining symbol (a container `swap, operator!=` used somewhere via a templated comparator) is not deterministic — repeated, otherwise-identical containerized runs reported , then , then as "the" header to add/remove for the exact same source. Gating a whole CI job on a nondeterministic suggestion would make ci_single_binaries flaky rather than informative, so json.hpp keeps the existing informational warning (still shown during its normal compile) without failing the build on it. Every other one of the ~50 single-header checks is included in the hard gate. #5715 item 4c. 4a (scan-build) and 4b (Infer) are separate commits. Verified: full local ctest suite (129/129) and the ci_single_binaries target itself both green in a containerized silkeh/clang:dev run (matching the actual CI job) after this fix; a deliberately-reintroduced unused #include in ordered_map.hpp was confirmed to fail `cmake --build ... --target ci_single_binaries` (exit 2) with this change, and to pass without it, on the same container/IWYU version CI uses. `make check-amalgamation` is clean. Compiled with Clang and GCC at -std=c++11/14/17/20 locally with no new warnings. Signed-off-by: Niels Lohmann --------- Signed-off-by: Niels Lohmann --- .cirrus.yml | 17 -- .github/dependabot.yml | 4 + .github/external_ci/appveyor.yml | 11 - .github/workflows/ubuntu.yml | 29 ++- .inferconfig | 12 + FILES.md | 11 - Makefile | 2 +- README.md | 1 - cmake/ci.cmake | 213 ++++++++++-------- .../docs/community/quality_assurance.md | 5 +- include/nlohmann/json.hpp | 26 ++- include/nlohmann/json_fwd.hpp | 11 +- include/nlohmann/ordered_map.hpp | 5 +- single_include/nlohmann/json.hpp | 45 +++- single_include/nlohmann/json_fwd.hpp | 11 +- tests/src/unit.cpp | 18 ++ tools/astyle/requirements.txt | 3 + 17 files changed, 254 insertions(+), 170 deletions(-) delete mode 100644 .cirrus.yml create mode 100644 .inferconfig diff --git a/.cirrus.yml b/.cirrus.yml deleted file mode 100644 index c7f4c15e2..000000000 --- a/.cirrus.yml +++ /dev/null @@ -1,17 +0,0 @@ -arm_container: - image: gcc:latest - -check_task: - check_script: - # the gcc image ships an outdated CMake, so fetch a recent prebuilt binary - # instead of compiling CMake from source - - wget -q https://github.com/Kitware/CMake/releases/download/v4.3.4/cmake-4.3.4-linux-aarch64.tar.gz - - tar xfz cmake-4.3.4-linux-aarch64.tar.gz - - export PATH="$(pwd)/cmake-4.3.4-linux-aarch64/bin:$PATH" - - cmake --version - - mkdir build - - cd build - - cmake .. -DJSON_FastTests=ON - - make -j4 - - cd tests - - ctest -j4 diff --git a/.github/dependabot.yml b/.github/dependabot.yml index ef1432591..4bf8f8782 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -24,6 +24,10 @@ updates: interval: daily cooldown: default-days: 7 + ignore: + # astyle is deliberately pinned (see tools/astyle/requirements.txt): newer versions + # reformat the code, and the pinned version defines the formatting CI enforces + - dependency-name: astyle - package-ecosystem: pip directory: /tools/generate_natvis diff --git a/.github/external_ci/appveyor.yml b/.github/external_ci/appveyor.yml index 5c6b47a34..805195742 100644 --- a/.github/external_ci/appveyor.yml +++ b/.github/external_ci/appveyor.yml @@ -30,14 +30,6 @@ environment: CMAKE_OPTIONS: "" GENERATOR: Visual Studio 14 2015 - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - configuration: Release - platform: x86 - name: with_win_header - CXX_FLAGS: "/W4 /WX" - CMAKE_OPTIONS: "" - GENERATOR: Visual Studio 14 2015 - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 configuration: Release platform: x86 @@ -74,9 +66,6 @@ install: - if "%platform%"=="x86" set GENERATOR_PLATFORM=Win32 before_build: - # for with_win_header build, inject the inclusion of Windows.h to the single-header library - - ps: if ($env:name -Eq "with_win_header") { $header_path = "single_include\nlohmann\json.hpp" } - - ps: if ($env:name -Eq "with_win_header") { "#include `n" + (Get-Content $header_path | Out-String) | Set-Content $header_path } - cmake . -G "%GENERATOR%" -A "%GENERATOR_PLATFORM%" -DCMAKE_CXX_FLAGS="%CXX_FLAGS%" -DCMAKE_IGNORE_PATH="C:/Program Files/Git/usr/bin" -DJSON_BuildTests=On "%CMAKE_OPTIONS%" build_script: diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index fb3cd4148..485fb3b6d 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -52,6 +52,13 @@ jobs: run: cmake -S . -B build -DJSON_CI=On - name: Build run: cmake --build build --target ci_infer + - name: Archive Infer report + if: always() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: infer-report + path: ${{ github.workspace }}/build/build_infer/infer-out/report.txt + if-no-files-found: ignore ci_static_analysis_ubuntu: runs-on: ubuntu-latest @@ -97,13 +104,13 @@ jobs: ci_cmake_options: runs-on: ubuntu-latest - container: ubuntu:focal + container: ubuntu:24.04 strategy: matrix: target: [ci_cmake_flags, ci_test_diagnostics, ci_test_diagnostic_positions, ci_test_noexceptions, ci_test_noimplicitconversions, ci_test_legacycomparison, ci_test_noglobaludls, ci_test_disableenumserialization, ci_test_disabletuplereferenceconversion, ci_test_skiplibraryversioncheck, ci_test_simdutf, ci_test_strict_nul_handling, ci_test_no_thread_local] steps: - name: Install build-essential - run: apt-get update ; apt-get install -y build-essential unzip wget git libssl-dev + run: apt-get update ; apt-get install -y build-essential unzip wget git - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false @@ -407,3 +414,21 @@ jobs: run: cmake -S . -B build -DJSON_CI=On - name: Build run: cmake --build build --target ${{ matrix.target }} + + # Native Linux ARM64 runner with the latest GCC. The ubuntu-24.04-arm label is + # only available for public repositories. + ci_test_arm64: + runs-on: ubuntu-24.04-arm + container: gcc:latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Get latest CMake and ninja + uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2 + - name: Check that the job runs natively on arm64 + run: uname -m && test "$(uname -m)" = aarch64 + - name: Run CMake + run: cmake -S . -B build -DJSON_CI=On + - name: Build + run: cmake --build build --target ci_test_compiler_default diff --git a/.inferconfig b/.inferconfig new file mode 100644 index 000000000..9a5a36873 --- /dev/null +++ b/.inferconfig @@ -0,0 +1,12 @@ +{ + "_comment": "Used by the ci_infer CMake target (#5715 item 4b). fail-on-issue makes CI fail on Infer findings; disable-issue-type is a type-level baseline for the ~174 pre-existing findings (all PULSE_UNNECESSARY_COPY*/PULSE_RESOURCE_LEAK/PULSE_CONST_REFABLE, mostly in test code) triaged in run https://github.com/nlohmann/json/actions/runs/35829411620 on commit 1054b2097, so CI fails only on a NEW issue type. Remove an entry here once its findings have been fixed or explicitly accepted.", + "fail-on-issue": true, + "disable-issue-type": [ + "PULSE_UNNECESSARY_COPY_ASSIGNMENT", + "PULSE_UNNECESSARY_COPY", + "PULSE_UNNECESSARY_COPY_INTERMEDIATE", + "PULSE_UNNECESSARY_COPY_OPTIONAL", + "PULSE_RESOURCE_LEAK", + "PULSE_CONST_REFABLE" + ] +} diff --git a/FILES.md b/FILES.md index 263647146..d13be1238 100644 --- a/FILES.md +++ b/FILES.md @@ -33,17 +33,6 @@ Further documentation: > [!IMPORTANT] > The folder `.github/workflows` is predetermined by GitHub. -### `.cirrus.yml` - -Configuration file for the pipeline at [Cirrus CI](https://cirrus-ci.com/github/nlohmann/json). - -Further documentation: - -- [Writing tasks](https://cirrus-ci.org/guide/writing-tasks/) - -> [!IMPORTANT] -> The filename `.cirrus.yml` and position (root of the repository) are predetermined by Cirrus CI. - ### `.github/external_ci/appveyor.yml` Configuration for the pipelines at [AppVeyor](https://ci.appveyor.com/project/nlohmann/json). diff --git a/Makefile b/Makefile index fec936343..3a7fa5c41 100644 --- a/Makefile +++ b/Makefile @@ -87,7 +87,7 @@ install_astyle: # call the Artistic Style pretty printer on all source files pretty: install_astyle - $(ASTYLE) --project=tools/astyle/.astylerc $(SRCS) $(TESTS_SRCS) $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_LITERALS_FILE) docs/mkdocs/docs/examples/*.cpp + $(ASTYLE) --project=tools/astyle/.astylerc $(SRCS) $(TESTS_SRCS) $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_LITERALS_FILE) docs/mkdocs/docs/examples/*.cpp docs/mkdocs/docs/examples/*.hpp # create single header files and pretty print amalgamate: $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_LITERALS_FILE) diff --git a/README.md b/README.md index 9fd3f71fc..19b238364 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,6 @@ [![Coverage Status](https://coveralls.io/repos/github/nlohmann/json/badge.svg?branch=develop)](https://coveralls.io/github/nlohmann/json?branch=develop) [![Coverity Scan Build Status](https://scan.coverity.com/projects/5550/badge.svg)](https://scan.coverity.com/projects/nlohmann-json) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/e0d1a9d5d6fd46fcb655c4cb930bb3e8)](https://app.codacy.com/gh/nlohmann/json/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) -[![Cirrus CI](https://api.cirrus-ci.com/github/nlohmann/json.svg)](https://cirrus-ci.com/github/nlohmann/json) [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/json.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:json) [![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/1mp10JbaANo6FUc7) [![Documentation](https://img.shields.io/badge/docs-mkdocs-blue.svg)](https://json.nlohmann.me) diff --git a/cmake/ci.cmake b/cmake/ci.cmake index 27187f235..c0ed77f6c 100644 --- a/cmake/ci.cmake +++ b/cmake/ci.cmake @@ -40,6 +40,14 @@ execute_process(COMMAND ${IWYU_TOOL} --version OUTPUT_VARIABLE IWYU_TOOL_VERSION string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" IWYU_TOOL_VERSION "${IWYU_TOOL_VERSION}") message(STATUS "🔖 include-what-you-use ${IWYU_TOOL_VERSION} (${IWYU_TOOL})") +# CMake's CXX_INCLUDE_WHAT_YOU_USE launcher runs IWYU during the normal compile step (useful to see +# diagnostics inline), but CMake's own __run_co_compile wrapper does not propagate the launched +# tool's exit code to the build, so IWYU's own "-Xiwyu --error" cannot fail that step (verified: a +# deliberately-unused #include in a header still lets `cmake --build` finish with exit code 0). +# iwyu_tool.py, which ships with IWYU, reads compile_commands.json and does return a non-zero exit +# code for any analyzed file with findings; ci_single_binaries uses it to actually fail on findings. +find_program(IWYU_TOOL_PY NAMES iwyu_tool iwyu_tool.py iwyu-tool) + find_program(INFER_TOOL NAMES infer) execute_process(COMMAND ${INFER_TOOL} --version OUTPUT_VARIABLE INFER_TOOL_VERSION ERROR_VARIABLE INFER_TOOL_VERSION) string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" INFER_TOOL_VERSION "${INFER_TOOL_VERSION}") @@ -55,12 +63,6 @@ execute_process(COMMAND ${NINJA_TOOL} --version OUTPUT_VARIABLE NINJA_TOOL_VERSI string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" NINJA_TOOL_VERSION "${NINJA_TOOL_VERSION}") message(STATUS "🔖 Ninja ${NINJA_TOOL_VERSION} (${NINJA_TOOL})") -find_program(OCLINT_TOOL NAMES oclint-json-compilation-database) -find_program(OCLINT_VERSION_TOOL NAMES oclint) -execute_process(COMMAND ${OCLINT_VERSION_TOOL} --version OUTPUT_VARIABLE OCLINT_TOOL_VERSION ERROR_VARIABLE OCLINT_TOOL_VERSION) -string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" OCLINT_TOOL_VERSION "${OCLINT_TOOL_VERSION}") -message(STATUS "🔖 OCLint ${OCLINT_TOOL_VERSION} (${OCLINT_TOOL})") - find_program(VALGRIND_TOOL NAMES valgrind) execute_process(COMMAND ${VALGRIND_TOOL} --version OUTPUT_VARIABLE VALGRIND_TOOL_VERSION ERROR_VARIABLE VALGRIND_TOOL_VERSION) string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" VALGRIND_TOOL_VERSION "${VALGRIND_TOOL_VERSION}") @@ -128,16 +130,16 @@ foreach(CXX_STANDARD 11 14 17 20 23 26) COMMENT "Compile and test with Clang for C++${CXX_STANDARD}" ) + # pass -stdlib=libc++ through CXXFLAGS: an explicit -DCMAKE_CXX_FLAGS would make CMake ignore CXXFLAGS add_custom_target(ci_test_clang_libcxx_cxx${CXX_STANDARD} - COMMAND CXX=${CLANG_TOOL} CXXFLAGS="${CLANG_CXXFLAGS}" ${CMAKE_COMMAND} + COMMAND CXX=${CLANG_TOOL} CXXFLAGS="${CLANG_CXXFLAGS};-stdlib=libc++" ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug -GNinja -DJSON_BuildTests=ON -DJSON_FastTests=ON -DJSON_TestStandards=${CXX_STANDARD} - -DCMAKE_CXX_FLAGS="-stdlib=libc++" -DCMAKE_EXE_LINKER_FLAGS="-lc++abi" - -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_clang_cxx${CXX_STANDARD} - COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_clang_cxx${CXX_STANDARD} - COMMAND cd ${PROJECT_BINARY_DIR}/build_clang_cxx${CXX_STANDARD} && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure + -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_clang_libcxx_cxx${CXX_STANDARD} + COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_clang_libcxx_cxx${CXX_STANDARD} + COMMAND cd ${PROJECT_BINARY_DIR}/build_clang_libcxx_cxx${CXX_STANDARD} && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure COMMENT "Compile and test with Clang for C++${CXX_STANDARD} (libc++)" ) endforeach() @@ -376,13 +378,20 @@ add_custom_target(ci_test_clang_sanitizer # Check if header is amalgamated and sources are properly indented. ############################################################################### +# Same file set as .github/workflows/check_amalgamation.yml, so a direct push to develop/master/release/* +# (which only this CMake target checks, not the pull_request-only workflow) is held to the same standard. file(GLOB_RECURSE INDENT_FILES - ${PROJECT_SOURCE_DIR}/include/nlohmann/*.hpp - ${PROJECT_SOURCE_DIR}/tests/src/*.cpp - ${PROJECT_SOURCE_DIR}/tests/src/*.hpp - ${PROJECT_SOURCE_DIR}/tests/benchmarks/src/benchmarks.cpp + ${PROJECT_SOURCE_DIR}/docs/mkdocs/docs/examples/*.hpp ${PROJECT_SOURCE_DIR}/docs/mkdocs/docs/examples/*.cpp + ${PROJECT_SOURCE_DIR}/docs/mkdocs/docs/examples/*.cu + ${PROJECT_SOURCE_DIR}/include/*.hpp + ${PROJECT_SOURCE_DIR}/include/*.cpp + ${PROJECT_SOURCE_DIR}/include/*.cu + ${PROJECT_SOURCE_DIR}/tests/*.hpp + ${PROJECT_SOURCE_DIR}/tests/*.cpp + ${PROJECT_SOURCE_DIR}/tests/*.cu ) +list(FILTER INDENT_FILES EXCLUDE REGEX "/tests/thirdparty/|/tests/abi/include/nlohmann/") set(include_dir ${PROJECT_SOURCE_DIR}/single_include/nlohmann) set(tool_dir ${PROJECT_SOURCE_DIR}/tools/amalgamate) @@ -391,6 +400,7 @@ add_custom_target(ci_test_amalgamation COMMAND cp ${include_dir}/json.hpp ${include_dir}/json.hpp~ COMMAND cp ${include_dir}/json_fwd.hpp ${include_dir}/json_fwd.hpp~ COMMAND cp ${include_dir}/json_literals.hpp ${include_dir}/json_literals.hpp~ + COMMAND cp ${PROJECT_SOURCE_DIR}/BUILD.bazel ${PROJECT_SOURCE_DIR}/BUILD.bazel~ COMMAND ${Python3_EXECUTABLE} -mvenv venv_astyle COMMAND venv_astyle/bin/pip3 --quiet install -r ${CMAKE_SOURCE_DIR}/tools/astyle/requirements.txt @@ -400,16 +410,18 @@ add_custom_target(ci_test_amalgamation COMMAND ${Python3_EXECUTABLE} ${tool_dir}/amalgamate.py -c ${tool_dir}/config_json_fwd.json -s . COMMAND cp ${PROJECT_SOURCE_DIR}/include/nlohmann/json_literals.hpp ${include_dir}/json_literals.hpp COMMAND venv_astyle/bin/astyle --project=tools/astyle/.astylerc --suffix=none ${include_dir}/json.hpp ${include_dir}/json_fwd.hpp + COMMAND ${CMAKE_COMMAND} -P ${PROJECT_SOURCE_DIR}/cmake/scripts/gen_bazel_build_file.cmake COMMAND diff ${include_dir}/json.hpp~ ${include_dir}/json.hpp COMMAND diff ${include_dir}/json_fwd.hpp~ ${include_dir}/json_fwd.hpp COMMAND diff ${include_dir}/json_literals.hpp~ ${include_dir}/json_literals.hpp + COMMAND diff ${PROJECT_SOURCE_DIR}/BUILD.bazel~ ${PROJECT_SOURCE_DIR}/BUILD.bazel COMMAND venv_astyle/bin/astyle --project=tools/astyle/.astylerc --suffix=orig ${INDENT_FILES} COMMAND for FILE in `find . -name '*.orig'`\; do false \; done WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - COMMENT "Check amalgamation and indentation" + COMMENT "Check amalgamation, formatting, and BUILD.bazel" ) ############################################################################### @@ -444,14 +456,14 @@ add_custom_target(ci_test_valgrind # Check code with Clang Static Analyzer. ############################################################################### -set(CLANG_ANALYZER_CHECKS "fuchsia.HandleChecker,nullability.NullableDereferenced,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,optin.cplusplus.UninitializedObject,optin.cplusplus.VirtualCall,optin.mpi.MPI-Checker,optin.osx.OSObjectCStyleCast,optin.osx.cocoa.localizability.EmptyLocalizationContextChecker,optin.osx.cocoa.localizability.NonLocalizedStringChecker,optin.performance.GCDAntipattern,optin.performance.Padding,optin.portability.UnixAPI,security.FloatLoopCounter,security.insecureAPI.DeprecatedOrUnsafeBufferHandling,security.insecureAPI.bcmp,security.insecureAPI.bcopy,security.insecureAPI.bzero,security.insecureAPI.rand,security.insecureAPI.strcpy,valist.CopyToSelf,valist.Uninitialized,valist.Unterminated,webkit.NoUncountedMemberChecker,webkit.RefCntblBaseVirtualDtor,core.CallAndMessage,core.DivideZero,core.NonNullParamChecker,core.NullDereference,core.StackAddressEscape,core.UndefinedBinaryOperatorResult,core.VLASize,core.uninitialized.ArraySubscript,core.uninitialized.Assign,core.uninitialized.Branch,core.uninitialized.CapturedBlockVariable,core.uninitialized.UndefReturn,cplusplus.InnerPointer,cplusplus.Move,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,cplusplus.PlacementNew,cplusplus.PureVirtualCall,deadcode.DeadStores,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull,osx.API,osx.MIG,osx.NumberObjectConversion,osx.OSObjectRetainCount,osx.ObjCProperty,osx.SecKeychainAPI,osx.cocoa.AtSync,osx.cocoa.AutoreleaseWrite,osx.cocoa.ClassRelease,osx.cocoa.Dealloc,osx.cocoa.IncompatibleMethodTypes,osx.cocoa.Loops,osx.cocoa.MissingSuperCall,osx.cocoa.NSAutoreleasePool,osx.cocoa.NSError,osx.cocoa.NilArg,osx.cocoa.NonNilReturnValue,osx.cocoa.ObjCGenerics,osx.cocoa.RetainCount,osx.cocoa.RunLoopAutoreleaseLeak,osx.cocoa.SelfInit,osx.cocoa.SuperDealloc,osx.cocoa.UnusedIvars,osx.cocoa.VariadicMethodTypes,osx.coreFoundation.CFError,osx.coreFoundation.CFNumber,osx.coreFoundation.CFRetainRelease,osx.coreFoundation.containers.OutOfBounds,osx.coreFoundation.containers.PointerSizedValues,security.insecureAPI.UncheckedReturn,security.insecureAPI.decodeValueOfObjCType,security.insecureAPI.getpw,security.insecureAPI.gets,security.insecureAPI.mkstemp,security.insecureAPI.mktemp,security.insecureAPI.vfork,unix.API,unix.Malloc,unix.MallocSizeof,unix.MismatchedDeallocator,unix.Vfork,unix.cstring.BadSizeArg,unix.cstring.NullArg") +set(CLANG_ANALYZER_CHECKS "nullability.NullableDereferenced,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,optin.cplusplus.UninitializedObject,optin.cplusplus.VirtualCall,optin.performance.Padding,optin.portability.UnixAPI,security.FloatLoopCounter,security.insecureAPI.DeprecatedOrUnsafeBufferHandling,security.insecureAPI.bcmp,security.insecureAPI.bcopy,security.insecureAPI.bzero,security.insecureAPI.rand,security.insecureAPI.strcpy,valist.CopyToSelf,valist.Uninitialized,valist.Unterminated,core.CallAndMessage,core.DivideZero,core.NonNullParamChecker,core.NullDereference,core.StackAddressEscape,core.UndefinedBinaryOperatorResult,core.VLASize,core.uninitialized.ArraySubscript,core.uninitialized.Assign,core.uninitialized.Branch,core.uninitialized.CapturedBlockVariable,core.uninitialized.UndefReturn,cplusplus.InnerPointer,cplusplus.Move,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,cplusplus.PlacementNew,cplusplus.PureVirtualCall,deadcode.DeadStores,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull,security.insecureAPI.UncheckedReturn,security.insecureAPI.decodeValueOfObjCType,security.insecureAPI.getpw,security.insecureAPI.gets,security.insecureAPI.mkstemp,security.insecureAPI.mktemp,security.insecureAPI.vfork,unix.API,unix.Malloc,unix.MallocSizeof,unix.MismatchedDeallocator,unix.Vfork,unix.cstring.BadSizeArg,unix.cstring.NullArg") add_custom_target(ci_clang_analyze COMMAND CXX=${CLANG_TOOL} ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug -GNinja -DJSON_BuildTests=ON -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_clang_analyze - COMMAND cd ${PROJECT_BINARY_DIR}/build_clang_analyze && ${SCAN_BUILD_TOOL} -enable-checker ${CLANG_ANALYZER_CHECKS} --use-c++=${CLANG_TOOL} -analyze-headers -o ${PROJECT_BINARY_DIR}/report ninja + COMMAND cd ${PROJECT_BINARY_DIR}/build_clang_analyze && ${SCAN_BUILD_TOOL} -enable-checker ${CLANG_ANALYZER_CHECKS} --use-c++=${CLANG_TOOL} --use-analyzer=${CLANG_TOOL} -analyze-headers --status-bugs -o ${PROJECT_BINARY_DIR}/report ninja COMMENT "Check code with Clang Analyzer" ) @@ -467,7 +479,7 @@ add_custom_target(ci_cppcheck COMMAND venv_cppcheck/bin/cppcheck --enable=warning --check-level=exhaustive --inline-suppr --inconclusive --force --std=c++11 ${PROJECT_SOURCE_DIR}/include/nlohmann/json.hpp -I ${CMAKE_SOURCE_DIR}/include --error-exitcode=1 --relative-paths=${PROJECT_SOURCE_DIR} -j ${N} --include=default_defines.hpp - --cppcheck-build-dir=cppcheck --check-level=exhaustive + --cppcheck-build-dir=cppcheck -UJSON_CATCH_USER -UJSON_TRY_USER -UJSON_ASSERT -UJSON_INTERNAL_CATCH -UJSON_THROW -DJSON_HAS_CPP_11 -UJSON_HAS_CPP_14 -UJSON_HAS_CPP_17 -UJSON_HAS_CPP_20 -UJSON_HAS_THREE_WAY_COMPARISON COMMENT "Check code with Cppcheck" @@ -485,34 +497,6 @@ add_custom_target(ci_cpplint WORKING_DIRECTORY ${PROJECT_BINARY_DIR} ) -############################################################################### -# Check code with OCLint. -############################################################################### - -file(COPY ${PROJECT_SOURCE_DIR}/single_include/nlohmann/json.hpp DESTINATION ${PROJECT_BINARY_DIR}/src_single) -file(RENAME ${PROJECT_BINARY_DIR}/src_single/json.hpp ${PROJECT_BINARY_DIR}/src_single/all.cpp) -file(APPEND "${PROJECT_BINARY_DIR}/src_single/all.cpp" "\n\nint main()\n{}\n") - -add_executable(single_all ${PROJECT_BINARY_DIR}/src_single/all.cpp) -target_compile_features(single_all PRIVATE cxx_std_11) - -add_custom_target(ci_oclint - COMMAND ${CMAKE_COMMAND} - -DCMAKE_BUILD_TYPE=Debug - -DCMAKE_EXPORT_COMPILE_COMMANDS=ON - -DJSON_BuildTests=OFF -DJSON_CI=ON - -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_oclint - COMMAND ${OCLINT_TOOL} -i ${PROJECT_BINARY_DIR}/build_oclint/src_single/all.cpp -p ${PROJECT_BINARY_DIR}/build_oclint -- - -report-type html -enable-global-analysis --max-priority-1=0 --max-priority-2=1000 --max-priority-3=2000 - --disable-rule=MultipleUnaryOperator - --disable-rule=DoubleNegative - --disable-rule=ShortVariableName - --disable-rule=GotoStatement - --disable-rule=LongLine - -o ${PROJECT_BINARY_DIR}/build_oclint/oclint_report.html - COMMENT "Check code with OCLint" -) - ############################################################################### # Check code with Clang-Tidy. ############################################################################### @@ -527,29 +511,16 @@ add_custom_target(ci_clang_tidy COMMENT "Check code with Clang-Tidy" ) -############################################################################### -# Check code with PVS-Studio Analyzer . -############################################################################### - -add_custom_target(ci_pvs_studio - COMMAND CXX=${CLANG_TOOL} ${CMAKE_COMMAND} - -DCMAKE_BUILD_TYPE=Debug - -DCMAKE_EXPORT_COMPILE_COMMANDS=ON - -DJSON_BuildTests=ON - -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_pvs_studio - COMMAND cd ${PROJECT_BINARY_DIR}/build_pvs_studio && ${PVS_STUDIO_ANALYZER_TOOL} analyze -j 10 - COMMAND cd ${PROJECT_BINARY_DIR}/build_pvs_studio && ${PLOG_CONVERTER_TOOL} -a'GA:1,2;64:1;CS' -t fullhtml PVS-Studio.log -o pvs - COMMENT "Check code with PVS Studio" -) - ############################################################################### # Check code with Infer static analyzer. ############################################################################### +# .inferconfig (repository root) pins --fail-on-issue and the currently-triaged issue types that +# are disabled until they are addressed separately; see #5715 item 4b. add_custom_target(ci_infer COMMAND mkdir -p ${PROJECT_BINARY_DIR}/build_infer COMMAND cd ${PROJECT_BINARY_DIR}/build_infer && ${INFER_TOOL} compile -- ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug ${PROJECT_SOURCE_DIR} -DJSON_BuildTests=ON - COMMAND cd ${PROJECT_BINARY_DIR}/build_infer && ${INFER_TOOL} run -- make + COMMAND cd ${PROJECT_BINARY_DIR}/build_infer && ${INFER_TOOL} run --project-root ${PROJECT_SOURCE_DIR} -- make COMMENT "Check code with Infer" ) @@ -605,7 +576,13 @@ add_custom_target(ci_reproducible_tests # be compiled individually. ############################################################################### -set(iwyu_path_and_options ${IWYU_TOOL} -Xiwyu --max_line_length=300) +set(iwyu_options -Xiwyu --error -Xiwyu --max_line_length=300) +set(iwyu_path_and_options ${IWYU_TOOL} ${iwyu_options}) + +# CMake needs to know the exact flags used to compile each src_single/*.cpp below to hand them to +# iwyu_tool.py; JSON_CI already implies a from-scratch configure, so enabling this project-wide has +# no downside here. +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) foreach(SRC_FILE ${SRC_FILES}) # get relative path of the header file @@ -620,14 +597,34 @@ foreach(SRC_FILE ${SRC_FILES}) target_include_directories(single_${RELATIVE_SRC_FILE} PRIVATE ${PROJECT_SOURCE_DIR}/include) target_compile_features(single_${RELATIVE_SRC_FILE} PRIVATE cxx_std_11) set_property(TARGET single_${RELATIVE_SRC_FILE} PROPERTY CXX_INCLUDE_WHAT_YOU_USE "${iwyu_path_and_options}") - # remember binary for ci_single_binaries target + # remember binary for ci_single_binaries list(APPEND single_binaries single_${RELATIVE_SRC_FILE}) + # json.hpp pulls together the whole library behind heavily templated, SFINAE-based code, and + # IWYU's suggestion for its one truly ambiguous symbol (a container-comparison "swap, + # operator!=") is not deterministic between runs (observed , , and + # for the exact same source across otherwise-identical local and containerized builds). Keep + # reporting its diagnostics (informational, via CXX_INCLUDE_WHAT_YOU_USE above) but exclude it + # from the hard gate below so a fresh IWYU/compiler combination does not fail this target on a + # nondeterministic suggestion for a header that already re-exports everything on purpose. + if(NOT RELATIVE_SRC_FILE STREQUAL "json") + list(APPEND single_binaries_tus src_single/${RELATIVE_SRC_FILE}.cpp) + endif() endforeach() -add_custom_target(ci_single_binaries - DEPENDS ${single_binaries} - COMMENT "Check if headers are self-contained" -) +if(IWYU_TOOL_PY) + add_custom_target(ci_single_binaries + DEPENDS ${single_binaries} + COMMAND ${IWYU_TOOL_PY} -p ${PROJECT_BINARY_DIR} ${single_binaries_tus} -- ${iwyu_options} + COMMENT "Check if headers are self-contained" + ) +else() + # iwyu_tool.py (ships with IWYU, e.g. as /usr/bin/iwyu_tool on Debian/Ubuntu) was not found; + # fall back to building the self-containment check without enforcing the IWYU findings. + add_custom_target(ci_single_binaries + DEPENDS ${single_binaries} + COMMENT "Check if headers are self-contained" + ) +endif() ############################################################################### # Benchmarks @@ -649,21 +646,41 @@ add_custom_target(ci_benchmarks # we test the project with different CMake versions: # - CMake 3.5 (the earliest supported) # - CMake 3.31.6 (the latest 3.x release) -# - CMake 4.0.0 (the latest release) +# - CMake 4.0.0 (the first 4.x release) +# - the CMake version running this build (usually the latest release) function(ci_get_cmake version var) set(${var} ${PROJECT_BINARY_DIR}/cmake-${version}/bin/cmake) - add_custom_command( - OUTPUT ${${var}} - COMMAND wget -nc https://github.com/Kitware/CMake/releases/download/v${version}/cmake-${version}.tar.gz - COMMAND tar xfz cmake-${version}.tar.gz - COMMAND rm cmake-${version}.tar.gz - # -DCMAKE_POLICY_VERSION_MINIMUM=3.5 required to compile older CMake versions with CMake 4.0.0 - COMMAND cmake -S cmake-${version} -B cmake-${version} -DCMAKE_POLICY_VERSION_MINIMUM=3.5 - COMMAND cmake --build cmake-${version} --parallel 10 - WORKING_DIRECTORY ${PROJECT_BINARY_DIR} - COMMENT "Download CMake ${version}" - ) + if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64)$") + # Kitware publishes a prebuilt Linux x86_64 archive for every release; unpacking it is far + # cheaper than compiling all of CMake (including its own test helpers) from source. + add_custom_command( + OUTPUT ${${var}} + COMMAND wget -nc https://github.com/Kitware/CMake/releases/download/v${version}/cmake-${version}-linux-x86_64.tar.gz + COMMAND wget -nc https://github.com/Kitware/CMake/releases/download/v${version}/cmake-${version}-SHA-256.txt + # verify the archive against Kitware's published SHA-256 sums before unpacking it + COMMAND sh -c "grep ' cmake-${version}-linux-x86_64[.]tar[.]gz$' cmake-${version}-SHA-256.txt | sha256sum -c -" + COMMAND tar xfz cmake-${version}-linux-x86_64.tar.gz + COMMAND rm cmake-${version}-linux-x86_64.tar.gz cmake-${version}-SHA-256.txt + COMMAND ${CMAKE_COMMAND} -E rm -rf cmake-${version} + COMMAND ${CMAKE_COMMAND} -E rename cmake-${version}-linux-x86_64 cmake-${version} + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + COMMENT "Download prebuilt CMake ${version}" + ) + else() + # no prebuilt archive for this platform (e.g. macOS or Linux aarch64): build from source + add_custom_command( + OUTPUT ${${var}} + COMMAND wget -nc https://github.com/Kitware/CMake/releases/download/v${version}/cmake-${version}.tar.gz + COMMAND tar xfz cmake-${version}.tar.gz + COMMAND rm cmake-${version}.tar.gz + # -DCMAKE_POLICY_VERSION_MINIMUM=3.5 required to compile older CMake versions with CMake 4.0.0 + COMMAND cmake -S cmake-${version} -B cmake-${version} -DCMAKE_POLICY_VERSION_MINIMUM=3.5 + COMMAND cmake --build cmake-${version} --parallel 10 + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + COMMENT "Download and build CMake ${version} from source" + ) + endif() set(${var} ${${var}} PARENT_SCOPE) endfunction() @@ -673,30 +690,24 @@ ci_get_cmake(4.0.0 CMAKE_4_0_0_BINARY) # the tests require CMake 3.13 or later, so they are excluded for CMake 3.5.0 set(JSON_CMAKE_FLAGS_3_5_0 JSON_Diagnostics JSON_Diagnostic_Positions JSON_GlobalUDLs JSON_ImplicitConversions JSON_DisableEnumSerialization - JSON_LegacyDiscardedValueComparison JSON_Install JSON_MultipleHeaders JSON_SystemInclude JSON_Valgrind) -set(JSON_CMAKE_FLAGS_3_31_6 JSON_BuildTests ${JSON_CMAKE_FLAGS_3_31_6}) + JSON_LegacyDiscardedValueComparison JSON_Install JSON_MultipleHeaders JSON_SystemInclude JSON_Valgrind + JSON_StrictNulHandling) +set(JSON_CMAKE_FLAGS_3_31_6 JSON_BuildTests ${JSON_CMAKE_FLAGS_3_5_0}) set(JSON_CMAKE_FLAGS_4_0_0 JSON_BuildTests ${JSON_CMAKE_FLAGS_3_5_0}) function(ci_add_cmake_flags_targets flag min_version) string(TOLOWER "ci_cmake_flag_${flag}" flag_target) string(REPLACE . _ min_version_var ${min_version}) set(cmake_binary ${CMAKE_${min_version_var}_BINARY}) - add_custom_target(${flag_target}_${min_version}_2 - COMMENT "Check CMake flag ${flag} (CMake ${CMAKE_VERSION})" - COMMAND ${CMAKE_COMMAND} - -Werror=dev - -D${flag}=ON - -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_${flag_target} - ) add_custom_target(${flag_target}_${min_version_var} - COMMENT "Check CMake flag ${JSON_CMAKE_FLAG} (CMake ${min_version})" + COMMENT "Check CMake flag ${flag} (CMake ${min_version})" COMMAND mkdir -pv ${PROJECT_BINARY_DIR}/build_${flag_target}_${min_version_var} COMMAND cd ${PROJECT_BINARY_DIR}/build_${flag_target}_${min_version_var} && ${cmake_binary} -Werror=dev ${PROJECT_SOURCE_DIR} -D${flag}=ON DEPENDS ${cmake_binary} ) - list(APPEND JSON_CMAKE_FLAG_TARGETS ${JSON_CMAKE_FLAG_TARGET} ${flag_target}_${min_version_var}) - list(APPEND JSON_CMAKE_FLAG_BUILD_DIRS ${PROJECT_BINARY_DIR}/build_${flag_target} ${PROJECT_BINARY_DIR}/build_${flag_target}_${min_version_var}) + list(APPEND JSON_CMAKE_FLAG_TARGETS ${flag_target}_${min_version_var}) + list(APPEND JSON_CMAKE_FLAG_BUILD_DIRS ${PROJECT_BINARY_DIR}/build_${flag_target}_${min_version_var}) set(JSON_CMAKE_FLAG_TARGETS ${JSON_CMAKE_FLAG_TARGETS} PARENT_SCOPE) set(JSON_CMAKE_FLAG_BUILD_DIRS ${JSON_CMAKE_FLAG_BUILD_DIRS} PARENT_SCOPE) endfunction() @@ -713,6 +724,20 @@ foreach(JSON_CMAKE_FLAG ${JSON_CMAKE_FLAGS_4_0_0}) ci_add_cmake_flags_targets(${JSON_CMAKE_FLAG} 4.0.0) endforeach() +# check the same flags with the CMake version running this build +foreach(JSON_CMAKE_FLAG ${JSON_CMAKE_FLAGS_4_0_0}) + string(TOLOWER "ci_cmake_flag_${JSON_CMAKE_FLAG}" flag_target) + add_custom_target(${flag_target} + COMMENT "Check CMake flag ${JSON_CMAKE_FLAG} (CMake ${CMAKE_VERSION})" + COMMAND ${CMAKE_COMMAND} + -Werror=dev + -D${JSON_CMAKE_FLAG}=ON + -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_${flag_target} + ) + list(APPEND JSON_CMAKE_FLAG_TARGETS ${flag_target}) + list(APPEND JSON_CMAKE_FLAG_BUILD_DIRS ${PROJECT_BINARY_DIR}/build_${flag_target}) +endforeach() + add_custom_target(ci_cmake_flags DEPENDS ${JSON_CMAKE_FLAG_TARGETS} COMMENT "Check CMake flags" @@ -871,6 +896,6 @@ add_custom_target(ci_test_build_documentation ############################################################################### add_custom_target(ci_clean - COMMAND rm -fr ${PROJECT_BINARY_DIR}/build_* cmake-3.5.0-Darwin64 ${JSON_CMAKE_FLAG_BUILD_DIRS} ${single_binaries} + COMMAND rm -fr ${PROJECT_BINARY_DIR}/build_* ${PROJECT_BINARY_DIR}/cmake-3.5.0 ${PROJECT_BINARY_DIR}/cmake-3.31.6 ${PROJECT_BINARY_DIR}/cmake-4.0.0 ${JSON_CMAKE_FLAG_BUILD_DIRS} ${single_binaries} COMMENT "Clean generated directories" ) diff --git a/docs/mkdocs/docs/community/quality_assurance.md b/docs/mkdocs/docs/community/quality_assurance.md index f2404c77b..d44135bf2 100644 --- a/docs/mkdocs/docs/community/quality_assurance.md +++ b/docs/mkdocs/docs/community/quality_assurance.md @@ -90,7 +90,7 @@ Note: Some modern features (like C++20 ranges or filesystem support) may be disa | GNU 14.2.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | | GNU 15.1.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | | GNU 16.1.0 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | - | GNU 16.1.0 | arm64 | Linux 6.1.100 | Cirrus CI | + | GNU 16.1.0 | arm64 | Ubuntu 24.04 | GitHub | | icpc (ICC) 2021.10.0 20230609 | x86_64 | Ubuntu 22.04 LTS | GitHub | | icpx (Intel oneAPI DPC++/C++) 2025.3.2 | x86_64 | Ubuntu 24.04 LTS | GitHub | | nvc++ (NVIDIA HPC SDK) 25.5-0 | x86_64 | Ubuntu 22.04 LTS | GitHub | @@ -132,7 +132,8 @@ Note: Some modern features (like C++20 ranges or filesystem support) may be disa [libstdc++](https://gcc.gnu.org/onlinedocs/libstdc++/) to detect subtle differences or incompatibilities. - [x] The code checked with [Include What You Use (IWYU)](https://include-what-you-use.org) that all required standard headers are included. -- [x] On Windows, the library is compiled with `` being included to detect and avoid common bugs. +- [x] On Windows, the library is compiled with `` being included to detect and avoid common bugs (see + [`unit-windows_h.cpp`](https://github.com/nlohmann/json/blob/develop/tests/src/unit-windows_h.cpp)). - [x] The library is compiled with exceptions disabled to support alternative means of error handling. ## Stable public API diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 09a1ec9b5..de82cad37 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -29,7 +29,9 @@ #endif #include // all_of, find, for_each, none_of +#include // isnan #include // nullptr_t, ptrdiff_t, size_t +#include // uint8_t #include // hash, less #include // initializer_list #ifndef JSON_NO_IO @@ -38,19 +40,28 @@ #include // make_move_iterator, random_access_iterator_tag #include // numeric_limits #include // unique_ptr +#include // swap, operator!= #include // length_error #include // string, stoi, to_string +#include // enable_if_t, is_same, is_scalar, ... +#include // swap (for the from_json(..., std::unordered_map&) overload) #include // declval, forward, move, pair, swap #include // vector -#include +// keep: json.hpp's own basic_json<> default template arguments need the complete definition of +// each of these, not only the forward declarations from json_fwd.hpp, so IWYU's suggestion to +// drop them (nothing in this file otherwise names the type) would break every downstream +// translation unit that relies on basic_json<>'s defaults actually being usable. +#include // IWYU pragma: keep #include -#include -#include +#include +#include // IWYU pragma: keep +#include // IWYU pragma: keep #include #include #include #include +#include #include #include #include @@ -62,6 +73,7 @@ #include #include #include +#include #include #include #include @@ -73,7 +85,8 @@ #include #include #include -#include +#include // IWYU pragma: keep +#include #if defined(JSON_HAS_CPP_17) #if JSON_HAS_STATIC_RTTI @@ -6802,7 +6815,10 @@ struct formatter // NOLINT(cert-dcl58-c } // namespace std -#include +// keep: undoes the macros defined via detail/macro_scope.hpp at the top of this file; removing it +// (nothing in this file *uses* a symbol from it) would leak JSON_* macros into every translation +// unit that includes this header. +#include // IWYU pragma: keep // End of GCC diagnostic pragmas for C++ modules support #if defined(__GNUC__) && !defined(__clang__) && __cplusplus >= 202002L diff --git a/include/nlohmann/json_fwd.hpp b/include/nlohmann/json_fwd.hpp index be05ebeef..3ca4d082d 100644 --- a/include/nlohmann/json_fwd.hpp +++ b/include/nlohmann/json_fwd.hpp @@ -11,8 +11,7 @@ #include // int64_t, uint64_t #include // map -#include // allocator -#include // string +#include // allocator, string #include // vector #include @@ -32,7 +31,7 @@ This serializer ignores the template arguments and uses ADL for serialization. */ template -struct adl_serializer; +struct adl_serializer; // IWYU pragma: keep /// a class to store JSON values /// @sa https://json.nlohmann.me/api/basic_json/ @@ -48,12 +47,12 @@ template class ObjectType = adl_serializer, class BinaryType = std::vector, // cppcheck-suppress syntaxError class CustomBaseClass = void> -class basic_json; +class basic_json; // IWYU pragma: keep /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document /// @sa https://json.nlohmann.me/api/json_pointer/ template -class json_pointer; +class json_pointer; // IWYU pragma: keep /*! @brief default specialization @@ -64,7 +63,7 @@ using json = basic_json<>; /// @brief a minimal map-like container that preserves insertion order /// @sa https://json.nlohmann.me/api/ordered_map/ template -struct ordered_map; +struct ordered_map; // IWYU pragma: keep /// @brief specialization that maintains the insertion order of object keys /// @sa https://json.nlohmann.me/api/ordered_json/ diff --git a/include/nlohmann/ordered_map.hpp b/include/nlohmann/ordered_map.hpp index 15e52ebb1..7b6f63781 100644 --- a/include/nlohmann/ordered_map.hpp +++ b/include/nlohmann/ordered_map.hpp @@ -12,13 +12,14 @@ #include // equal_to, less #include // initializer_list #include // input_iterator_tag, iterator_traits -#include // allocator +#include // for operator new (placement new) #include // for out_of_range #include // forward_as_tuple #include // enable_if, integral_constant, is_convertible, is_nothrow_move_constructible #include // forward, move, pair, piecewise_construct -#include // vector +#include // vector, allocator +#include #include #include diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index c6c4d81b5..f39e593b9 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -29,7 +29,9 @@ #endif #include // all_of, find, for_each, none_of +#include // isnan #include // nullptr_t, ptrdiff_t, size_t +#include // uint8_t #include // hash, less #include // initializer_list #ifndef JSON_NO_IO @@ -38,11 +40,18 @@ #include // make_move_iterator, random_access_iterator_tag #include // numeric_limits #include // unique_ptr +#include // swap, operator!= #include // length_error #include // string, stoi, to_string +#include // enable_if_t, is_same, is_scalar, ... +#include // swap (for the from_json(..., std::unordered_map&) overload) #include // declval, forward, move, pair, swap #include // vector +// keep: json.hpp's own basic_json<> default template arguments need the complete definition of +// each of these, not only the forward declarations from json_fwd.hpp, so IWYU's suggestion to +// drop them (nothing in this file otherwise names the type) would break every downstream +// translation unit that relies on basic_json<>'s defaults actually being usable. // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ @@ -3973,8 +3982,7 @@ NLOHMANN_JSON_NAMESPACE_END #include // int64_t, uint64_t #include // map - #include // allocator - #include // string + #include // allocator, string #include // vector // #include @@ -3995,7 +4003,7 @@ NLOHMANN_JSON_NAMESPACE_END for serialization. */ template - struct adl_serializer; + struct adl_serializer; // IWYU pragma: keep /// a class to store JSON values /// @sa https://json.nlohmann.me/api/basic_json/ @@ -4011,12 +4019,12 @@ NLOHMANN_JSON_NAMESPACE_END adl_serializer, class BinaryType = std::vector, // cppcheck-suppress syntaxError class CustomBaseClass = void> - class basic_json; + class basic_json; // IWYU pragma: keep /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document /// @sa https://json.nlohmann.me/api/json_pointer/ template - class json_pointer; + class json_pointer; // IWYU pragma: keep /*! @brief default specialization @@ -4027,7 +4035,7 @@ NLOHMANN_JSON_NAMESPACE_END /// @brief a minimal map-like container that preserves insertion order /// @sa https://json.nlohmann.me/api/ordered_map/ template - struct ordered_map; + struct ordered_map; // IWYU pragma: keep /// @brief specialization that maintains the insertion order of object keys /// @sa https://json.nlohmann.me/api/ordered_json/ @@ -7144,7 +7152,7 @@ struct adl_serializer }; NLOHMANN_JSON_NAMESPACE_END - +// IWYU pragma: keep // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ @@ -7251,10 +7259,12 @@ class byte_container_with_subtype : public BinaryType NLOHMANN_JSON_NAMESPACE_END +// #include + // #include - +// IWYU pragma: keep // #include - +// IWYU pragma: keep // #include // #include @@ -17855,6 +17865,8 @@ NLOHMANN_JSON_NAMESPACE_END // #include +// #include + // #include // #include @@ -20836,6 +20848,8 @@ NLOHMANN_JSON_NAMESPACE_END // #include +// #include + // #include // #include @@ -26375,12 +26389,14 @@ NLOHMANN_JSON_NAMESPACE_END #include // equal_to, less #include // initializer_list #include // input_iterator_tag, iterator_traits -#include // allocator +#include // for operator new (placement new) #include // for out_of_range #include // forward_as_tuple #include // enable_if, integral_constant, is_convertible, is_nothrow_move_constructible #include // forward, move, pair, piecewise_construct -#include // vector +#include // vector, allocator + +// #include // #include @@ -26815,6 +26831,8 @@ private: }; NLOHMANN_JSON_NAMESPACE_END +// IWYU pragma: keep +// #include #if defined(JSON_HAS_CPP_17) @@ -33544,6 +33562,9 @@ struct formatter // NOLINT(cert-dcl58-c } // namespace std +// keep: undoes the macros defined via detail/macro_scope.hpp at the top of this file; removing it +// (nothing in this file *uses* a symbol from it) would leak JSON_* macros into every translation +// unit that includes this header. // #include // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ @@ -33758,7 +33779,7 @@ struct formatter // NOLINT(cert-dcl58-c #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG #undef JSON_HEDLEY_FALL_THROUGH - +// IWYU pragma: keep // End of GCC diagnostic pragmas for C++ modules support #if defined(__GNUC__) && !defined(__clang__) && __cplusplus >= 202002L diff --git a/single_include/nlohmann/json_fwd.hpp b/single_include/nlohmann/json_fwd.hpp index f23ea4820..3ee7afa73 100644 --- a/single_include/nlohmann/json_fwd.hpp +++ b/single_include/nlohmann/json_fwd.hpp @@ -11,8 +11,7 @@ #include // int64_t, uint64_t #include // map -#include // allocator -#include // string +#include // allocator, string #include // vector // #include @@ -177,7 +176,7 @@ This serializer ignores the template arguments and uses ADL for serialization. */ template -struct adl_serializer; +struct adl_serializer; // IWYU pragma: keep /// a class to store JSON values /// @sa https://json.nlohmann.me/api/basic_json/ @@ -193,12 +192,12 @@ template class ObjectType = adl_serializer, class BinaryType = std::vector, // cppcheck-suppress syntaxError class CustomBaseClass = void> -class basic_json; +class basic_json; // IWYU pragma: keep /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document /// @sa https://json.nlohmann.me/api/json_pointer/ template -class json_pointer; +class json_pointer; // IWYU pragma: keep /*! @brief default specialization @@ -209,7 +208,7 @@ using json = basic_json<>; /// @brief a minimal map-like container that preserves insertion order /// @sa https://json.nlohmann.me/api/ordered_map/ template -struct ordered_map; +struct ordered_map; // IWYU pragma: keep /// @brief specialization that maintains the insertion order of object keys /// @sa https://json.nlohmann.me/api/ordered_json/ diff --git a/tests/src/unit.cpp b/tests/src/unit.cpp index 93a934005..c05cde9c8 100644 --- a/tests/src/unit.cpp +++ b/tests/src/unit.cpp @@ -7,4 +7,22 @@ // SPDX-License-Identifier: MIT #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN + +// libc++ annotates std::mutex for Clang's thread safety analysis, so -Weverything +// reports -Wthread-safety-negative for the locks in doctest's reporters, which are +// only compiled in this file. __has_warning keeps older Clang versions from +// reporting an unknown warning group. +#if defined(__clang__) && defined(__has_warning) + #if __has_warning("-Wthread-safety-negative") + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wthread-safety-negative" + #endif +#endif + #include "doctest_compatibility.h" + +#if defined(__clang__) && defined(__has_warning) + #if __has_warning("-Wthread-safety-negative") + #pragma clang diagnostic pop + #endif +#endif diff --git a/tools/astyle/requirements.txt b/tools/astyle/requirements.txt index 99458a860..cfa98d67e 100644 --- a/tools/astyle/requirements.txt +++ b/tools/astyle/requirements.txt @@ -1 +1,4 @@ +# astyle is deliberately pinned: newer versions reformat the code, and this version +# defines the formatting that `make amalgamate` produces and check_amalgamation.yml enforces. +# Dependabot is told to ignore it in .github/dependabot.yml. astyle==3.4.13