| # Shared extractor for the JSON_HEDLEY_* macro names defined in hedley.hpp. | |
| # | |
| # Every macro that hedley.hpp #defines must be #undef-ed again once json.hpp | |
| # has been fully processed (see include/nlohmann/detail/macro_unscope.hpp | |
| # and https://github.com/nlohmann/json/issues/5408). Deriving the macro list | |
| # straight from hedley.hpp here -- instead of hand-maintaining it in two | |
| # places -- means hedley_undef.hpp and the regression test that checks for | |
| # leaked macros can never drift apart, even after a future `make | |
| # update_hedley` pulls in new macros from upstream Hedley. | |
| # | |
| # MODE=undef (default): write hedley_undef.hpp (SPDX header, #pragma once, | |
| # one #undef per macro name) -- used by `make update_hedley_undef` | |
| # MODE=checks: write one #ifdef/FAIL_CHECK/#endif per macro name, | |
| # meant to be #include-d inside a TEST_CASE -- used by | |
| # tests/CMakeLists.txt to (re)generate the include for | |
| # tests/src/unit-no-macro-leak.cpp | |
| # | |
| # Required variables: | |
| # HEDLEY_HPP path to include/nlohmann/thirdparty/hedley/hedley.hpp | |
| # OUTPUT path of the file to (over)write | |
| # Optional: | |
| # MODE "undef" (default) or "checks" | |
| if(NOT DEFINED HEDLEY_HPP OR NOT DEFINED OUTPUT) | |
| message(FATAL_ERROR "HEDLEY_HPP and OUTPUT must be set") | |
| endif() | |
| if(NOT EXISTS "${HEDLEY_HPP}") | |
| message(FATAL_ERROR "Hedley header not found: ${HEDLEY_HPP}") | |
| endif() | |
| if(NOT DEFINED MODE) | |
| set(MODE undef) | |
| endif() | |
| if(NOT MODE STREQUAL "undef" AND NOT MODE STREQUAL "checks") | |
| message(FATAL_ERROR "MODE must be undef or checks, got: ${MODE}") | |
| endif() | |
| # Line-anchored, like `grep -oE "^[[:blank:]]*#[[:blank:]]*define[[:blank:]]+JSON_HEDLEY_[A-Za-z0-9_]+"`. | |
| # Unanchored matching would also pick up JSON_HEDLEY_* mentions inside | |
| # comments or string literals elsewhere in the file, which must not turn | |
| # into #undef lines. | |
| file(STRINGS "${HEDLEY_HPP}" hedley_lines) | |
| set(macro_names) | |
| foreach(line IN LISTS hedley_lines) | |
| if("${line}" MATCHES "^[ \t]*#[ \t]*define[ \t]+(JSON_HEDLEY_[A-Za-z0-9_]+)") | |
| list(APPEND macro_names "${CMAKE_MATCH_1}") | |
| endif() | |
| endforeach() | |
| if(NOT macro_names) | |
| message(FATAL_ERROR "No JSON_HEDLEY_* macros found in ${HEDLEY_HPP}") | |
| endif() | |
| list(REMOVE_DUPLICATES macro_names) | |
| # Lexicographic, locale-independent (ASCII-only names) -- matches `LC_ALL=C sort`. | |
| list(SORT macro_names COMPARE STRING) | |
| list(LENGTH macro_names macro_count) | |
| set(generated "") | |
| if(MODE STREQUAL "undef") | |
| # Same banner `make update_hedley_undef` would stamp by hand, so the | |
| # recipe is self-contained and its output is byte-stable across reruns. | |
| # The embedded SPDX tags below are part of the *generated* file's | |
| # content, not a REUSE header for this .cmake script itself (which is | |
| # already covered by the blanket path = "**" rule in REUSE.toml) -- keep | |
| # them wrapped in REUSE-IgnoreStart/End so `reuse lint` does not try to | |
| # parse "MIT\n")" as this file's own SPDX-License-Identifier value. | |
| # REUSE-IgnoreStart | |
| string(APPEND generated "// __ _____ _____ _____\n") | |
| string(APPEND generated "// __| | __| | | | JSON for Modern C++\n") | |
| string(APPEND generated "// | | |__ | | | | | | version 3.12.0\n") | |
| string(APPEND generated "// |_____|_____|_____|_|___| https://github.com/nlohmann/json\n") | |
| string(APPEND generated "//\n") | |
| string(APPEND generated "// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>\n") | |
| string(APPEND generated "// SPDX-License-Identifier: MIT\n") | |
| # REUSE-IgnoreEnd | |
| string(APPEND generated "\n") | |
| string(APPEND generated "#pragma once\n") | |
| string(APPEND generated "\n") | |
| foreach(name IN LISTS macro_names) | |
| string(APPEND generated "#undef ${name}\n") | |
| endforeach() | |
| else() | |
| string(APPEND generated "// This file is generated by cmake/scripts/gen_hedley_undef_check.cmake\n") | |
| string(APPEND generated "// from include/nlohmann/thirdparty/hedley/hedley.hpp. Do not edit it by\n") | |
| string(APPEND generated "// hand -- it is regenerated on every build. ${macro_count} macros checked.\n\n") | |
| foreach(name IN LISTS macro_names) | |
| string(APPEND generated "#ifdef ${name}\n") | |
| string(APPEND generated " FAIL_CHECK(\"${name} leaked after including nlohmann/json.hpp\");\n") | |
| string(APPEND generated "#endif\n") | |
| endforeach() | |
| endif() | |
| get_filename_component(output_dir "${OUTPUT}" DIRECTORY) | |
| if(output_dir) | |
| file(MAKE_DIRECTORY "${output_dir}") | |
| endif() | |
| # Avoid rewriting the file (and busting downstream incremental rebuilds) | |
| # when the content has not actually changed. | |
| set(write_output TRUE) | |
| if(EXISTS "${OUTPUT}") | |
| file(READ "${OUTPUT}" existing_content) | |
| if(existing_content STREQUAL generated) | |
| set(write_output FALSE) | |
| endif() | |
| endif() | |
| if(write_output) | |
| file(WRITE "${OUTPUT}" "${generated}") | |
| endif() |