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 "cmGetPropertyCommand.h"
7 #include "cmExecutionStatus.h"
8 #include "cmGlobalGenerator.h"
9 #include "cmInstalledFile.h"
10 #include "cmMakefile.h"
11 #include "cmMessageType.h"
12 #include "cmPolicies.h"
13 #include "cmProperty.h"
14 #include "cmPropertyDefinition.h"
15 #include "cmSetPropertyCommand.h"
16 #include "cmSourceFile.h"
18 #include "cmStringAlgorithms.h"
19 #include "cmSystemTools.h"
35 // Implementation of each property type.
36 bool HandleGlobalMode(cmExecutionStatus& status, const std::string& name,
37 OutType infoType, const std::string& variable,
38 const std::string& propertyName);
39 bool HandleDirectoryMode(cmExecutionStatus& status, const std::string& name,
40 OutType infoType, const std::string& variable,
41 const std::string& propertyName);
42 bool HandleTargetMode(cmExecutionStatus& status, const std::string& name,
43 OutType infoType, const std::string& variable,
44 const std::string& propertyName);
45 bool HandleSourceMode(cmExecutionStatus& status, const std::string& name,
46 OutType infoType, const std::string& variable,
47 const std::string& propertyName,
48 cmMakefile& directory_makefile,
49 bool source_file_paths_should_be_absolute);
50 bool HandleTestMode(cmExecutionStatus& status, const std::string& name,
51 OutType infoType, const std::string& variable,
52 const std::string& propertyName);
53 bool HandleVariableMode(cmExecutionStatus& status, const std::string& name,
54 OutType infoType, const std::string& variable,
55 const std::string& propertyName);
56 bool HandleCacheMode(cmExecutionStatus& status, const std::string& name,
57 OutType infoType, const std::string& variable,
58 const std::string& propertyName);
59 bool HandleInstallMode(cmExecutionStatus& status, const std::string& name,
60 OutType infoType, const std::string& variable,
61 const std::string& propertyName);
64 bool cmGetPropertyCommand(std::vector<std::string> const& args,
65 cmExecutionStatus& status)
67 OutType infoType = OutValue;
68 if (args.size() < 3) {
69 status.SetError("called with incorrect number of arguments");
73 // The cmake variable in which to store the result.
74 std::string const& variable = args[0];
77 std::string propertyName;
79 std::vector<std::string> source_file_directories;
80 std::vector<std::string> source_file_target_directories;
81 bool source_file_directory_option_enabled = false;
82 bool source_file_target_option_enabled = false;
84 // Get the scope from which to get the property.
85 cmProperty::ScopeType scope;
86 if (args[1] == "GLOBAL") {
87 scope = cmProperty::GLOBAL;
88 } else if (args[1] == "DIRECTORY") {
89 scope = cmProperty::DIRECTORY;
90 } else if (args[1] == "TARGET") {
91 scope = cmProperty::TARGET;
92 } else if (args[1] == "SOURCE") {
93 scope = cmProperty::SOURCE_FILE;
94 } else if (args[1] == "TEST") {
95 scope = cmProperty::TEST;
96 } else if (args[1] == "VARIABLE") {
97 scope = cmProperty::VARIABLE;
98 } else if (args[1] == "CACHE") {
99 scope = cmProperty::CACHE;
100 } else if (args[1] == "INSTALL") {
101 scope = cmProperty::INSTALL;
103 status.SetError(cmStrCat(
104 "given invalid scope ", args[1],
107 "GLOBAL, DIRECTORY, TARGET, SOURCE, TEST, VARIABLE, CACHE, INSTALL."));
111 // Parse remaining arguments.
118 DoingSourceDirectory,
119 DoingSourceTargetDirectory
121 Doing doing = DoingName;
122 for (unsigned int i = 2; i < args.size(); ++i) {
123 if (args[i] == "PROPERTY") {
124 doing = DoingProperty;
125 } else if (args[i] == "BRIEF_DOCS") {
127 infoType = OutBriefDoc;
128 } else if (args[i] == "FULL_DOCS") {
130 infoType = OutFullDoc;
131 } else if (args[i] == "SET") {
134 } else if (args[i] == "DEFINED") {
136 infoType = OutDefined;
137 } else if (doing == DoingName) {
140 } else if (doing == DoingNone && scope == cmProperty::SOURCE_FILE &&
141 args[i] == "DIRECTORY") {
142 doing = DoingSourceDirectory;
143 source_file_directory_option_enabled = true;
144 } else if (doing == DoingNone && scope == cmProperty::SOURCE_FILE &&
145 args[i] == "TARGET_DIRECTORY") {
146 doing = DoingSourceTargetDirectory;
147 source_file_target_option_enabled = true;
148 } else if (doing == DoingSourceDirectory) {
149 source_file_directories.push_back(args[i]);
151 } else if (doing == DoingSourceTargetDirectory) {
152 source_file_target_directories.push_back(args[i]);
154 } else if (doing == DoingProperty) {
156 propertyName = args[i];
158 status.SetError(cmStrCat("given invalid argument \"", args[i], "\"."));
163 // Make sure a property name was found.
164 if (propertyName.empty()) {
165 status.SetError("not given a PROPERTY <name> argument.");
169 std::vector<cmMakefile*> source_file_directory_makefiles;
170 bool file_scopes_handled =
171 SetPropertyCommand::HandleAndValidateSourceFileDirectoryScopes(
172 status, source_file_directory_option_enabled,
173 source_file_target_option_enabled, source_file_directories,
174 source_file_target_directories, source_file_directory_makefiles);
175 if (!file_scopes_handled) {
179 // Compute requested output.
180 if (infoType == OutBriefDoc) {
181 // Lookup brief documentation.
183 if (cmPropertyDefinition const* def =
184 status.GetMakefile().GetState()->GetPropertyDefinition(propertyName,
186 output = def->GetShortDescription();
188 if (output.empty()) {
191 status.GetMakefile().AddDefinition(variable, output);
192 } else if (infoType == OutFullDoc) {
193 // Lookup full documentation.
195 if (cmPropertyDefinition const* def =
196 status.GetMakefile().GetState()->GetPropertyDefinition(propertyName,
198 output = def->GetFullDescription();
200 if (output.empty()) {
203 status.GetMakefile().AddDefinition(variable, output);
204 } else if (infoType == OutDefined) {
205 // Lookup if the property is defined
206 if (status.GetMakefile().GetState()->GetPropertyDefinition(propertyName,
208 status.GetMakefile().AddDefinition(variable, "1");
210 status.GetMakefile().AddDefinition(variable, "0");
213 // Dispatch property getting.
214 cmMakefile& directory_scope_mf = *(source_file_directory_makefiles[0]);
215 bool source_file_paths_should_be_absolute =
216 source_file_directory_option_enabled ||
217 source_file_target_option_enabled;
220 case cmProperty::GLOBAL:
221 return HandleGlobalMode(status, name, infoType, variable,
223 case cmProperty::DIRECTORY:
224 return HandleDirectoryMode(status, name, infoType, variable,
226 case cmProperty::TARGET:
227 return HandleTargetMode(status, name, infoType, variable,
229 case cmProperty::SOURCE_FILE:
230 return HandleSourceMode(status, name, infoType, variable, propertyName,
232 source_file_paths_should_be_absolute);
233 case cmProperty::TEST:
234 return HandleTestMode(status, name, infoType, variable, propertyName);
235 case cmProperty::VARIABLE:
236 return HandleVariableMode(status, name, infoType, variable,
238 case cmProperty::CACHE:
239 return HandleCacheMode(status, name, infoType, variable, propertyName);
240 case cmProperty::INSTALL:
241 return HandleInstallMode(status, name, infoType, variable,
244 case cmProperty::CACHED_VARIABLE:
245 break; // should never happen
254 // Implementation of result storage.
255 template <typename ValueType>
256 bool StoreResult(OutType infoType, cmMakefile& makefile,
257 const std::string& variable, ValueType value)
259 if (infoType == OutSet) {
260 makefile.AddDefinition(variable, value ? "1" : "0");
261 } else // if(infoType == OutValue)
264 makefile.AddDefinition(variable, value);
266 makefile.RemoveDefinition(variable);
272 bool StoreResult(OutType infoType, cmMakefile& makefile,
273 const std::string& variable, std::nullptr_t value)
275 return StoreResult(infoType, makefile, variable, cmValue(value));
278 bool HandleGlobalMode(cmExecutionStatus& status, const std::string& name,
279 OutType infoType, const std::string& variable,
280 const std::string& propertyName)
283 status.SetError("given name for GLOBAL scope.");
288 cmake* cm = status.GetMakefile().GetCMakeInstance();
289 return StoreResult(infoType, status.GetMakefile(), variable,
290 cm->GetState()->GetGlobalProperty(propertyName));
293 bool HandleDirectoryMode(cmExecutionStatus& status, const std::string& name,
294 OutType infoType, const std::string& variable,
295 const std::string& propertyName)
297 // Default to the current directory.
298 cmMakefile* mf = &status.GetMakefile();
300 // Lookup the directory if given.
302 // Construct the directory name. Interpret relative paths with
303 // respect to the current directory.
304 std::string dir = cmSystemTools::CollapseFullPath(
305 name, status.GetMakefile().GetCurrentSourceDirectory());
307 // Lookup the generator.
308 mf = status.GetMakefile().GetGlobalGenerator()->FindMakefile(dir);
310 // Could not find the directory.
312 "DIRECTORY scope provided but requested directory was not found. "
313 "This could be because the directory argument was invalid or, "
314 "it is valid but has not been processed yet.");
319 if (propertyName == "DEFINITIONS") {
320 switch (mf->GetPolicyStatus(cmPolicies::CMP0059)) {
321 case cmPolicies::WARN:
322 mf->IssueMessage(MessageType::AUTHOR_WARNING,
323 cmPolicies::GetPolicyWarning(cmPolicies::CMP0059));
325 case cmPolicies::OLD:
326 return StoreResult(infoType, status.GetMakefile(), variable,
327 mf->GetDefineFlagsCMP0059());
328 case cmPolicies::NEW:
329 case cmPolicies::REQUIRED_ALWAYS:
330 case cmPolicies::REQUIRED_IF_USED:
336 return StoreResult(infoType, status.GetMakefile(), variable,
337 mf->GetProperty(propertyName));
340 bool HandleTargetMode(cmExecutionStatus& status, const std::string& name,
341 OutType infoType, const std::string& variable,
342 const std::string& propertyName)
345 status.SetError("not given name for TARGET scope.");
349 if (cmTarget* target = status.GetMakefile().FindTargetToUse(name)) {
350 if (propertyName == "ALIASED_TARGET" || propertyName == "ALIAS_GLOBAL") {
351 if (status.GetMakefile().IsAlias(name)) {
352 if (propertyName == "ALIASED_TARGET") {
354 return StoreResult(infoType, status.GetMakefile(), variable,
355 target->GetName().c_str());
357 if (propertyName == "ALIAS_GLOBAL") {
359 infoType, status.GetMakefile(), variable,
360 status.GetMakefile().GetGlobalGenerator()->IsAlias(name)
365 return StoreResult(infoType, status.GetMakefile(), variable, nullptr);
368 target->GetComputedProperty(propertyName, status.GetMakefile());
370 prop = target->GetProperty(propertyName);
372 return StoreResult(infoType, status.GetMakefile(), variable, prop);
374 status.SetError(cmStrCat("could not find TARGET ", name,
375 ". Perhaps it has not yet been created."));
379 bool HandleSourceMode(cmExecutionStatus& status, const std::string& name,
380 OutType infoType, const std::string& variable,
381 const std::string& propertyName,
382 cmMakefile& directory_makefile,
383 const bool source_file_paths_should_be_absolute)
386 status.SetError("not given name for SOURCE scope.");
390 // Get the source file.
391 const std::string source_file_absolute_path =
392 SetPropertyCommand::MakeSourceFilePathAbsoluteIfNeeded(
393 status, name, source_file_paths_should_be_absolute);
394 if (cmSourceFile* sf =
395 directory_makefile.GetOrCreateSource(source_file_absolute_path)) {
396 return StoreResult(infoType, status.GetMakefile(), variable,
397 sf->GetPropertyForUser(propertyName));
400 cmStrCat("given SOURCE name that could not be found or created: ",
401 source_file_absolute_path));
405 bool HandleTestMode(cmExecutionStatus& status, const std::string& name,
406 OutType infoType, const std::string& variable,
407 const std::string& propertyName)
410 status.SetError("not given name for TEST scope.");
414 // Loop over all tests looking for matching names.
415 if (cmTest* test = status.GetMakefile().GetTest(name)) {
416 return StoreResult(infoType, status.GetMakefile(), variable,
417 test->GetProperty(propertyName));
420 // If not found it is an error.
421 status.SetError(cmStrCat("given TEST name that does not exist: ", name));
425 bool HandleVariableMode(cmExecutionStatus& status, const std::string& name,
426 OutType infoType, const std::string& variable,
427 const std::string& propertyName)
430 status.SetError("given name for VARIABLE scope.");
434 return StoreResult(infoType, status.GetMakefile(), variable,
435 status.GetMakefile().GetDefinition(propertyName));
438 bool HandleCacheMode(cmExecutionStatus& status, const std::string& name,
439 OutType infoType, const std::string& variable,
440 const std::string& propertyName)
443 status.SetError("not given name for CACHE scope.");
447 cmValue value = nullptr;
448 if (status.GetMakefile().GetState()->GetCacheEntryValue(name)) {
449 value = status.GetMakefile().GetState()->GetCacheEntryProperty(
452 StoreResult(infoType, status.GetMakefile(), variable, value);
456 bool HandleInstallMode(cmExecutionStatus& status, const std::string& name,
457 OutType infoType, const std::string& variable,
458 const std::string& propertyName)
461 status.SetError("not given name for INSTALL scope.");
465 // Get the installed file.
466 cmake* cm = status.GetMakefile().GetCMakeInstance();
468 if (cmInstalledFile* file =
469 cm->GetOrCreateInstalledFile(&status.GetMakefile(), name)) {
471 bool isSet = file->GetProperty(propertyName, value);
473 return StoreResult(infoType, status.GetMakefile(), variable,
474 isSet ? value.c_str() : nullptr);
477 cmStrCat("given INSTALL name that could not be found or created: ", name));