cmFindBase: Create find-v1 configure log events

Record `find_` command events in the configure log, except
`find_package` as it is far more complicated (and will have its own
event kind).

Note that testing only generates the events of interest, there is no
verification. Also note that testing that the "found" to "notfound"
transition causes an event is not testable because a truthy value in the
variable skips any kind of verification or other logic beyond
normalization.

Co-Authored-by: Ryan Krattiger <ryan.krattiger@kitware.com>
See: #24833
This commit is contained in:
Ben Boeckel
2025-04-04 15:16:56 +02:00
parent 58b5d41a4f
commit a3f273b657
14 changed files with 457 additions and 15 deletions

View File

@@ -334,3 +334,110 @@ documented by the `try_compile-v1 event`_, plus:
An optional key that is present when the test project built successfully.
Its value is an integer specifying the exit code, or a string containing
an error message, from trying to run the test executable.
.. _`find configure-log event`:
Event Kind ``find``
-------------------
The :command:`find_file`, :command:`find_path`, :command:`find_library`, and
:command:`find_program` commands log ``find`` events.
There is only one ``find`` event major version, version 1.
.. _`find-v1 event`:
``find-v1`` Event
^^^^^^^^^^^^^^^^^
.. versionadded:: 4.1
A ``find-v1`` event is a YAML mapping:
.. code-block:: yaml
kind: "find-v1"
backtrace:
- "CMakeLists.txt:456 (find_program)"
mode: "program"
variable: "PROGRAM_PATH"
description: "Docstring for variable"
settings:
SearchFramework: "NEVER"
SearchAppBundle: "NEVER"
CMAKE_FIND_USE_CMAKE_PATH: true
CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH: true
CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH: true
CMAKE_FIND_USE_CMAKE_SYSTEM_PATH: true
CMAKE_FIND_USE_INSTALL_PREFIX: true
names:
- "name1"
- "name2"
candidate_directories:
- "/path/to/search"
- "/other/path/to/search"
- "/path/to/found"
- "/further/path/to/search"
searched_directories:
- "/path/to/search"
- "/other/path/to/search"
found: "/path/to/found/program"
The keys specific to ``find-v1`` mappings are:
``mode``
A string describing the command using the search performed. One of ``file``,
``path``, ``program``, or ``library``.
``variable``
The variable to which the search stored its result.
``description``
The documentation string of the variable.
``settings``
Search settings active for the search.
``SearchFramework``
A string describing how framework search is performed. One of ``FIRST``,
``LAST``, ``ONLY``, or ``NEVER``. See :variable:`CMAKE_FIND_FRAMEWORK`.
``SearchAppBundle``
A string describing how application bundle search is performed. One of
``FIRST``, ``LAST``, ``ONLY``, or ``NEVER``. See
:variable:`CMAKE_FIND_APPBUNDLE`.
``CMAKE_FIND_USE_CMAKE_PATH``
A boolean indicating whether or not CMake-specific cache variables are
used when searching. See :variable:`CMAKE_FIND_USE_CMAKE_PATH`.
``CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH``
A boolean indicating whether or not CMake-specific environment variables
are used when searching. See
:variable:`CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH`.
``CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH``
A boolean indicating whether or not platform-specific environment
variables are used when searching. See
:variable:`CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH`.
``CMAKE_FIND_USE_CMAKE_SYSTEM_PATH``
A boolean indicating whether or not platform-specific CMake variables are
used when searching. See :variable:`CMAKE_FIND_USE_CMAKE_SYSTEM_PATH`.
``CMAKE_FIND_USE_INSTALL_PREFIX``
A boolean indicating whether or not the install prefix is used when
searching. See :variable:`CMAKE_FIND_USE_INSTALL_PREFIX`.
``names``
The names to look for the queries.
``candidate_directories``
Candidate directories, in order, to look in during the search.
``searched_directories``
Directories, in order, looked at during the search process.
``found``
Either a string representing the found value or ``false`` if it was not
found.

View File

@@ -0,0 +1,7 @@
configure-log-find-v1
---------------------
* The :ref:`find configure-log event` ``find-v1`` has been added to
:manual:`cmake-configure-log(7)` to track calls to the :command:`find_file`,
:command:`find_path`, :command:`find_library`, and :command:`find_program`
commands.

View File

