Skip to content

Let consumers override the import std gate UUID - #12

Merged
stephenberry merged 1 commit into
mainfrom
import-std-gate-override
Jul 31, 2026
Merged

Let consumers override the import std gate UUID#12
stephenberry merged 1 commit into
mainfrom
import-std-gate-override

Conversation

@stephenberry

@stephenberry stephenberry commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #9.

The problem

#9 replaced the single hardcoded CMAKE_EXPERIMENTAL_CXX_IMPORT_STD value with a table keyed on the running CMake version, which fixed configuring across releases. But it assigned the value with a plain set(), and that creates a normal variable which shadows the cache entry -D produces:

-- BEFORE set:      'USER-VALUE'   cache='USER-VALUE'
-- AFTER plain set: 'TABLE-VALUE'  cache='USER-VALUE'   <- -D silently discarded

So -DCMAKE_EXPERIMENTAL_CXX_IMPORT_STD=... was ignored for every release listed in the table. If a row is ever wrong, there is no escape hatch short of editing CMakeLists.txt, and CMake's own gate-mismatch diagnostic blames the project rather than the stale row.

The change

Skip the assignment when the consumer has put a value in the cache:

if(UT_IMPORT_STD_GATE AND NOT DEFINED CACHE{CMAKE_EXPERIMENTAL_CXX_IMPORT_STD})
  set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "${UT_IMPORT_STD_GATE}")
endif()

Two details in that condition are load-bearing.

Why not assign to the cache. set(... CACHE STRING "") would also restore the override, but a non-FORCE cache write will not update an existing entry, so the UUID gets pinned in CMakeCache.txt for everyone. A consumer who upgrades CMake in an existing build tree then keeps the old value and the table's corrected one never applies:

### 1st configure:                    EFFECTIVE='UUID-FOR-CMAKE-4.3'
### reconfigure after table updates:  EFFECTIVE='UUID-FOR-CMAKE-4.3'   <- stale, silent

That reintroduces the failure the table was added to prevent, in a form harder to diagnose than the original.

Why DEFINED CACHE{...} and not DEFINED. Testing DEFINED also defers to an ordinary variable. When this project is consumed through add_subdirectory() or FetchContent from a parent that hardcodes a single UUID -- the pattern the table replaced, and what this project itself did before #9 -- the parent's value would win on every release and pass its staleness on to us. Testing the cache keeps the table authoritative there while still honouring a deliberate -D.

Diagnostics

The unlisted-release warning now distinguishes three states, since each has a different cause and a different fix:

  • unlisted release, nothing supplied -- unchanged message asking for a new table row
  • empty or false value supplied -- says so, and points at -U. Previously this produced the unlisted-release warning even on a release that is in the table, asking for a row that already exists
  • a value differing from the table -- a STATUS line naming both values. A -D override is cached, so it outlives the command line that introduced it; without this, a stale override is indistinguishable from the table's own choice. Passing the value the table already holds stays quiet

Verified

Against this branch's CMakeLists.txt with CMake 4.4.1, using --trace-expand to confirm which branch executes:

scenario result
no -D table value applies, no cache entry written
-DCMAKE_EXPERIMENTAL_CXX_IMPORT_STD=<uuid> override honoured, STATUS names both values
-D equal to the table value override honoured, no message
-DCMAKE_EXPERIMENTAL_CXX_IMPORT_STD= empty-value warning, not the unlisted-release one
table value bumped, same build tree, no override new value applies -- no staleness
reconfigure without repeating -D override persists
nested under a parent pinning the 4.3 UUID table's 4.4 value applies in this project's scope

Notes

  • The toolchain-file route works unchanged, before and after this commit: a toolchain file is read during project(), after these lines run, so it takes precedence.
  • set(CACHE{VAR} VALUE ...) would be a tidier spelling but needs CMake 4.2, above this project's cmake_minimum_required(VERSION 3.31). Worth revisiting if the floor moves.
  • The tests above exercise CMake variable scoping, which is version-independent. They do not exercise CMake's gate validation -- AppleClang never reaches the import std probe on macOS, so a bogus UUID produces no local error. That coverage comes from the modules CI jobs.

The version-keyed table added in #9 picks the right
CMAKE_EXPERIMENTAL_CXX_IMPORT_STD value for known CMake releases, but it
assigned it with a plain set(). That creates an ordinary variable which
shadows the cache entry `-D` produces, so
`-DCMAKE_EXPERIMENTAL_CXX_IMPORT_STD=...` was silently discarded for every
release listed in the table, leaving no escape hatch when a row is wrong.

Skip the assignment when the consumer has put a value in the cache, so the
command line wins while the table stays authoritative by default.

Guard on the cache entry rather than on DEFINED. Testing DEFINED would also
defer to an ordinary variable, so consuming this project via
add_subdirectory() or FetchContent from a parent that hardcodes a single
UUID -- the pattern the table replaced -- would let the parent's value win
on every release and pass its staleness on to us.

Assigning to the cache here would also restore the override, but it would
pin the UUID in CMakeCache.txt for everyone: upgrading CMake in an existing
build tree would keep using the previous release's value and quietly ignore
the table, which is the failure the table exists to prevent.

Report the gate value actually in effect. The unlisted-release warning
previously fired whenever no value was set, so supplying an empty or false
one on a listed release claimed CMake was newer than every listed release
and asked for a row that already exists; empty and unlisted are now separate
messages naming their real cause. A supplied value differing from the table
gets a STATUS line, since `-D` is cached and outlives the command line that
introduced it, making a stale override otherwise indistinguishable from the
table's own choice.
@stephenberry
stephenberry force-pushed the import-std-gate-override branch from 32a110f to 909d988 Compare July 31, 2026 03:48
@stephenberry
stephenberry merged commit 5f76b8d into main Jul 31, 2026
9 checks passed
@stephenberry
stephenberry deleted the import-std-gate-override branch July 31, 2026 10:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant