1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
3 #include "cmFileAPICommand.h"
10 #include <cm/string_view>
11 #include <cmext/string_view>
13 #include "cmArgumentParser.h"
14 #include "cmArgumentParserTypes.h"
15 #include "cmExecutionStatus.h"
16 #include "cmFileAPI.h"
17 #include "cmMakefile.h"
19 #include "cmStringAlgorithms.h"
20 #include "cmSubcommandTable.h"
25 bool isCharDigit(char ch
)
27 return std::isdigit(static_cast<unsigned char>(ch
));
30 std::string
processObjectKindVersions(cmFileAPI
& fileApi
,
31 cmFileAPI::ObjectKind objectKind
,
32 cm::string_view keyword
,
33 const std::vector
<std::string
>& versions
)
35 // The "versions" vector is empty only when the keyword was not present.
36 // It is an error to provide the keyword with no versions after it, and that
37 // is enforced by the argument parser before we get here.
38 if (versions
.empty()) {
42 // The first supported version listed is what we use
43 for (const std::string
& ver
: versions
) {
44 const char* vStart
= ver
.c_str();
45 int majorVersion
= std::atoi(vStart
);
47 std::string::size_type pos
= ver
.find('.');
48 if (pos
!= std::string::npos
) {
50 minorVersion
= std::atoi(vStart
);
52 if (majorVersion
< 1 || minorVersion
< 0) {
53 return cmStrCat("Given a malformed version \"", ver
, "\" for ", keyword
,
56 if (fileApi
.AddProjectQuery(objectKind
,
57 static_cast<unsigned>(majorVersion
),
58 static_cast<unsigned>(minorVersion
))) {
62 return cmStrCat("None of the specified ", keyword
,
63 " versions is supported by this version of CMake.");
66 bool handleQueryCommand(std::vector
<std::string
> const& args
,
67 cmExecutionStatus
& status
)
70 status
.SetError("QUERY subcommand called without required arguments.");
74 struct Arguments
: public ArgumentParser::ParseResult
76 ArgumentParser::NonEmpty
<std::string
> ApiVersion
;
77 ArgumentParser::NonEmpty
<std::vector
<std::string
>> CodeModelVersions
;
78 ArgumentParser::NonEmpty
<std::vector
<std::string
>> CacheVersions
;
79 ArgumentParser::NonEmpty
<std::vector
<std::string
>> CMakeFilesVersions
;
80 ArgumentParser::NonEmpty
<std::vector
<std::string
>> ToolchainsVersions
;
83 static auto const parser
=
84 cmArgumentParser
<Arguments
>{}
85 .Bind("API_VERSION"_s
, &Arguments::ApiVersion
)
86 .Bind("CODEMODEL"_s
, &Arguments::CodeModelVersions
)
87 .Bind("CACHE"_s
, &Arguments::CacheVersions
)
88 .Bind("CMAKEFILES"_s
, &Arguments::CMakeFilesVersions
)
89 .Bind("TOOLCHAINS"_s
, &Arguments::ToolchainsVersions
);
91 std::vector
<std::string
> unparsedArguments
;
92 Arguments
const arguments
=
93 parser
.Parse(cmMakeRange(args
).advance(1), &unparsedArguments
);
95 if (arguments
.MaybeReportError(status
.GetMakefile())) {
98 if (!unparsedArguments
.empty()) {
99 status
.SetError("QUERY subcommand given unknown argument \"" +
100 unparsedArguments
.front() + "\".");
104 if (!std::all_of(arguments
.ApiVersion
.begin(), arguments
.ApiVersion
.end(),
106 status
.SetError("QUERY subcommand given a non-integer API_VERSION.");
109 const int apiVersion
= std::atoi(arguments
.ApiVersion
.c_str());
110 if (apiVersion
!= 1) {
112 cmStrCat("QUERY subcommand given an unsupported API_VERSION \"",
113 arguments
.ApiVersion
,
114 "\" (the only currently supported version is 1)."));
118 cmMakefile
& mf
= status
.GetMakefile();
119 cmake
* cmi
= mf
.GetCMakeInstance();
120 cmFileAPI
* fileApi
= cmi
->GetFileAPI();
122 // We want to check all keywords and report all errors, not just the first.
123 // Record each result rather than short-circuiting on the first error.
125 // NOTE: Double braces are needed here for compilers that don't implement the
126 // CWG 1270 revision to C++11.
127 std::array
<std::string
, 4> errors
{
128 { processObjectKindVersions(*fileApi
, cmFileAPI::ObjectKind::CodeModel
,
129 "CODEMODEL"_s
, arguments
.CodeModelVersions
),
130 processObjectKindVersions(*fileApi
, cmFileAPI::ObjectKind::Cache
,
131 "CACHE"_s
, arguments
.CacheVersions
),
132 processObjectKindVersions(*fileApi
, cmFileAPI::ObjectKind::CMakeFiles
,
133 "CMAKEFILES"_s
, arguments
.CMakeFilesVersions
),
134 processObjectKindVersions(*fileApi
, cmFileAPI::ObjectKind::Toolchains
,
135 "TOOLCHAINS"_s
, arguments
.ToolchainsVersions
) }
138 if (!std::all_of(errors
.begin(), errors
.end(),
139 [](const std::string
& s
) -> bool { return s
.empty(); })) {
140 std::string
message("QUERY subcommand was given invalid arguments:");
141 for (const std::string
& s
: errors
) {
143 message
= cmStrCat(message
, "\n ", s
);
146 status
.SetError(message
);
155 bool cmFileAPICommand(std::vector
<std::string
> const& args
,
156 cmExecutionStatus
& status
)
159 status
.SetError("must be called with arguments.");
164 static cmSubcommandTable
const subcommand
{
165 { "QUERY"_s
, handleQueryCommand
}
169 return subcommand(args
[0], args
, status
);