@@ -55,6 +55,7 @@ Json::Value ConfigureLog::DumpEventKindNames()
eventKindNames.append("message-v1"); // WriteMessageEvent
eventKindNames.append("try_compile-v1"); // WriteTryCompileEvent
eventKindNames.append("try_run-v1"); // WriteTryRunEvent
eventKindNames.append("find-v1"); // WriteFindBaseEvent
}
return eventKindNames;
}

View File

@@ -14,6 +14,7 @@
#include <cmext/string_view>
#include "cmCMakePath.h"
#include "cmConfigureLog.h"
#include "cmExecutionStatus.h"
#include "cmList.h"
#include "cmListFileCache.h"
@@ -642,6 +643,24 @@ cmFindBaseDebugState::cmFindBaseDebugState(std::string commandName,
cmFindBaseDebugState::~cmFindBaseDebugState()
{
bool found = !this->FoundSearchLocation.path.empty();
#ifndef CMAKE_BOOTSTRAP
// Write find event to the configure log if the log exists
if (cmConfigureLog* log =
this->FindCommand->Makefile->GetCMakeInstance()->GetConfigureLog()) {
// Write event if any of:
// - debug mode is enabled
// - the variable was not defined (first run)
// - the variable found state does not match the new found state (state
// transition)
if (this->FindCommand->DebugMode || !this->FindCommand->IsDefined() ||
this->FindCommand->IsFound() != found) {
this->WriteFindEvent(*log, *this->FindCommand->Makefile);
}
}
#endif
if (!this->FindCommand->DebugMode) {
return;
}
@@ -690,7 +709,7 @@ cmFindBaseDebugState::~cmFindBaseDebugState()
buffer += cmStrCat(path, '\n');
}
if (!this->FoundSearchLocation.path.empty()) {
if (found) {
buffer += cmStrCat("The item was found at\n ",
this->FoundSearchLocation.path, '\n');
} else {
@@ -703,7 +722,7 @@ cmFindBaseDebugState::~cmFindBaseDebugState()
void cmFindBaseDebugState::FoundAt(std::string const& path,
std::string regexName)
{
if (this->FindCommand->DebugMode) {
if (this->TrackSearchProgress()) {
this->FoundSearchLocation = DebugLibState{ std::move(regexName), path };
}
}
@@ -711,7 +730,74 @@ void cmFindBaseDebugState::FoundAt(std::string const& path,
void cmFindBaseDebugState::FailedAt(std::string const& path,
std::string regexName)
{
if (this->FindCommand->DebugMode) {
if (this->TrackSearchProgress()) {
this->FailedSearchLocations.emplace_back(std::move(regexName), path);
}
}
#ifndef CMAKE_BOOTSTRAP
void cmFindBaseDebugState::WriteFindEvent(cmConfigureLog& log,
cmMakefile const& mf) const
{
log.BeginEvent("find-v1", mf);
// Mode is the Command name without the "find_" prefix
log.WriteValue("mode"_s, this->CommandName.substr(5));
log.WriteValue("variable"_s, this->FindCommand->VariableName);
log.WriteValue("description"_s, this->FindCommand->VariableDocumentation);
// Yes, this needs to return a `std::string`. If it returns a `const char*`,
// the `WriteValue` method prefers the `bool` overload. There's no overload
// for a `cm::string_view` because the underlying JSON library doesn't
// support `string_view` arguments itself.
auto search_opt_to_str = [](bool first, bool last,
bool only) -> std::string {
return first ? "FIRST" : (last ? "LAST" : (only ? "ONLY" : "NEVER"));
};
log.BeginObject("settings"_s);
log.WriteValue("SearchFramework"_s,
search_opt_to_str(this->FindCommand->SearchFrameworkFirst,
this->FindCommand->SearchFrameworkLast,
this->FindCommand->SearchFrameworkOnly));
log.WriteValue("SearchAppBundle"_s,
search_opt_to_str(this->FindCommand->SearchAppBundleFirst,
this->FindCommand->SearchAppBundleLast,
this->FindCommand->SearchAppBundleOnly));
log.WriteValue("CMAKE_FIND_USE_CMAKE_PATH"_s,
!this->FindCommand->NoCMakePath);
log.WriteValue("CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH"_s,
!this->FindCommand->NoCMakeEnvironmentPath);
log.WriteValue("CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH"_s,
!this->FindCommand->NoSystemEnvironmentPath);
log.WriteValue("CMAKE_FIND_USE_CMAKE_SYSTEM_PATH"_s,
!this->FindCommand->NoCMakeSystemPath);
log.WriteValue("CMAKE_FIND_USE_INSTALL_PREFIX"_s,
!this->FindCommand->NoCMakeInstallPath);
log.EndObject();
log.WriteValue("names"_s, this->FindCommand->Names);
std::vector<std::string> directories;
directories.reserve(this->FailedSearchLocations.size());
for (auto const& location : this->FailedSearchLocations) {
directories.push_back(location.path);
}
log.WriteValue("candidate_directories"_s, this->FindCommand->SearchPaths);
log.WriteValue("searched_directories"_s, directories);
if (!this->FoundSearchLocation.path.empty()) {
log.WriteValue("found"_s, this->FoundSearchLocation.path);
} else {
log.WriteValue("found"_s, false);
}
log.EndEvent();
}
#endif
bool cmFindBaseDebugState::TrackSearchProgress() const
{
// Track search progress if debugging or logging the configure.
return this->FindCommand->DebugMode
#ifndef CMAKE_BOOTSTRAP
|| this->FindCommand->Makefile->GetCMakeInstance()->GetConfigureLog()
#endif
;
}

View File

@@ -11,7 +11,9 @@
#include "cmFindCommon.h"
#include "cmStateTypes.h"
class cmConfigureLog;
class cmExecutionStatus;
class cmMakefile;
/** \class cmFindBase
* \brief Base class for most FIND_XXX commands.
@@ -113,8 +115,13 @@ private:
std::string path;
};
#ifndef CMAKE_BOOTSTRAP
void WriteFindEvent(cmConfigureLog& log, cmMakefile const& mf) const;
#endif
cmFindBase const* FindCommand;
std::string CommandName;
bool TrackSearchProgress() const;
std::vector<DebugLibState> FailedSearchLocations;
DebugLibState FoundSearchLocation;
};

View File

@@ -65,7 +65,7 @@ def check_object_configureLog(o):
assert os.path.exists(path)
eventKindNames = o["eventKindNames"]
assert is_list(eventKindNames)
assert sorted(eventKindNames) == ["message-v1", "try_compile-v1", "try_run-v1"]
assert sorted(eventKindNames) == ["find-v1", "message-v1", "try_compile-v1", "try_run-v1"]
assert is_dict(index)
assert sorted(index.keys()) == ["cmake", "objects", "reply"]

View File

@@ -45,7 +45,7 @@ def check_object_configureLog(o):
assert os.path.exists(path)
eventKindNames = o["eventKindNames"]
assert is_list(eventKindNames)
assert sorted(eventKindNames) == ["message-v1", "try_compile-v1", "try_run-v1"]
assert sorted(eventKindNames) == ["find-v1", "message-v1", "try_compile-v1", "try_run-v1"]
assert is_dict(index)
assert sorted(index.keys()) == ["cmake", "objects", "reply"]

View File

@@ -14,7 +14,7 @@ def check_object_configureLog(o):
assert os.path.exists(path)
eventKindNames = o["eventKindNames"]
assert is_list(eventKindNames)
assert sorted(eventKindNames) == ["message-v1", "try_compile-v1", "try_run-v1"]
assert sorted(eventKindNames) == ["find-v1", "message-v1", "try_compile-v1", "try_run-v1"]
assert is_dict(index)
assert sorted(index.keys()) == ["cmake", "objects", "reply"]

View File

@@ -2,3 +2,70 @@ enable_language(C)
if(FAIL)
message(FATAL_ERROR "Intentionally fail to configure")
endif()
find_file(find_file_var # first search
NAMES "configureLog-v1.cmake"
PATHS "${CMAKE_CURRENT_LIST_DIR}"
DOC "find_file search")
find_file(find_file_var # re-find (no log)
NAMES "configureLog-v1.cmake"
PATHS "${CMAKE_CURRENT_LIST_DIR}"
DOC "find_file search")
unset(find_file_var)
set(find_file_var "find_file_var-NOTFOUND" CACHE PATH "" FORCE)
find_file(find_file_var # not-found to found
NAMES "configureLog-v1.cmake"
PATHS "${CMAKE_CURRENT_LIST_DIR}"
DOC "find_file search")
find_path(find_path_var # first search
NAMES "configureLog-v1.cmake"
PATHS "${CMAKE_CURRENT_LIST_DIR}"
DOC "find_path search")
find_path(find_path_var # re-find (no log)
NAMES "configureLog-v1.cmake"
PATHS "${CMAKE_CURRENT_LIST_DIR}"
DOC "find_path search")
unset(find_path_var)
set(find_path_var "find_path_var-NOTFOUND" CACHE PATH "" FORCE)
find_path(find_path_var # not-found to found
NAMES "configureLog-v1.cmake"
PATHS "${CMAKE_CURRENT_LIST_DIR}"
DOC "find_path search")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}lib${CMAKE_SHARED_LIBRARY_SUFFIX}")
find_library(find_library_var # first search
NAMES "lib"
PATHS "${CMAKE_CURRENT_BINARY_DIR}"
DOC "find_library search")
find_library(find_library_var # re-find (no log)
NAMES "lib"
PATHS "${CMAKE_CURRENT_BINARY_DIR}"
DOC "find_library search")
unset(find_library_var)
set(find_library_var "find_library_var-NOTFOUND" CACHE PATH "" FORCE)
find_library(find_library_var # not-found to found
NAMES "lib"
PATHS "${CMAKE_CURRENT_BINARY_DIR}"
DOC "find_library search")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/exe${CMAKE_EXECUTABLE_SUFFIX}" "")
file(CHMOD "${CMAKE_CURRENT_BINARY_DIR}/exe${CMAKE_EXECUTABLE_SUFFIX}"
FILE_PERMISSIONS
OWNER_READ OWNER_WRITE OWNER_EXECUTE
GROUP_READ GROUP_EXECUTE
WORLD_READ WORLD_EXECUTE)
find_program(find_program_var # first search
NAMES "exe"
PATHS "${CMAKE_CURRENT_BINARY_DIR}"
DOC "find_program search")
find_program(find_program_var # re-find (no log)
NAMES "exe"
PATHS "${CMAKE_CURRENT_BINARY_DIR}"
DOC "find_program search")
unset(find_program_var)
set(find_program_var "find_program_var-NOTFOUND" CACHE PATH "" FORCE)
find_program(find_program_var # not-found to found
NAMES "exe"
PATHS "${CMAKE_CURRENT_BINARY_DIR}"
DOC "find_program search")

View File

@@ -7,7 +7,23 @@ events:(
- "[^"]+")+
message: \|(
+ [^
]*)*)+
]*)*|
-
kind: "find-v1"
backtrace:(
- "[^"]+")+
mode: "[^"]*"
variable: "[^"]*"
description: "[^"]*"
settings:(
[A-Za-z_]+: (true|false|"(NEVER|ONLY|FIRST|LAST)"))+
names:(
- "[^"]+")+
candidate_directories:(
- "[^"]+")*
searched_directories:(
- "[^"]+")*
found: (false|"[^"]*"))+
-
kind: "try_compile-v1"
backtrace:
@@ -34,7 +50,46 @@ events:(
- "[^"]+")+
message: \|(
+ [^
]*)*)*
]*)*|
-
kind: "find-v1"
backtrace:(
- "[^"]+")+
mode: "[^"]*"
variable: "[^"]*"
description: "[^"]*"
settings:(
[A-Za-z_]+: (true|false|"(NEVER|ONLY|FIRST|LAST)"))+
names:(
- "[^"]+")+
candidate_directories:(
- "[^"]+")*
searched_directories:(
- "[^"]+")*
found: (false|"[^"]*"))+(
-
kind: "try_compile-v1"
backtrace:
- ".*/Modules/Internal/FeatureTesting.cmake:[0-9]+ \(try_compile\)"
- ".*/Modules/Internal/FeatureTesting.cmake:[0-9]+ \(_record_compiler_features\)"
- ".*/Modules/Compiler/CMakeCommonCompilerMacros.cmake:[0-9]+ \(_record_compiler_features_c\)"
- ".*/Modules/CMakeDetermineCompilerSupport.cmake:[0-9]+ \(cmake_record_c_compile_features\)"
- ".*/Modules/CMakeTestCCompiler.cmake:[0-9]+ \(CMAKE_DETERMINE_COMPILER_SUPPORT\)"
- "ConfigureLog.cmake:[0-9]+ \(enable_language\)"
- "CMakeLists.txt:[0-9]+ \(include\)"
checks:
- "Detecting C compile features"
directories:
source: "[^"]*/Tests/RunCMake/try_compile/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/"]+"
binary: "[^"]*/Tests/RunCMake/try_compile/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/"]+"
cmakeVariables:(
CMAKE_[^
]*)+
buildResult:
variable: "CMAKE_C_FEATURE_TEST"
cached: true
stdout: \|.*
exitCode: 0)?
-
kind: "try_compile-v1"
backtrace:

View File

@@ -7,7 +7,23 @@ events:(
- "[^"]+")+
message: \|(
+ [^
]*)*)+
]*)*|
-
kind: "find-v1"
backtrace:(
- "[^"]+")+
mode: "[^"]*"
variable: "[^"]*"
description: "[^"]*"
settings:(
[A-Za-z_]+: (true|false|"(NEVER|ONLY|FIRST|LAST)"))+
names:(
- "[^"]+")+
candidate_directories:(
- "[^"]+")*
searched_directories:(
- "[^"]+")*
found: (false|"[^"]*"))+
-
kind: "try_compile-v1"
backtrace:
@@ -34,7 +50,23 @@ events:(
- "[^"]+")+
message: \|(
+ [^
]*)*)+
]*)*|
-
kind: "find-v1"
backtrace:(
- "[^"]+")+
mode: "[^"]*"
variable: "[^"]*"
description: "[^"]*"
settings:(
[A-Za-z_]+: (true|false|"(NEVER|ONLY|FIRST|LAST)"))+
names:(
- "[^"]+")+
candidate_directories:(
- "[^"]+")*
searched_directories:(
- "[^"]+")*
found: (false|"[^"]*"))+
-
kind: "try_compile-v1"
backtrace:

