mirror of
https://github.com/nlohmann/json.git
synced 2026-10-03 13:10:33 +00:00
tools/macro_builder only emitted NLOHMANN_JSON_EXPAND..PASTE64, so two other tables that scale with the same max_args stayed hand-maintained with nothing checking them: NLOHMANN_JSON_DOUBLE_PASTE (added by hand in #4563 for the *_WITH_NAMES macros) and the 64-slot dispatch table of NLOHMANN_JSON_TYPE_BODY (the #4041 zero-member/one-or-more-member switch). Both tables pass one macro name per slot to the same NLOHMANN_JSON_GET_MACRO dispatch as PASTE, so they can drift out of sync with max_args exactly the way _dp did in the ABI tag list fixed by #5544. Extend main.cpp with build_double_paste_code() (same recursive-doubling shape as build_paste_code(), but DOUBLE_PASTE consumes two arguments per member, so an even slot index falls back to the next lower odd DOUBLE_PASTE<N>) and build_type_body_table() (max_args - 1 MEMBERS slots and one trailing EMPTY slot, 8 per line, matching how it is written by hand today). Add a "type_body" argument that selects the TYPE_BODY block, since it lives at a separate location in macro_scope.hpp from the EXPAND..DOUBLE_PASTE63 block; plain invocation is unchanged apart from covering the extended range. No longer emit the tool's old trailing blank line, so its output is directly diffable without post-processing. Verified with c++ -std=c++11: running the tool (with and without "type_body") and piping the raw output through the pinned astyle reproduces both blocks of the current macro_scope.hpp byte for byte. tests/src/unit-udt_macro.cpp (all NLOHMANN_DEFINE_TYPE_*/_WITH_NAMES/ zero-member variants) passes unchanged under -std=c++11 and -std=c++17 with -fsanitize=address,undefined. Add a "macro_builder_check" Makefile target that builds main.cpp, regenerates both blocks into a scratch directory inside the repository (astyle's --project lookup needs the target files under the same tree as .astylerc, unlike an external /tmp directory), and diffs them against the corresponding ranges of macro_scope.hpp; wire it into check-amalgamation next to the natvis check. Wire the same regeneration into check_amalgamation.yml, splicing the (still unindented) generated blocks back into the PR's own macro_scope.hpp before the existing astyle/amalgamation step runs, so that step's own tree-wide astyle pass both indents them and folds any drift into the amalgamation patch/diff the workflow already produces. Unlike amalgamate.py and generate_natvis.py, this step builds tools/macro_builder/main.cpp from the pull request's own checkout ($MAIN_DIR) rather than a separate checkout of tools/ at develop: this tool has no independent source of truth to regenerate against (its README documents that it must reproduce macro_scope.hpp byte for byte), so a develop-pinned copy would only reproduce the generate_natvis.py trap fixed in a previous commit on this branch, where a PR that teaches the tool to cover more of the file fails its own CI until that PR merges and updates the develop copy. Add tools/macro_builder/README.md documentation for both new tables and the two-invocation usage, and a short pointer comment above NLOHMANN_JSON_TYPE_BODY (the EXPAND pointer already covered the first block; extended its wording to include DOUBLE_PASTE63). Closes #5717 item 5 in full, completing what the documentation-only "Document tools/macro_builder..." commit already on this branch left open (that commit's README/pointer-comment half stands; it also covers item 7). Signed-off-by: Niels Lohmann <mail@nlohmann.me>
172 lines
7.4 KiB
YAML
172 lines
7.4 KiB
YAML
name: "Check amalgamation"
|
|
|
|
on:
|
|
pull_request:
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref || github.run_id }}
|
|
cancel-in-progress: true
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
save:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Harden Runner
|
|
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
|
with:
|
|
egress-policy: audit
|
|
|
|
- name: Save PR number
|
|
run: |
|
|
mkdir -p ./pr
|
|
echo ${{ github.event.number }} > ./pr/number
|
|
echo ${{ github.event.pull_request.user.login }} > ./pr/author
|
|
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
with:
|
|
name: pr
|
|
path: pr/
|
|
|
|
check:
|
|
runs-on: ubuntu-latest
|
|
env:
|
|
MAIN_DIR: ${{ github.workspace }}/main
|
|
INCLUDE_DIR: ${{ github.workspace }}/main/single_include/nlohmann
|
|
TOOL_DIR: ${{ github.workspace }}/tools/tools/amalgamate
|
|
NATVIS_TOOL_DIR: ${{ github.workspace }}/tools/tools/generate_natvis
|
|
|
|
steps:
|
|
- name: Harden Runner
|
|
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
|
with:
|
|
egress-policy: audit
|
|
|
|
- name: Checkout pull request
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
path: main
|
|
ref: ${{ github.event.pull_request.head.sha }}
|
|
persist-credentials: false
|
|
|
|
- name: Checkout tools
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
path: tools
|
|
ref: develop
|
|
persist-credentials: false
|
|
|
|
- name: Install astyle
|
|
run: |
|
|
python3 -mvenv venv
|
|
venv/bin/pip3 install -r $MAIN_DIR/tools/astyle/requirements.txt
|
|
|
|
- name: Install generate_natvis dependencies
|
|
run: pip3 install -r $NATVIS_TOOL_DIR/requirements.txt
|
|
|
|
- name: Regenerate the tools/macro_builder tables in macro_scope.hpp
|
|
run: |
|
|
cd $MAIN_DIR
|
|
|
|
# Built from this PR's own tools/macro_builder/main.cpp, not a
|
|
# develop checkout: unlike amalgamate.py and generate_natvis.py,
|
|
# this tool has no other source of truth to check against (its
|
|
# own README documents that it must reproduce macro_scope.hpp
|
|
# byte for byte), so there is nothing to gain from checking out a
|
|
# separate copy, and doing so would make this step fail on a PR
|
|
# that adds support for a new dispatch table until that PR itself
|
|
# merges to develop, the same way generate_natvis.py's --version
|
|
# requirement briefly did.
|
|
TMPDIR=$(mktemp -d ./macro_builder_check.XXXXXX)
|
|
c++ -std=c++11 tools/macro_builder/main.cpp -o "$TMPDIR/macro_builder"
|
|
"$TMPDIR/macro_builder" > "$TMPDIR/paste.hpp"
|
|
"$TMPDIR/macro_builder" type_body > "$TMPDIR/type_body.hpp"
|
|
|
|
# Splice the (still unindented) generated blocks back into
|
|
# macro_scope.hpp; the astyle pass below indents their
|
|
# continuation lines the same way it does for the rest of
|
|
# include/, so a correctly regenerated file comes out unchanged.
|
|
awk -v newfile="$TMPDIR/paste.hpp" '
|
|
BEGIN { while ((getline line < newfile) > 0) { new = new line "\n" } }
|
|
/^#define NLOHMANN_JSON_EXPAND\( x \) x$/ { printf "%s", new; skip=1 }
|
|
skip && /^#define NLOHMANN_JSON_DOUBLE_PASTE63\(/ { skip=0; next }
|
|
skip { next }
|
|
{ print }
|
|
' include/nlohmann/detail/macro_scope.hpp > "$TMPDIR/macro_scope_1.hpp"
|
|
awk -v newfile="$TMPDIR/type_body.hpp" '
|
|
BEGIN { while ((getline line < newfile) > 0) { new = new line "\n" } }
|
|
/^#define NLOHMANN_JSON_TYPE_BODY\(Prefix, \.\.\.\)/ { printf "%s", new; skip=1 }
|
|
skip && /^[[:space:]]*NLOHMANN_JSON_TYPE_BODY_SENTINEL\)\)$/ { skip=0; next }
|
|
skip { next }
|
|
{ print }
|
|
' "$TMPDIR/macro_scope_1.hpp" > "$TMPDIR/macro_scope_2.hpp"
|
|
mv "$TMPDIR/macro_scope_2.hpp" include/nlohmann/detail/macro_scope.hpp
|
|
rm -rf "$TMPDIR"
|
|
|
|
- name: Regenerate amalgamation, formatting, and BUILD.bazel
|
|
run: |
|
|
cd $MAIN_DIR
|
|
|
|
python3 $TOOL_DIR/amalgamate.py -c $TOOL_DIR/config_json.json -s .
|
|
python3 $TOOL_DIR/amalgamate.py -c $TOOL_DIR/config_json_fwd.json -s .
|
|
|
|
# the header list of the Bazel "json" target must match the files in include/
|
|
cmake -P cmake/scripts/gen_bazel_build_file.cmake
|
|
|
|
${{ github.workspace }}/venv/bin/astyle --project=tools/astyle/.astylerc --suffix=none --quiet \
|
|
$INCLUDE_DIR/json.hpp $INCLUDE_DIR/json_fwd.hpp
|
|
|
|
# fail loudly if a directory is renamed or removed: find would only warn
|
|
# about the missing path and silently drop its files from the check
|
|
SOURCE_DIRS="docs/mkdocs/docs/examples include tests"
|
|
for DIR in $SOURCE_DIRS; do
|
|
if [ ! -d "$DIR" ]; then
|
|
echo "::error::source directory '$DIR' does not exist"
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
${{ github.workspace }}/venv/bin/astyle --project=tools/astyle/.astylerc --suffix=none --quiet \
|
|
$(find $SOURCE_DIRS -type f \( -name '*.hpp' -o -name '*.cpp' -o -name '*.cu' \) -not -path 'tests/thirdparty/*' -not -path 'tests/abi/include/nlohmann/*' | sort)
|
|
|
|
- name: Regenerate nlohmann_json.natvis
|
|
run: |
|
|
cd $MAIN_DIR
|
|
# Pass --version explicitly so this step also works with the tool
|
|
# copy from develop before this repository's own generate_natvis.py
|
|
# learns to derive the version itself: the older script requires
|
|
# --version, and the newer one accepts it as an explicit override.
|
|
ABI_MACROS=include/nlohmann/detail/abi_macros.hpp
|
|
VERSION_MAJOR=$(grep -m1 'define NLOHMANN_JSON_VERSION_MAJOR' $ABI_MACROS | grep -o '[0-9]\+')
|
|
VERSION_MINOR=$(grep -m1 'define NLOHMANN_JSON_VERSION_MINOR' $ABI_MACROS | grep -o '[0-9]\+')
|
|
VERSION_PATCH=$(grep -m1 'define NLOHMANN_JSON_VERSION_PATCH' $ABI_MACROS | grep -o '[0-9]\+')
|
|
python3 $NATVIS_TOOL_DIR/generate_natvis.py --version "$VERSION_MAJOR.$VERSION_MINOR.$VERSION_PATCH" $MAIN_DIR
|
|
|
|
- name: Build patch and check for differences
|
|
id: diff
|
|
run: |
|
|
cd $MAIN_DIR
|
|
mkdir -p ${{ github.workspace }}/patch
|
|
git diff --patch --no-color > ${{ github.workspace }}/patch/amalgamation.patch
|
|
if [ -s ${{ github.workspace }}/patch/amalgamation.patch ]; then
|
|
echo "The source code has not been amalgamated/formatted correctly or BUILD.bazel is out of date. Diff:"
|
|
cat ${{ github.workspace }}/patch/amalgamation.patch
|
|
echo "has_diff=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "has_diff=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
# Uploaded so contributors can fix their PR with `git apply amalgamation.patch`
|
|
# instead of installing the pinned astyle version locally.
|
|
- name: Upload patch
|
|
if: steps.diff.outputs.has_diff == 'true'
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
with:
|
|
name: amalgamation-patch
|
|
path: patch/amalgamation.patch
|
|
|
|
- name: Fail if not amalgamated/formatted
|
|
if: steps.diff.outputs.has_diff == 'true'
|
|
run: exit 1
|