# 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 "Files: *" rule in .reuse/dep5) -- 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 \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()