The TRANSFORM action registry held one live action instance per action for
the whole process, and each instance carried per-call state: a raw Selector
pointer, REPLACE's helper, APPEND/PREPEND's operands. That was harmless
while every action ran to completion uninterrupted, but commit c7af6e94d8
(list(TRANSFORM): Add PREDICATE selector, 2026-04-08, v4.4.0-rc1) added a
selector that runs a user function once per element, interleaved with the
transform. User code reentering list(TRANSFORM) with the same action now
rebinds the shared instance mid-flight. That produces silently wrong
results, and a use-after-free once any element is transformed after the
reentering one. It needs no unusual code to hit: a predicate calling
find_package(Python) reaches list(TRANSFORM ... REPLACE) inside FindPython's
own module.
Make action objects immutable and per-call. Operands and the selector become
constructor arguments, Initialize is deleted, and the registry becomes a
constexpr table of metadata with a MakeTransformAction factory. The
InSelection guard, duplicated in all eight actions, moves into the base class.
This also closes a second hole in the same machinery. TransformActionApply
overrode only the vector form of Initialize, so transform(APPLY, "f",
selector) dispatched to the empty two-argument virtual in the base, left
Selector null, and dereferenced it. With no virtual Initialize left to
inherit, an APPLY action without a cmMakefile is no longer constructible, so
the throwing stub that guarded the vector form is no longer needed.
Close a third, from commit 651f82642c (Add APPLY action for list(TRANSFORM),
2026-04-08, v4.4.0-rc1): the cmMakefile overload performs APPLY
unconditionally but validated only the arity of the action passed to it.
APPEND, PREPEND and APPLY all take one argument, so transform(APPEND, "x",
makefile) passed validation and then silently ran APPLY, calling "x" as a
function instead of appending it. Reject any action but APPLY up front.
That path is unreachable from CMake code, since HandleTransformCommand only
selects the overload for APPLY, and Tests/CMakeLib has no cmMakefile to drive
it with, so it carries no test.
Document the predicate's evaluation order while here. It runs once per
element, immediately before that element would be transformed. The manual
did not state the timing, which matters precisely because a predicate that
reenters list(TRANSFORM) observes the outer call mid-flight.
Fixes: #28031
Allow users to provide a custom comparison function for `list(SORT)`.
The comparator is validated for strict weak ordering at runtime to
produce a clear CMake error rather than a platform-dependent abort.
Closes: #27761
Add a new `PREDICATE` selector to `list(TRANSFORM)` that uses a
user-defined function or macro to decide which elements to transform.
The predicate callable receives each element value and an output
variable name. It must set the output variable to a truthy or falsy
value in PARENT_SCOPE; only elements for which the predicate returns
true are passed to the transform action.
Adds a shared PredicateEvaluator helper class used by both TRANSFORM
PREDICATE and (in a subsequent commit) FILTER PREDICATE.
Includes parser wiring, error and success tests covering all existing
actions (TOUPPER, TOLOWER, REPLACE, STRIP, GENEX_STRIP, APPEND,
PREPEND, APPLY) combined with the PREDICATE selector.
Issue: #27761
Add a new APPLY action to list(TRANSFORM) that invokes a user-defined
function or macro for each element of the list, enabling arbitrary
per-element transformations.
The callable receives the current element value and an output variable
name, and must set the output variable in PARENT_SCOPE to the
transformed value.
Includes documentation, release notes, and tests for both function
and macro callables, OUTPUT_VARIABLE, error cases, and selector
combinations (AT, FOR, REGEX).
Refs: #27761
When doing successive matches, track the input start and current search
start positions separately to prevent the `^` anchor from matching in
the middle of the string. Add policy CMP0186 to provide compatibility.
Issue: #26629Fixes: #16899
Convert documentation of the `list` and `set` commands to use new
`signature` directive. Use new `cref` role in the `list` introduction so
that the subcommands there are links rather than just text. Turn
references into `string` subcommands into actual links. Reformat some
prose as definition lists.
This change ony concerns directives that appear in the document body.
The guidelines for inserting version directives:
* Baseline version is CMake 3.0, i.e. directives start at 3.1.
* Always use `.. versionadded::` directive, avoid ad-hoc version
references. Exception: policy pages.
* For new command signatures, put `versionadded` on a separate line
after the signature.
* For a group of new signatures in a new document section,
a single version note at the beginning of the section is sufficient.
* For new options, put `versionadded` on a separate line before
option description.
* If all the option descriptions in the list are short one-liners,
it's fine to put `versionadded` on the same line as the description.
* If multiple option descriptions in close proximity would have
the same ..versionadded directive, consider adding a single
directive after the list, mentioning all added options.
* For compact value lists and sub-option lists, put a single
`versionadded` directive after the list mentioning all additions.
* When a change is described in a single paragraph, put
`versionadded` into that paragraph.
* When only part of the paragraph has changed, separate the changed
part if it doesn't break the flow. Otherwise, write a follow-up
clarification paragraph and apply version directive to that.
* When multiple version directives are close by, order earlier
additions before later additions.
* Indent related lists and code blocks to include them in the scope
of `versionadded` directive.
Issue: #19715
Revise docs for all "Scripting Commands", except four find_XXX
that use a macro suite of their own.
* Take full advantage of the improved syntax highlighting.
* Make consequential use of <..> placeholders.
* Clarify things here and there in the text.
Specific improvements to some command docs:
* "math": Correct description of novel hexadecimal capability.
* "if", "foreach", "while": Provide link to "endif" etc
* "foreach", "while": Mention "break" and "continue".
* "foreach": Simplify explanation of ``RANGE`` and ``IN`` signatures;
advise against negative arguments or reverse ranges (compare issue #18461)
* "endif", "endfunction" etc: Explain that the argument is optional and
maintained for compatibility only
Summarize the command signatures in one block at the top of the
documentation as is typical in Unix command-line tool manuals.
Make the mode keywords links to the corresponding full signature
and documentation.
Issue: #17948
Add notes about macro arguments in the foreach, if, and list commands.
Add a section to the macro command documentation explaining in detail
how macro arguments are not variables.