View File

@@ -7,5 +7,21 @@ events:(
- "[^"]+")+
message: \|(
+ [^
]*)*)+
]*)*|
-
kind: "find-v1"
backtrace:(
- "[^"]+")+
mode: "[^"]*"
variable: "[^"]*"
description: "[^"]*"
settings:(
[A-Za-z_]+: (true|false|"(NEVER|ONLY|FIRST|LAST)"))+
names:(
- "[^"]+")+
candidate_directories:(
- "[^"]+")*
searched_directories:(
- "[^"]+")*
found: (false|"[^"]*"))+
\.\.\.$

View File

@@ -7,7 +7,23 @@ events:(
- "[^"]+")+
message: \|(
+ [^
]*)*)+
]*)*|
-
kind: "find-v1"
backtrace:(
- "[^"]+")+
mode: "[^"]*"
variable: "[^"]*"
description: "[^"]*"
settings:(
[A-Za-z_]+: (true|false|"(NEVER|ONLY|FIRST|LAST)"))+
names:(
- "[^"]+")+
candidate_directories:(
- "[^"]+")*
searched_directories:(
- "[^"]+")*
found: (false|"[^"]*"))+
-
kind: "try_compile-v1"
backtrace:
@@ -34,7 +50,23 @@ events:(
- "[^"]+")+
message: \|(
+ [^
]*)*)*
]*)*|
-
kind: "find-v1"
backtrace:(
- "[^"]+")+
mode: "[^"]*"
variable: "[^"]*"
description: "[^"]*"
settings:(
[A-Za-z_]+: (true|false|"(NEVER|ONLY|FIRST|LAST)"))+
names:(
- "[^"]+")+
candidate_directories:(
- "[^"]+")*
searched_directories:(
- "[^"]+")*
found: (false|"[^"]*"))*
-
kind: "try_compile-v1"
backtrace:

View File

@@ -7,7 +7,23 @@ events:(
- "[^"]+")+
message: \|(
+ [^
]*)*)+
]*)*|
-
kind: "find-v1"
backtrace:(
- "[^"]+")+
mode: "[^"]*"
variable: "[^"]*"
description: "[^"]*"
settings:(
[A-Za-z_]+: (true|false|"(NEVER|ONLY|FIRST|LAST)"))+
names:(
- "[^"]+")+
candidate_directories:(
- "[^"]+")*
searched_directories:(
- "[^"]+")*
found: (false|"[^"]*"))+
-
kind: "try_compile-v1"
backtrace:
@@ -33,7 +49,23 @@ events:(
- "[^"]+")+
message: \|(
+ [^
]*)*)*
]*)*|
-
kind: "find-v1"
backtrace:(
- "[^"]+")+
mode: "[^"]*"
variable: "[^"]*"
description: "[^"]*"
settings:(
[A-Za-z_]+: (true|false|"(NEVER|ONLY|FIRST|LAST)"))+
names:(
- "[^"]+")+
candidate_directories:(
- "[^"]+")*
searched_directories:(
- "[^"]+")*
found: (false|"[^"]*"))*
-
kind: "try_run-v1"
backtrace: