diff options
author | Brad King <brad.king@kitware.com> | 2023-06-05 13:44:44 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2023-06-05 13:45:02 (GMT) |
commit | 3760ac9845e3c0d163eb1b4d83ab5b2f367507aa (patch) | |
tree | 8b0e37e17ea6bf8779f0db4f64de89691dacd3dc /Source | |
parent | 33750f128b874f9420db1e9e44c2963e64b59448 (diff) | |
parent | 99b2ccf80dc87ccf6832508cc3f8889a70c2785f (diff) | |
download | CMake-3760ac9845e3c0d163eb1b4d83ab5b2f367507aa.zip CMake-3760ac9845e3c0d163eb1b4d83ab5b2f367507aa.tar.gz CMake-3760ac9845e3c0d163eb1b4d83ab5b2f367507aa.tar.bz2 |
Merge topic 'file-api-query-command'
99b2ccf80d cmake_file_api: New project command
Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: buildbot <buildbot@kitware.com>
Merge-request: !8530
Diffstat (limited to 'Source')
-rw-r--r-- | Source/CMakeLists.txt | 2 | ||||
-rw-r--r-- | Source/cmCommands.cxx | 3 | ||||
-rw-r--r-- | Source/cmFileAPI.cxx | 42 | ||||
-rw-r--r-- | Source/cmFileAPI.h | 33 | ||||
-rw-r--r-- | Source/cmFileAPICommand.cxx | 170 | ||||
-rw-r--r-- | Source/cmFileAPICommand.h | 13 | ||||
-rw-r--r-- | Source/cmake.h | 4 |
7 files changed, 256 insertions, 11 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index bcaf890..b01e1e7 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -232,6 +232,8 @@ add_library( cmFileAPIConfigureLog.h cmFileAPICMakeFiles.cxx cmFileAPICMakeFiles.h + cmFileAPICommand.cxx + cmFileAPICommand.h cmFileAPIToolchains.cxx cmFileAPIToolchains.h cmFileCopier.cxx diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx index 27f2156..ae83b2e 100644 --- a/Source/cmCommands.cxx +++ b/Source/cmCommands.cxx @@ -97,6 +97,7 @@ # include "cmExportCommand.h" # include "cmExportLibraryDependenciesCommand.h" # include "cmFLTKWrapUICommand.h" +# include "cmFileAPICommand.h" # include "cmIncludeExternalMSProjectCommand.h" # include "cmInstallProgramsCommand.h" # include "cmLinkLibrariesCommand.h" @@ -293,6 +294,7 @@ void GetProjectCommands(cmState* state) state->AddBuiltinCommand("qt_wrap_ui", cmQTWrapUICommand); state->AddBuiltinCommand("remove_definitions", cmRemoveDefinitionsCommand); state->AddBuiltinCommand("source_group", cmSourceGroupCommand); + state->AddBuiltinCommand("cmake_file_api", cmFileAPICommand); state->AddDisallowedCommand( "export_library_dependencies", cmExportLibraryDependenciesCommand, @@ -333,6 +335,7 @@ void GetProjectCommandsInScriptMode(cmState* state) CM_UNEXPECTED_PROJECT_COMMAND("add_test"); CM_UNEXPECTED_PROJECT_COMMAND("aux_source_directory"); CM_UNEXPECTED_PROJECT_COMMAND("build_command"); + CM_UNEXPECTED_PROJECT_COMMAND("cmake_file_api"); CM_UNEXPECTED_PROJECT_COMMAND("create_test_sourcelist"); CM_UNEXPECTED_PROJECT_COMMAND("define_property"); CM_UNEXPECTED_PROJECT_COMMAND("enable_language"); diff --git a/Source/cmFileAPI.cxx b/Source/cmFileAPI.cxx index 8b98916..8abb5a8 100644 --- a/Source/cmFileAPI.cxx +++ b/Source/cmFileAPI.cxx @@ -978,3 +978,45 @@ Json::Value cmFileAPI::ReportCapabilities() return capabilities; } + +bool cmFileAPI::AddProjectQuery(cmFileAPI::ObjectKind kind, + unsigned majorVersion, unsigned minorVersion) +{ + switch (kind) { + case ObjectKind::CodeModel: + if (majorVersion != 2 || minorVersion > CodeModelV2Minor) { + return false; + } + break; + case ObjectKind::Cache: + if (majorVersion != 2 || minorVersion > CacheV2Minor) { + return false; + } + break; + case ObjectKind::CMakeFiles: + if (majorVersion != 1 || minorVersion > CMakeFilesV1Minor) { + return false; + } + break; + case ObjectKind::Toolchains: + if (majorVersion != 1 || minorVersion > ToolchainsV1Minor) { + return false; + } + break; + // These cannot be requested by the project + case ObjectKind::ConfigureLog: + case ObjectKind::InternalTest: + return false; + } + + Object query; + query.Kind = kind; + query.Version = majorVersion; + if (std::find(this->TopQuery.Known.begin(), this->TopQuery.Known.end(), + query) == this->TopQuery.Known.end()) { + this->TopQuery.Known.emplace_back(query); + this->QueryExists = true; + } + + return true; +} diff --git a/Source/cmFileAPI.h b/Source/cmFileAPI.h index 6d7678f..1c13d7b 100644 --- a/Source/cmFileAPI.h +++ b/Source/cmFileAPI.h @@ -41,6 +41,20 @@ public: /** Report file-api capabilities for cmake -E capabilities. */ static Json::Value ReportCapabilities(); + // Keep in sync with ObjectKindName. + enum class ObjectKind + { + CodeModel, + ConfigureLog, + Cache, + CMakeFiles, + Toolchains, + InternalTest + }; + + bool AddProjectQuery(ObjectKind kind, unsigned majorVersion, + unsigned minorVersion); + private: cmake* CMakeInstance; @@ -53,17 +67,6 @@ private: static std::vector<std::string> LoadDir(std::string const& dir); void RemoveOldReplyFiles(); - // Keep in sync with ObjectKindName. - enum class ObjectKind - { - CodeModel, - ConfigureLog, - Cache, - CMakeFiles, - Toolchains, - InternalTest - }; - /** Identify one object kind and major version. */ struct Object { @@ -76,6 +79,14 @@ private: } return l.Version < r.Version; } + friend bool operator==(Object const& l, Object const& r) + { + return l.Kind == r.Kind && l.Version == r.Version; + } + friend bool operator!=(Object const& l, Object const& r) + { + return !(l == r); + } }; /** Represent content of a query directory. */ diff --git a/Source/cmFileAPICommand.cxx b/Source/cmFileAPICommand.cxx new file mode 100644 index 0000000..d051c9c --- /dev/null +++ b/Source/cmFileAPICommand.cxx @@ -0,0 +1,170 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying +file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmFileAPICommand.h" + +#include <algorithm> +#include <array> +#include <cctype> +#include <cstdlib> + +#include <cm/string_view> +#include <cmext/string_view> + +#include "cmArgumentParser.h" +#include "cmArgumentParserTypes.h" +#include "cmExecutionStatus.h" +#include "cmFileAPI.h" +#include "cmMakefile.h" +#include "cmRange.h" +#include "cmStringAlgorithms.h" +#include "cmSubcommandTable.h" +#include "cmake.h" + +namespace { + +bool isCharDigit(char ch) +{ + return std::isdigit(static_cast<unsigned char>(ch)); +} + +std::string processObjectKindVersions(cmFileAPI& fileApi, + cmFileAPI::ObjectKind objectKind, + cm::string_view keyword, + const std::vector<std::string>& versions) +{ + // The "versions" vector is empty only when the keyword was not present. + // It is an error to provide the keyword with no versions after it, and that + // is enforced by the argument parser before we get here. + if (versions.empty()) { + return {}; + } + + // The first supported version listed is what we use + for (const std::string& ver : versions) { + const char* vStart = ver.c_str(); + int majorVersion = std::atoi(vStart); + int minorVersion = 0; + std::string::size_type pos = ver.find('.'); + if (pos != std::string::npos) { + vStart += pos + 1; + minorVersion = std::atoi(vStart); + } + if (majorVersion < 1 || minorVersion < 0) { + return cmStrCat("Given a malformed version \"", ver, "\" for ", keyword, + "."); + } + if (fileApi.AddProjectQuery(objectKind, + static_cast<unsigned>(majorVersion), + static_cast<unsigned>(minorVersion))) { + return {}; + } + } + return cmStrCat("None of the specified ", keyword, + " versions is supported by this version of CMake."); +} + +bool handleQueryCommand(std::vector<std::string> const& args, + cmExecutionStatus& status) +{ + if (args.empty()) { + status.SetError("QUERY subcommand called without required arguments."); + return false; + } + + struct Arguments : public ArgumentParser::ParseResult + { + ArgumentParser::NonEmpty<std::string> ApiVersion; + ArgumentParser::NonEmpty<std::vector<std::string>> CodeModelVersions; + ArgumentParser::NonEmpty<std::vector<std::string>> CacheVersions; + ArgumentParser::NonEmpty<std::vector<std::string>> CMakeFilesVersions; + ArgumentParser::NonEmpty<std::vector<std::string>> ToolchainsVersions; + }; + + static auto const parser = + cmArgumentParser<Arguments>{} + .Bind("API_VERSION"_s, &Arguments::ApiVersion) + .Bind("CODEMODEL"_s, &Arguments::CodeModelVersions) + .Bind("CACHE"_s, &Arguments::CacheVersions) + .Bind("CMAKEFILES"_s, &Arguments::CMakeFilesVersions) + .Bind("TOOLCHAINS"_s, &Arguments::ToolchainsVersions); + + std::vector<std::string> unparsedArguments; + Arguments const arguments = + parser.Parse(cmMakeRange(args).advance(1), &unparsedArguments); + + if (arguments.MaybeReportError(status.GetMakefile())) { + return true; + } + if (!unparsedArguments.empty()) { + status.SetError("QUERY subcommand given unknown argument \"" + + unparsedArguments.front() + "\"."); + return false; + } + + if (!std::all_of(arguments.ApiVersion.begin(), arguments.ApiVersion.end(), + isCharDigit)) { + status.SetError("QUERY subcommand given a non-integer API_VERSION."); + return false; + } + const int apiVersion = std::atoi(arguments.ApiVersion.c_str()); + if (apiVersion != 1) { + status.SetError( + cmStrCat("QUERY subcommand given an unsupported API_VERSION \"", + arguments.ApiVersion, + "\" (the only currently supported version is 1).")); + return false; + } + + cmMakefile& mf = status.GetMakefile(); + cmake* cmi = mf.GetCMakeInstance(); + cmFileAPI* fileApi = cmi->GetFileAPI(); + + // We want to check all keywords and report all errors, not just the first. + // Record each result rather than short-circuiting on the first error. + + // NOTE: Double braces are needed here for compilers that don't implement the + // CWG 1270 revision to C++11. + std::array<std::string, 4> errors{ + { processObjectKindVersions(*fileApi, cmFileAPI::ObjectKind::CodeModel, + "CODEMODEL"_s, arguments.CodeModelVersions), + processObjectKindVersions(*fileApi, cmFileAPI::ObjectKind::Cache, + "CACHE"_s, arguments.CacheVersions), + processObjectKindVersions(*fileApi, cmFileAPI::ObjectKind::CMakeFiles, + "CMAKEFILES"_s, arguments.CMakeFilesVersions), + processObjectKindVersions(*fileApi, cmFileAPI::ObjectKind::Toolchains, + "TOOLCHAINS"_s, arguments.ToolchainsVersions) } + }; + + if (!std::all_of(errors.begin(), errors.end(), + [](const std::string& s) -> bool { return s.empty(); })) { + std::string message("QUERY subcommand was given invalid arguments:"); + for (const std::string& s : errors) { + if (!s.empty()) { + message = cmStrCat(message, "\n ", s); + } + } + status.SetError(message); + return false; + } + + return true; +} + +} + +bool cmFileAPICommand(std::vector<std::string> const& args, + cmExecutionStatus& status) +{ + if (args.empty()) { + status.SetError("must be called with arguments."); + return false; + } + + // clang-format off + static cmSubcommandTable const subcommand{ + { "QUERY"_s, handleQueryCommand } + }; + // clang-format on + + return subcommand(args[0], args, status); +} diff --git a/Source/cmFileAPICommand.h b/Source/cmFileAPICommand.h new file mode 100644 index 0000000..28a4571 --- /dev/null +++ b/Source/cmFileAPICommand.h @@ -0,0 +1,13 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying +file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include "cmConfigure.h" // IWYU pragma: keep + +#include <string> +#include <vector> + +class cmExecutionStatus; + +bool cmFileAPICommand(std::vector<std::string> const& args, + cmExecutionStatus& status); diff --git a/Source/cmake.h b/Source/cmake.h index 2f5ea24..156d061 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -635,6 +635,10 @@ public: void UnwatchUnusedCli(const std::string& var); void WatchUnusedCli(const std::string& var); +#if !defined(CMAKE_BOOTSTRAP) + cmFileAPI* GetFileAPI() const { return this->FileAPI.get(); } +#endif + cmState* GetState() const { return this->State.get(); } void SetCurrentSnapshot(cmStateSnapshot const& snapshot) { |