Imported Upstream version 3.25.0
[platform/upstream/cmake.git] / Source / cmDefinePropertyCommand.cxx
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 "cmDefinePropertyCommand.h"
4
5 #include <algorithm>
6 #include <iterator>
7
8 #include <cmext/string_view>
9
10 #include "cmArgumentParser.h"
11 #include "cmArgumentParserTypes.h"
12 #include "cmExecutionStatus.h"
13 #include "cmMakefile.h"
14 #include "cmProperty.h"
15 #include "cmRange.h"
16 #include "cmState.h"
17 #include "cmStringAlgorithms.h"
18
19 bool cmDefinePropertyCommand(std::vector<std::string> const& args,
20                              cmExecutionStatus& status)
21 {
22   if (args.empty()) {
23     status.SetError("called with incorrect number of arguments");
24     return false;
25   }
26
27   // Get the scope in which to define the property.
28   cmProperty::ScopeType scope;
29   std::string const& scope_arg = args[0];
30
31   if (scope_arg == "GLOBAL") {
32     scope = cmProperty::GLOBAL;
33   } else if (scope_arg == "DIRECTORY") {
34     scope = cmProperty::DIRECTORY;
35   } else if (scope_arg == "TARGET") {
36     scope = cmProperty::TARGET;
37   } else if (scope_arg == "SOURCE") {
38     scope = cmProperty::SOURCE_FILE;
39   } else if (scope_arg == "TEST") {
40     scope = cmProperty::TEST;
41   } else if (scope_arg == "VARIABLE") {
42     scope = cmProperty::VARIABLE;
43   } else if (scope_arg == "CACHED_VARIABLE") {
44     scope = cmProperty::CACHED_VARIABLE;
45   } else {
46     status.SetError(cmStrCat("given invalid scope ", scope_arg,
47                              ".  Valid scopes are GLOBAL, DIRECTORY, TARGET, "
48                              "SOURCE, TEST, VARIABLE, CACHED_VARIABLE."));
49     return false;
50   }
51
52   // Parse remaining arguments.
53   bool inherited = false;
54   std::string PropertyName;
55   ArgumentParser::NonEmpty<std::vector<std::string>> BriefDocs;
56   ArgumentParser::NonEmpty<std::vector<std::string>> FullDocs;
57   std::string initializeFromVariable;
58
59   cmArgumentParser<void> parser;
60   parser.Bind("PROPERTY"_s, PropertyName);
61   parser.Bind("BRIEF_DOCS"_s, BriefDocs);
62   parser.Bind("FULL_DOCS"_s, FullDocs);
63   parser.Bind("INHERITED"_s, inherited);
64   parser.Bind("INITIALIZE_FROM_VARIABLE"_s, initializeFromVariable);
65   std::vector<std::string> invalidArgs;
66
67   parser.Parse(cmMakeRange(args).advance(1), &invalidArgs);
68   if (!invalidArgs.empty()) {
69     status.SetError(
70       cmStrCat("given invalid argument \"", invalidArgs.front(), "\"."));
71     return false;
72   }
73
74   // Make sure a property name was found.
75   if (PropertyName.empty()) {
76     status.SetError("not given a PROPERTY <name> argument.");
77     return false;
78   }
79
80   if (!initializeFromVariable.empty()) {
81     // Make sure property scope is TARGET.
82     if (scope != cmProperty::TARGET) {
83       status.SetError(
84         "Scope must be TARGET if INITIALIZE_FROM_VARIABLE is specified");
85       return false;
86     }
87
88     // Make sure the variable has the property name as a suffix.
89     if (!cmHasSuffix(initializeFromVariable, PropertyName)) {
90       status.SetError(cmStrCat("Variable name \"", initializeFromVariable,
91                                "\" does not end with property name \"",
92                                PropertyName, "\""));
93       return false;
94     }
95     if (PropertyName.find('_') == std::string::npos) {
96       status.SetError(cmStrCat("Property name \"", PropertyName,
97                                "\" defined with INITIALIZE_FROM_VARIABLE does "
98                                "not contain underscore"));
99       return false;
100     }
101
102     // Make sure the variable is not reserved.
103     static constexpr const char* reservedPrefixes[] = {
104       "CMAKE_",
105       "_CMAKE_",
106     };
107     if (std::any_of(std::begin(reservedPrefixes), std::end(reservedPrefixes),
108                     [&initializeFromVariable](const char* prefix) {
109                       return cmHasPrefix(initializeFromVariable, prefix);
110                     })) {
111       status.SetError(cmStrCat("variable name \"", initializeFromVariable,
112                                "\" is reserved"));
113       return false;
114     }
115   }
116
117   // Actually define the property.
118   status.GetMakefile().GetState()->DefineProperty(
119     PropertyName, scope, cmJoin(BriefDocs, ""), cmJoin(FullDocs, ""),
120     inherited, initializeFromVariable);
121
122   return true;
123 }