resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmTargetPropCommandBase.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 "cmTargetPropCommandBase.h"
4
5 #include "cmExecutionStatus.h"
6 #include "cmGlobalGenerator.h"
7 #include "cmMakefile.h"
8 #include "cmStateTypes.h"
9 #include "cmTarget.h"
10 #include "cmValue.h"
11 #include "cmake.h"
12
13 cmTargetPropCommandBase::cmTargetPropCommandBase(cmExecutionStatus& status)
14   : Makefile(&status.GetMakefile())
15   , Status(status)
16 {
17 }
18
19 void cmTargetPropCommandBase::SetError(std::string const& e)
20 {
21   this->Status.SetError(e);
22 }
23
24 bool cmTargetPropCommandBase::HandleArguments(
25   std::vector<std::string> const& args, const std::string& prop,
26   ArgumentFlags flags)
27 {
28   if (args.size() < 2) {
29     this->SetError("called with incorrect number of arguments");
30     return false;
31   }
32
33   if (this->Makefile->IsAlias(args[0])) {
34     this->SetError("can not be used on an ALIAS target.");
35     return false;
36   }
37   // Lookup the target for which property-values are specified.
38   this->Target =
39     this->Makefile->GetCMakeInstance()->GetGlobalGenerator()->FindTarget(
40       args[0]);
41   if (!this->Target) {
42     this->Target = this->Makefile->FindTargetToUse(args[0]);
43   }
44   if (!this->Target) {
45     this->HandleMissingTarget(args[0]);
46     return false;
47   }
48   const bool isRegularTarget =
49     (this->Target->GetType() == cmStateEnums::EXECUTABLE) ||
50     (this->Target->GetType() == cmStateEnums::STATIC_LIBRARY) ||
51     (this->Target->GetType() == cmStateEnums::SHARED_LIBRARY) ||
52     (this->Target->GetType() == cmStateEnums::MODULE_LIBRARY) ||
53     (this->Target->GetType() == cmStateEnums::OBJECT_LIBRARY) ||
54     (this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY) ||
55     (this->Target->GetType() == cmStateEnums::UNKNOWN_LIBRARY);
56   const bool isCustomTarget = this->Target->GetType() == cmStateEnums::UTILITY;
57
58   if (prop == "SOURCES") {
59     if (!isRegularTarget && !isCustomTarget) {
60       this->SetError("called with non-compilable target type");
61       return false;
62     }
63   } else {
64     if (!isRegularTarget) {
65       this->SetError("called with non-compilable target type");
66       return false;
67     }
68   }
69
70   bool system = false;
71   unsigned int argIndex = 1;
72
73   if ((flags & PROCESS_SYSTEM) && args[argIndex] == "SYSTEM") {
74     if (args.size() < 3) {
75       this->SetError("called with incorrect number of arguments");
76       return false;
77     }
78     system = true;
79     ++argIndex;
80   }
81
82   bool prepend = false;
83   if ((flags & PROCESS_BEFORE) && args[argIndex] == "BEFORE") {
84     if (args.size() < 3) {
85       this->SetError("called with incorrect number of arguments");
86       return false;
87     }
88     prepend = true;
89     ++argIndex;
90   } else if ((flags & PROCESS_AFTER) && args[argIndex] == "AFTER") {
91     if (args.size() < 3) {
92       this->SetError("called with incorrect number of arguments");
93       return false;
94     }
95     prepend = false;
96     ++argIndex;
97   }
98
99   if ((flags & PROCESS_REUSE_FROM) && args[argIndex] == "REUSE_FROM") {
100     if (args.size() != 3) {
101       this->SetError("called with incorrect number of arguments");
102       return false;
103     }
104     ++argIndex;
105
106     this->Target->SetProperty("PRECOMPILE_HEADERS_REUSE_FROM", args[argIndex]);
107     ++argIndex;
108   }
109
110   this->Property = prop;
111
112   while (argIndex < args.size()) {
113     if (!this->ProcessContentArgs(args, argIndex, prepend, system)) {
114       return false;
115     }
116   }
117   return true;
118 }
119
120 bool cmTargetPropCommandBase::ProcessContentArgs(
121   std::vector<std::string> const& args, unsigned int& argIndex, bool prepend,
122   bool system)
123 {
124   std::string const& scope = args[argIndex];
125
126   if (scope != "PUBLIC" && scope != "PRIVATE" && scope != "INTERFACE") {
127     this->SetError("called with invalid arguments");
128     return false;
129   }
130
131   ++argIndex;
132
133   std::vector<std::string> content;
134
135   for (unsigned int i = argIndex; i < args.size(); ++i, ++argIndex) {
136     if (args[i] == "PUBLIC" || args[i] == "PRIVATE" ||
137         args[i] == "INTERFACE") {
138       break;
139     }
140     content.push_back(args[i]);
141   }
142   if (!content.empty()) {
143     if (this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY &&
144         scope != "INTERFACE" && this->Property != "SOURCES") {
145       this->SetError("may only set INTERFACE properties on INTERFACE targets");
146       return false;
147     }
148     if (this->Target->IsImported() && scope != "INTERFACE") {
149       this->SetError("may only set INTERFACE properties on IMPORTED targets");
150       return false;
151     }
152     if (this->Target->GetType() == cmStateEnums::UTILITY &&
153         scope != "PRIVATE") {
154       this->SetError("may only set PRIVATE properties on custom targets");
155       return false;
156     }
157   }
158   return this->PopulateTargetProperties(scope, content, prepend, system);
159 }
160
161 bool cmTargetPropCommandBase::PopulateTargetProperties(
162   const std::string& scope, const std::vector<std::string>& content,
163   bool prepend, bool system)
164 {
165   if (content.empty()) {
166     return true;
167   }
168   if (scope == "PRIVATE" || scope == "PUBLIC") {
169     if (!this->HandleDirectContent(this->Target, content, prepend, system)) {
170       return false;
171     }
172   }
173   if (scope == "INTERFACE" || scope == "PUBLIC") {
174     this->HandleInterfaceContent(this->Target, content, prepend, system);
175   }
176   return true;
177 }
178
179 void cmTargetPropCommandBase::HandleInterfaceContent(
180   cmTarget* tgt, const std::vector<std::string>& content, bool prepend, bool)
181 {
182   if (prepend) {
183     const std::string propName = std::string("INTERFACE_") + this->Property;
184     cmValue propValue = tgt->GetProperty(propName);
185     const std::string totalContent =
186       this->Join(content) + (propValue ? (";" + *propValue) : std::string());
187     tgt->SetProperty(propName, totalContent);
188   } else {
189     tgt->AppendProperty("INTERFACE_" + this->Property, this->Join(content));
190   }
191 }