cmake_language: Add PRINT_VARIABLES operation

Print CMake variables in human-readable form for debugging.

Issue: #27513
This commit is contained in:
Tom Osika
2026-08-05 14:45:44 -04:00
parent a0d1a037ec
commit a06658b6d7
43 changed files with 576 additions and 0 deletions
+73
View File
@@ -18,6 +18,8 @@ Synopsis
cmake_language(`EXIT`_ <exit-code>)
cmake_language(`TRACE`_ <boolean> ...)
cmake_language(`PRINT_TARGETS`_ <filter>...)
cmake_language(`PRINT_VARIABLES`_
[{ ALL [<filter>...] | NAMED <vars>... }])
Introduction
^^^^^^^^^^^^
@@ -610,3 +612,74 @@ Gives::
Non-imported targets matching REGEX '^(app|util)$' (case sensitive):
app (EXECUTABLE)
util (STATIC_LIBRARY)
Printing Variables
^^^^^^^^^^^^^^^^^^
.. versionadded:: 4.5
.. signature::
cmake_language(PRINT_VARIABLES
[{ ALL [<filter>...] | NAMED <vars>... }])
Prints the values of variables in the current scope. The set of
variables to print may be specified by one of:
``ALL [<filter>...]`` (default)
Enumerates every regular variable in the current scope and every
cache entry, printing one entry per line. Cache entries are annotated
as ``CACHE{<name>}:<TYPE>`` (e.g.
``CACHE{CMAKE_INSTALL_PREFIX}:PATH = "/usr/local"``). If a name
corresponds to both a cache entry and a regular variable, both are printed.
Each ``<filter>`` may be one of:
``NAME_REGEX <name-regex>``
Print only variables whose name matches the given
:ref:`regular expression <Regex Specification>`.
``VALUE_REGEX <value-regex>``
Print only variables whose value matches the given
:ref:`regular expression <Regex Specification>`.
``IGNORE_CASE``
Lower-case both the pattern and the candidate string before matching,
so ``NAME_REGEX`` and ``VALUE_REGEX`` match case-insensitively.
``NAMED <vars>...``
Prints one ``<var> = "<value>"`` entry per line, in the order given. Note
that a regular variable shadows a cache entry of the same name. A
``<var>`` that is not defined prints as ``<var> = <NOTFOUND>``; a variable
set to the empty string is *defined* and prints as ``<var> = ""``.
Printing Variables Examples
"""""""""""""""""""""""""""
Printing a few specific variables:
.. code-block:: cmake
cmake_language(
PRINT_VARIABLES NAMED CMAKE_C_COMPILER CMAKE_MAJOR_VERSION NOT_SET
)
Gives::
-- Printing variables...
Named variables:
CMAKE_C_COMPILER = "/usr/bin/cc"
CMAKE_MAJOR_VERSION = "4"
NOT_SET = <NOTFOUND>
Enumerating user variables and cache entries:
.. code-block:: cmake
set(MY_FLAG "on")
set(MY_PATH "/some/path" CACHE FILEPATH "")
cmake_language(PRINT_VARIABLES ALL NAME_REGEX "^MY_")
Gives::
-- Printing variables...
Variables in scope at '/path/to/CMakeLists.txt' matching name '^MY_' (case sensitive):
MY_FLAG = "on"
CACHE{MY_PATH}:FILEPATH = "/some/path"
+6
View File
@@ -0,0 +1,6 @@
print_variables
---------------
* The :command:`cmake_language(PRINT_VARIABLES)` command was added
to print variables and their values in human-readable form for
debugging.
+267
View File
@@ -29,6 +29,8 @@
#include "cmMessageType.h" // IWYU pragma: keep
#include "cmRange.h"
#include "cmState.h"
#include "cmStateSnapshot.h"
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
@@ -522,6 +524,267 @@ bool cmCMakeLanguageCommandPRINT_TARGETS(
}
return true;
}
struct PrintVariablesArgs : public ArgumentParser::ParseResult
{
bool All = false;
ArgumentParser::NonEmpty<std::vector<std::string>> Named;
cm::optional<std::string> NameRegex;
cm::optional<std::string> ValueRegex;
bool IgnoreCase = false;
// Internal: set by the deprecated cmake_print_variables() module wrapper to
// request the historical flush single-line output (no banner, undefined
// names printed as name=""). Not part of the public interface.
bool CmakePrintVariables = false;
};
// Banner opening a cmake_language(PRINT_VARIABLES) status message. Suppressed
// in the deprecated cmake_print_variables() (legacy) path.
cm::static_string_view const PrintVariablesBanner =
"Printing variables...\n"_s;
// NAMED mode. By default (matching cmake_language(PRINT_PROPERTIES)) this
// emits a " Named variables:" header followed by one `name = "value"` entry
// per line; a name that is not defined prints as `name = <NOTFOUND>` in the
// order given. When `legacy` is set (the deprecated cmake_print_variables()
// wrapper) it instead emits the historical flush single line
// "name=\"value\" ; ..." with no header and undefined names as name="".
// Values go through GetDefinition so users see the same
// in-scope/cache-fallback value they'd get from ${var}.
void PrintVariablesNamed(cmMakefile& makefile,
std::vector<std::string> const& names, bool legacy)
{
if (legacy) {
std::string msg;
bool first = true;
for (std::string const& name : names) {
if (!first) {
msg += " ; ";
}
first = false;
cmValue v = makefile.GetDefinition(name);
msg += cmStrCat(name, "=\"", v ? *v : std::string(), "\"");
}
makefile.DisplayStatus(msg, -1);
return;
}
std::string out = cmStrCat(PrintVariablesBanner, " Named variables:\n");
for (std::string const& name : names) {
cmValue v = makefile.GetDefinition(name);
if (v) {
out += cmStrCat(" ", name, " = \"", *v, "\"\n");
} else {
out += cmStrCat(" ", name, " = <NOTFOUND>\n");
}
}
makefile.DisplayStatus(out, -1);
}
// ALL mode: enumerate every regular variable in scope and
// every cache entry. A name with both a regular variable and a cache
// entry is printed on two distinct lines so the user sees the full
// picture, including the value the cache holds even when a regular
// variable shadows it. Values are read via the snapshot and cache APIs
// directly to avoid firing variable-watch callbacks (which would
// otherwise trip CMP0218 when CMAKE_WARN_DEPRECATED or
// CMAKE_ERROR_DEPRECATED are in scope).
bool PrintVariablesAll(cmMakefile& makefile, PrintVariablesArgs const& parsed,
cmExecutionStatus& status)
{
cm::optional<cmsys::RegularExpression> nameRegex;
cm::optional<cmsys::RegularExpression> valueRegex;
if (parsed.NameRegex) {
cmsys::RegularExpression re;
std::string const pat = parsed.IgnoreCase
? cmSystemTools::LowerCase(*parsed.NameRegex)
: *parsed.NameRegex;
if (!re.compile(pat)) {
return FatalError(status,
cmStrCat("NAME_REGEX regular expression \"",
*parsed.NameRegex, "\" cannot compile."));
}
nameRegex = std::move(re);
}
if (parsed.ValueRegex) {
cmsys::RegularExpression re;
std::string const pat = parsed.IgnoreCase
? cmSystemTools::LowerCase(*parsed.ValueRegex)
: *parsed.ValueRegex;
if (!re.compile(pat)) {
return FatalError(status,
cmStrCat("VALUE_REGEX regular expression \"",
*parsed.ValueRegex, "\" cannot compile."));
}
valueRegex = std::move(re);
}
auto matches = [&](std::string const& name, std::string const& value) {
if (nameRegex) {
std::string const subj =
parsed.IgnoreCase ? cmSystemTools::LowerCase(name) : name;
if (!nameRegex->find(subj)) {
return false;
}
}
if (valueRegex) {
std::string const subj =
parsed.IgnoreCase ? cmSystemTools::LowerCase(value) : value;
if (!valueRegex->find(subj)) {
return false;
}
}
return true;
};
cmStateSnapshot const snapshot = makefile.GetStateSnapshot();
cmState* state = makefile.GetState();
// GetDefinitions() already unions ClosureKeys() with the cache keys and
// sorts the result; just dedupe so a name that lives in both lists isn't
// visited twice.
auto names = makefile.GetDefinitions();
names.erase(std::unique(names.begin(), names.end()), names.end());
// Build the body first so nothing is printed when a regex filters
// everything out; the warning below covers that case.
std::string body;
bool anyMatched = false;
for (std::string const& name : names) {
cmValue regular = snapshot.GetDefinition(name);
if (regular && matches(name, *regular)) {
body += cmStrCat(" ", name, " = \"", *regular, "\"\n");
anyMatched = true;
}
cmValue cached = state->GetInitializedCacheValue(name);
if (cached && matches(name, *cached)) {
auto const type = state->GetCacheEntryType(name);
body += cmStrCat(" CACHE{", name, "}");
if (type != cmStateEnums::UNINITIALIZED) {
body += cmStrCat(":", cmState::CacheEntryTypeToString(type));
}
body += cmStrCat(" = \"", *cached, "\"\n");
anyMatched = true;
}
}
if (anyMatched) {
cmValue listFile = snapshot.GetDefinition("CMAKE_CURRENT_LIST_FILE");
std::string out =
cmStrCat(PrintVariablesBanner, " Variables in scope at '",
listFile ? *listFile : std::string("<unknown>"), "'");
if (parsed.NameRegex || parsed.ValueRegex) {
out += " matching";
if (parsed.NameRegex) {
out += cmStrCat(" name '", *parsed.NameRegex, "'");
}
if (parsed.NameRegex && parsed.ValueRegex) {
out += " and";
}
if (parsed.ValueRegex) {
out += cmStrCat(" value '", *parsed.ValueRegex, "'");
}
out += parsed.IgnoreCase ? " (case insensitive)" : " (case sensitive)";
}
out += cmStrCat(":\n", body);
makefile.DisplayStatus(out, -1);
}
if (!anyMatched && (parsed.NameRegex || parsed.ValueRegex)) {
std::string msg = "No variables in scope matching";
if (parsed.NameRegex) {
msg += cmStrCat(" name '", *parsed.NameRegex, "'");
}
if (parsed.NameRegex && parsed.ValueRegex) {
msg += " and";
}
if (parsed.ValueRegex) {
msg += cmStrCat(" value '", *parsed.ValueRegex, "'");
}
msg += parsed.IgnoreCase ? " (case insensitive)" : " (case sensitive)";
msg += " in cmake_language(PRINT_VARIABLES ...).";
makefile.IssueMessage(MessageType::WARNING, msg);
}
return true;
}
bool cmCMakeLanguageCommandPRINT_VARIABLES(
std::vector<cmListFileArgument> const& args, cmExecutionStatus& status)
{
cmMakefile& makefile = status.GetMakefile();
std::vector<std::string> expandedArgs;
makefile.ExpandArguments(args, expandedArgs);
// Drop the leading "PRINT_VARIABLES" subcommand keyword.
std::vector<std::string> body(expandedArgs.begin() + 1, expandedArgs.end());
auto const ArgsParser =
cmArgumentParser<PrintVariablesArgs>()
.Bind("ALL"_s, &PrintVariablesArgs::All)
.Bind("NAMED"_s, &PrintVariablesArgs::Named)
.Bind("NAME_REGEX"_s, &PrintVariablesArgs::NameRegex)
.Bind("VALUE_REGEX"_s, &PrintVariablesArgs::ValueRegex)
.Bind("IGNORE_CASE"_s, &PrintVariablesArgs::IgnoreCase)
.Bind("__CMAKE_PRINT_VARIABLES"_s,
&PrintVariablesArgs::CmakePrintVariables);
std::vector<std::string> unparsed;
auto parsedArgs = ArgsParser.Parse(body, &unparsed);
// No bareword form: every token must belong to ALL, NAMED, or a filter.
if (!unparsed.empty()) {
return FatalError(
status,
cmStrCat("Unknown argument(s) given to cmake_language(PRINT_VARIABLES)"
": \"",
cmJoin(unparsed, "\" \""), "\"."));
}
if (parsedArgs.MaybeReportError(makefile)) {
cmSystemTools::SetFatalErrorOccurred();
return true;
}
bool const hasNamed = !parsedArgs.Named.empty();
bool const hasFilters =
parsedArgs.NameRegex || parsedArgs.ValueRegex || parsedArgs.IgnoreCase;
// ALL and NAMED are mutually exclusive modes.
if (parsedArgs.All && hasNamed) {
return FatalError(status,
"ALL and NAMED keywords in "
"cmake_language(PRINT_VARIABLES) call "
"are mutually exclusive.");
}
// The filter keywords narrow an enumeration, so they only make sense with
// ALL (explicit or implicit), never with NAMED.
if (hasNamed && hasFilters) {
return FatalError(status,
"NAME_REGEX, VALUE_REGEX, and IGNORE_CASE in "
"cmake_language(PRINT_VARIABLES) call "
"are only valid with ALL, not NAMED.");
}
// __CMAKE_PRINT_VARIABLES selects the legacy single-line NAMED output; it is
// meaningless when enumerating variables (ALL, explicit or implicit).
if (!hasNamed && parsedArgs.CmakePrintVariables) {
return FatalError(status,
"__CMAKE_PRINT_VARIABLES in "
"cmake_language(PRINT_VARIABLES) call is only valid "
"with NAMED.");
}
// Default to ALL when neither mode keyword is given.
bool const all = parsedArgs.All || !hasNamed;
if (all) {
return PrintVariablesAll(makefile, parsedArgs, status);
}
PrintVariablesNamed(makefile, parsedArgs.Named,
parsedArgs.CmakePrintVariables);
return true;
}
}
bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args,
@@ -705,6 +968,10 @@ bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args,
return cmCMakeLanguageCommandPRINT_TARGETS(args, status);
}
if (expArgs[expArg] == "PRINT_VARIABLES") {
return cmCMakeLanguageCommandPRINT_VARIABLES(args, status);
}
if (expArgs[expArg] == "TRACE") {
++expArg; // Consume "TRACE".
@@ -0,0 +1,16 @@
-- Printing variables\.\.\.
Variables in scope at '.*PrintVariablesAll\.cmake' matching name '\^MY_' \(case sensitive\):
MY_BAR = "beta"
MY_BAZ = "alpha-too"
MY_FOO = "alpha"
-- Printing variables\.\.\.
Variables in scope at '.*PrintVariablesAll\.cmake' matching value '\^alpha' \(case sensitive\):
MY_BAZ = "alpha-too"
MY_FOO = "alpha"
OTHER_ALPHA = "alpha-other"
-- Printing variables\.\.\.
Variables in scope at '.*PrintVariablesAll\.cmake' matching name '\^MY_' and value '\^alpha' \(case sensitive\):
MY_BAZ = "alpha-too"
MY_FOO = "alpha"
@@ -0,0 +1,15 @@
set(MY_FOO "alpha")
set(MY_BAR "beta")
set(MY_BAZ "alpha-too")
set(OTHER_FOO "gamma")
set(OTHER_ALPHA "alpha-other")
# NAME_REGEX alone.
cmake_language(PRINT_VARIABLES ALL NAME_REGEX "^MY_")
# VALUE_REGEX alone.
cmake_language(PRINT_VARIABLES ALL VALUE_REGEX "^alpha")
# Both together.
cmake_language(PRINT_VARIABLES ALL
NAME_REGEX "^MY_" VALUE_REGEX "^alpha")
@@ -0,0 +1,3 @@
^CMake Error at PrintVariablesAllAndNamed\.cmake:[0-9]+ \(cmake_language\):
cmake_language ALL and NAMED keywords in cmake_language\(PRINT_VARIABLES\)
call are mutually exclusive\.
@@ -0,0 +1,2 @@
# ALL and NAMED are mutually exclusive.
cmake_language(PRINT_VARIABLES ALL NAMED MY_VAR)
@@ -0,0 +1,7 @@
-- Printing variables\.\.\.
+Variables in scope at '.*PrintVariablesCacheAnnotation\.cmake'
+matching NAME_REGEX '\^\(typed_cache|uninit_cache|shadowed\)\$' \(case sensitive\):
+shadowed = "regular_val"
+CACHE{shadowed}:STRING = "cache_val"
+CACHE{typed_cache}:FILEPATH = "/filepath/in/cache"
+CACHE{uninit_cache} = "raw_value"
@@ -0,0 +1,15 @@
# `typed_cache` exercises the `CACHE{name}:TYPE` annotation.
set(typed_cache "/filepath/in/cache" CACHE FILEPATH "")
# `uninit_cache` is injected via -D on the cmake command line in the
# harness (see RunCMakeTest.cmake), which produces an UNINITIALIZED cache
# entry. We assert that the `:TYPE` suffix is suppressed for those.
# `shadowed` exists both as a regular variable AND a cache entry; we
# expect two distinct lines
set(shadowed "cache_val" CACHE STRING "" FORCE)
set(shadowed "regular_val")
cmake_language(PRINT_VARIABLES ALL
NAME_REGEX "^(typed_cache|uninit_cache|shadowed)$"
)
@@ -0,0 +1,10 @@
CMake Warning at PrintVariablesEmptyMatch\.cmake:[0-9]+ \(cmake_language\):
No variables in scope matching name 'ZZZ_NEVER_MATCHES_ANY_NAME' \(case
sensitive\) in cmake_language\(PRINT_VARIABLES \.\.\.\)\.
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
CMake Warning at PrintVariablesEmptyMatch\.cmake:[0-9]+ \(cmake_language\):
No variables in scope matching value 'ZZZ_NEVER_MATCHES_ANY_VALUE' \(case
sensitive\) in cmake_language\(PRINT_VARIABLES \.\.\.\)\.
@@ -0,0 +1,2 @@
cmake_language(PRINT_VARIABLES ALL NAME_REGEX "ZZZ_NEVER_MATCHES_ANY_NAME")
cmake_language(PRINT_VARIABLES ALL VALUE_REGEX "ZZZ_NEVER_MATCHES_ANY_VALUE")
@@ -0,0 +1,17 @@
-- Printing variables\.\.\.
Variables in scope at '.*PrintVariablesIgnoreCase\.cmake' matching name '\^my_' \(case sensitive\):
my_lower = "abc"
-- Printing variables\.\.\.
Variables in scope at '.*PrintVariablesIgnoreCase\.cmake' matching name '\^my_' \(case insensitive\):
MY_UPPER = "ABC"
my_lower = "abc"
-- Printing variables\.\.\.
Variables in scope at '.*PrintVariablesIgnoreCase\.cmake' matching value '\^abc' \(case sensitive\):
my_lower = "abc"
-- Printing variables\.\.\.
Variables in scope at '.*PrintVariablesIgnoreCase\.cmake' matching value '\^abc' \(case insensitive\):
MY_UPPER = "ABC"
my_lower = "abc"
@@ -0,0 +1,14 @@
set(my_lower "abc")
set(MY_UPPER "ABC")
# Case-sensitive NAME_REGEX: only my_lower matches.
cmake_language(PRINT_VARIABLES ALL NAME_REGEX "^my_")
# IGNORE_CASE NAME_REGEX: both names lower-case to start with "my_".
cmake_language(PRINT_VARIABLES ALL NAME_REGEX "^my_" IGNORE_CASE)
# Case-sensitive VALUE_REGEX: only my_lower's value matches.
cmake_language(PRINT_VARIABLES ALL VALUE_REGEX "^abc")
# IGNORE_CASE VALUE_REGEX: both values lower-case to "abc".
cmake_language(PRINT_VARIABLES ALL VALUE_REGEX "^abc" IGNORE_CASE)
@@ -0,0 +1,3 @@
-- Printing variables\.\.\.
+Variables in scope at '.*PrintVariablesImplicitAll\.cmake':
.* +zz_implicit_marker = "present"
@@ -0,0 +1,4 @@
set(zz_implicit_marker "present")
# No ALL and no NAMED -> defaults to ALL.
cmake_language(PRINT_VARIABLES)
@@ -0,0 +1,3 @@
^CMake Error at PrintVariablesLegacyFlagRequiresNamed\.cmake:[0-9]+ \(cmake_language\):
cmake_language __CMAKE_PRINT_VARIABLES in cmake_language\(PRINT_VARIABLES\)
call is only valid with NAMED\.
@@ -0,0 +1,3 @@
# __CMAKE_PRINT_VARIABLES selects the legacy NAMED output, so it is only valid
# with NAMED; here no mode keyword is given (implicit ALL), which rejects it.
cmake_language(PRINT_VARIABLES __CMAKE_PRINT_VARIABLES)
@@ -0,0 +1,2 @@
CMake Error at PrintVariablesNameRegexError\.cmake:[0-9]+ \(cmake_language\):
cmake_language NAME_REGEX regular expression "\[" cannot compile\.
@@ -0,0 +1 @@
cmake_language(PRINT_VARIABLES ALL NAME_REGEX "[")
@@ -0,0 +1,5 @@
-- Printing variables\.\.\.
Named variables:
source_dir = "src"
binary_dir = "build"
cache_var = "cached"
@@ -0,0 +1,4 @@
set(source_dir "src")
set(binary_dir "build")
set(cache_var "cached" CACHE STRING "")
cmake_language(PRINT_VARIABLES NAMED source_dir binary_dir cache_var)
@@ -0,0 +1,12 @@
-- Printing variables\.\.\.
Named variables:
source_dir = "src"
binary_dir = "build"
NOT_SET = <NOTFOUND>
-- Printing variables\.\.\.
Named variables:
source_dir = "src"
NOT_SET = <NOTFOUND>
binary_dir = "build"
ALSO_NOT_SET = <NOTFOUND>
@@ -0,0 +1,8 @@
set(source_dir "src")
set(binary_dir "build")
# One undefined name -> printed inline as <NOTFOUND>.
cmake_language(PRINT_VARIABLES NAMED source_dir binary_dir NOT_SET)
# Multiple undefined names -> each printed as <NOTFOUND> in the order given.
cmake_language(PRINT_VARIABLES NAMED source_dir NOT_SET binary_dir ALSO_NOT_SET)
@@ -0,0 +1,3 @@
CMake Error at PrintVariablesNamedWithFilter\.cmake:[0-9]+ \(cmake_language\):
cmake_language NAME_REGEX, VALUE_REGEX, and IGNORE_CASE in
cmake_language\(PRINT_VARIABLES\) call are only valid with ALL, not NAMED\.
@@ -0,0 +1 @@
cmake_language(PRINT_VARIABLES NAMED foo NAME_REGEX "bar")
@@ -0,0 +1,3 @@
CMake Error at PrintVariablesNamedWithIgnoreCase\.cmake:[0-9]+ \(cmake_language\):
cmake_language NAME_REGEX, VALUE_REGEX, and IGNORE_CASE in
cmake_language\(PRINT_VARIABLES\) call are only valid with ALL, not NAMED\.
@@ -0,0 +1 @@
cmake_language(PRINT_VARIABLES NAMED foo IGNORE_CASE)
@@ -0,0 +1,3 @@
-- Printing variables\.\.\.
Variables in scope at '.*PrintVariablesNoWatch\.cmake' matching name '\^watched\$' \(case sensitive\):
watched = "value"
@@ -0,0 +1,9 @@
# Enumerating ALL reads values via the snapshot API, not makefile.GetDefinition,
# so it must not fire variable_watch callbacks. If the watch fires during the
# walk, the test fails.
function(watch_fired)
message(FATAL_ERROR "variable_watch fired during PRINT_VARIABLES enumeration")
endfunction()
set(watched "value")
variable_watch(watched watch_fired)
cmake_language(PRINT_VARIABLES ALL NAME_REGEX "^watched$")
@@ -0,0 +1,11 @@
-- Printing variables\.\.\.
+Variables in scope at '.*PrintVariablesScope/CMakeLists\.txt'
+matching NAME_REGEX '\^\(parent_|child_\)' \(case sensitive\):
+child_local = "c_val"
+CACHE{parent_cache}:STRING = "p_cache_val"
+parent_regular = "p_val"
-- Printing variables\.\.\.
+Variables in scope at '.*PrintVariablesScope\.cmake'
+matching NAME_REGEX '\^\(parent_|child_\)' \(case sensitive\):
+CACHE{parent_cache}:STRING = "p_cache_val"
+parent_regular = "p_val"
@@ -0,0 +1,9 @@
set(parent_regular "p_val")
set(parent_cache "p_cache_val" CACHE STRING "")
add_subdirectory(PrintVariablesScope)
# Back in the parent scope: the child set `child_local` as a regular
# variable; it must NOT be visible here.
cmake_language(PRINT_VARIABLES ALL
NAME_REGEX "^(parent_|child_)")
@@ -0,0 +1,6 @@
set(child_local "c_val")
# Inside the subdir: parent's regular variable and the cache entry are
# both visible. `child_local` is too because we just defined it here.
cmake_language(PRINT_VARIABLES ALL
NAME_REGEX "^(parent_|child_)")
@@ -0,0 +1,3 @@
-- Printing variables\.\.\.
+Variables in scope at '.*PrintVariablesUnfiltered\.cmake':
.* +zz_unfiltered_marker = "present"
@@ -0,0 +1,3 @@
set(zz_unfiltered_marker "present")
cmake_language(PRINT_VARIABLES ALL)
@@ -0,0 +1,2 @@
CMake Error at PrintVariablesValueRegexError\.cmake:[0-9]+ \(cmake_language\):
cmake_language VALUE_REGEX regular expression "\[" cannot compile\.
@@ -0,0 +1 @@
cmake_language(PRINT_VARIABLES ALL VALUE_REGEX "[")
@@ -197,3 +197,26 @@ run_cmake(PrintTargetsRegexError)
run_cmake(PrintTargetsNoRegex)
run_cmake(PrintTargetsIgnoreCase)
run_cmake(PrintTargetsIgnoreCaseRequiresRegex)
# cmake_language(PRINT_VARIABLES)
run_cmake(PrintVariablesAll)
block()
set(RunCMake_TEST_NOT_EXPECT_stdout "matching")
run_cmake(PrintVariablesUnfiltered)
run_cmake(PrintVariablesImplicitAll)
endblock()
block()
set(RunCMake_TEST_OPTIONS -Duninit_cache=raw_value -Wno-unused-cli)
run_cmake(PrintVariablesCacheAnnotation)
endblock()
run_cmake(PrintVariablesIgnoreCase)
run_cmake(PrintVariablesScope)
run_cmake(PrintVariablesNamed)
run_cmake(PrintVariablesNamedUndefined)
run_cmake(PrintVariablesLegacyFlagRequiresNamed)
run_cmake(PrintVariablesNoWatch)
run_cmake(PrintVariablesEmptyMatch)
run_cmake(PrintVariablesAllAndNamed)
run_cmake(PrintVariablesNamedWithFilter)
run_cmake(PrintVariablesNamedWithIgnoreCase)
run_cmake(PrintVariablesNameRegexError)
run_cmake(PrintVariablesValueRegexError)