cmake_path(IS_PREFIX) and $<PATH:IS_PREFIX> treated an empty path as a
prefix of every path, including another empty path, following
std::filesystem::path. A prefix that is empty because a variable was
set to an empty value, or because a generator expression argument
expanded to nothing, therefore satisfied a check meant to reject it.
Return false for an empty prefix, in cmCMakePath::IsPrefix so that every
caller shares one implementation and both the plain and NORMALIZE forms
are covered. Normalizing an empty path leaves it empty, so no separate
handling of NORMALIZE is needed. Unlike the component comparison, which
follows std::filesystem::path deliberately, IsPrefix has no counterpart
in the standard: it borrows path iteration but the predicate itself is
defined by CMake, so an empty prefix is a gap to fill rather than a
standard answer to override.
Add policy CMP0223 and restore the old result behind it at the two
released surfaces. The other callers of IsPrefix, source_group() and
the Makefile generator's source classification, take the new behavior
ungated: source_group() rejects an empty TREE argument before reaching
it, and the generator passes the source and binary directories.
The if(PATH_IS_PREFIX) operator, new in this same release, follows the
policy too rather than simply taking the new behavior, so that it agrees
with cmake_path(IS_PREFIX) in every policy state and the parity
assertions in its test hold unconditionally.
Fixes: #28077
Testing whether one path is a prefix of another is possible today with
cmake_path(IS_PREFIX), but the idiom needs a separate statement plus a
scratch variable and takes the prefix as a variable name, so projects
reach for if(path MATCHES "^${prefix}") instead. That is wrong whenever
the prefix contains a regex metacharacter, and it accepts siblings,
because '^/a/b' matches '/a/bc'.
Add a binary operator where the left operand is the candidate prefix and
the right is the path, matching the operand order of cmake_path(IS_PREFIX)
and $<PATH:IS_PREFIX> so that the same operation reads the same way on all
three surfaces. Neither operand is normalized, matching the default of
cmake_path(IS_PREFIX) and the existing PATH_EQUAL operator, so '.' and
'..' are compared as ordinary components. The test is non-strict, purely
lexical, and applies no relative-to-absolute reconciliation.
Add policy CMP0222 for compatibility, modeled on CMP0139. The keyword
is consumed as an operator only when it appears in the second argument
slot, so a variable named PATH_IS_PREFIX keeps working in unary and
left-operand position. What the policy covers is such a variable
appearing after another token, as in if(NOT PATH_IS_PREFIX AND other),
which becomes a configure error under NEW.
Since the operator is an if() spelling of cmake_path(IS_PREFIX) and shares
its implementation, test it by asserting the two agree over a corpus of
inputs rather than by restating expected values. Those are pinned by the
cmake_path(IS_PREFIX) test, so the operator's tests stay limited to what
has no command equivalent, and no platform branching is needed because
parity holds whatever the host path model answers.
Fixes: #28040
Add an existence check to the `if` command for diagnostic categories,
mirroring the check for policies. Aside from being desirable for
consistency's sake, this will make it easier for users to write logic to
manipulate diagnostics from newer versions of CMake that don't exist
today.
Consolidate the description of precedence during evaluation. Use xrefs
to improve syntax highlighting. Remove an outdated `versionadded`
directive for CMake 2.6.
Using `signature` renders the anchor links for each sub-command, and is
consistent with the other `Help/command` pages which contain multiple
sub-commands.
This was added in 2.6.0 by commit c1b3484c2d (ENH: store the matches for
paren-delimited subexpression..., 2007-08-21, v2.6.0~1227), not in 3.9.
Only the documentation at this place was added in 3.9, by commit
eb08e1febb (Help: Document CMAKE_MATCH_<n> variables, 2017-04-18,
v3.9.0-rc1~257^2)
Previously this behavior was only mentioned implicitly by the command
signature. Describe it explicitly as we do for other conditions that
automatically expand variables.
Fixes: #26234
Document and add explicit tests for empty string input:
`if(EXISTS "")` and `if(IS_DIRECTORY "")` are always false.
This avoids need for users to do extra checks due to
CMake non-short-circuit logic as below:
if("${p}")
if(EXISTS "${p}")
The docs for if(PATH_EQUAL) did not mention the component-wise
nature of the checks. It also claimed no normalization was
performed, but multiple separators are effectively collapsed
(part of normalization). Improve the wording to clarify both of
these points.
Also update the corresponding description of cmake_path(COMPARE),
which had the same inaccuracy.
Fixes: #23758
The wording update in commit b74819e4fe (Help: Format 'if' command
documentation, 2013-12-18, v3.0.0-rc1~227^2~1) incorrectly implied that
`AND` has higher precedence than `OR`. Although this is common in many
languages, it has never been true in CMake's implementation. Revise
the wording to clarify the precedence.
Add a test case demonstrating the order.
Fixes: #23207
The meaning of "absolute path" was previously assumed knowledge,
but a number of special cases were left unspecified. The way some of
these are handled differs to the way that cmake_path(IS_ABSOLUTE)
works, so document those special cases so that the differing behavior
between these two commands is clearly defined.
`.. versionchanged` directive might be more appropriate when
documentation refers to previous CMake version, old behavior
or a policy, and there's no new parameter or a variable involved.
Issue: #19715
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
In CMake 3.13.x, we had this evaluation for if() conditions:
if(a) elseif(b) else(a) endif(a)
The sensible intention of the change in commit c2efb3efcd (Help: Revise
docs on Scripting Commands, 2018-10-16, v3.14.0-rc1~505^2) was:
> "endif", "endfunction" etc: Explain that the argument is optional and
> maintained for compatibility only
Instead of "endif", it ended up being written to the documentation as
"elseif" by the commit author (oops) to if()'s page.
if(a) elseif(a!?) else() endif(a?)
Truthfully, endif()'s parameter should be an optional verbatim repeat
and not elseif()'s. If it wasn't, elseif() would be described to be the
same as if(). The rightful intended description is:
if(a) elseif(b) else() endif()
Fix that typo.