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 "cmSetPropertyCommand.h"
4
5 #include <set>
6 #include <sstream>
7 #include <unordered_set>
8
9 #include "cmExecutionStatus.h"
10 #include "cmGlobalGenerator.h"
11 #include "cmInstalledFile.h"
12 #include "cmMakefile.h"
13 #include "cmMessageType.h"
14 #include "cmPolicies.h"
15 #include "cmProperty.h"
16 #include "cmRange.h"
17 #include "cmSourceFile.h"
18 #include "cmSourceFileLocation.h"
19 #include "cmState.h"
20 #include "cmStringAlgorithms.h"
21 #include "cmSystemTools.h"
22 #include "cmTarget.h"
23 #include "cmTest.h"
24 #include "cmValue.h"
25 #include "cmake.h"
26
27 namespace {
28 bool HandleGlobalMode(cmExecutionStatus& status,
29 const std::set<std::string>& names,
30 const std::string& propertyName,
31 const std::string& propertyValue, bool appendAsString,
32 bool appendMode, bool remove);
33 bool HandleDirectoryMode(cmExecutionStatus& status,
34 const std::set<std::string>& names,
35 const std::string& propertyName,
36 const std::string& propertyValue, bool appendAsString,
37 bool appendMode, bool remove);
38 bool HandleTargetMode(cmExecutionStatus& status,
39 const std::set<std::string>& names,
40 const std::string& propertyName,
41 const std::string& propertyValue, bool appendAsString,
42 bool appendMode, bool remove);
43 bool HandleTarget(cmTarget* target, cmMakefile& makefile,
44 const std::string& propertyName,
45 const std::string& propertyValue, bool appendAsString,
46 bool appendMode, bool remove);
47 bool HandleSourceMode(cmExecutionStatus& status,
48 const std::set<std::string>& names,
49 const std::string& propertyName,
50 const std::string& propertyValue, bool appendAsString,
51 bool appendMode, bool remove,
52 const std::vector<cmMakefile*>& directory_makefiles,
53 bool source_file_paths_should_be_absolute);
54 bool HandleSource(cmSourceFile* sf, const std::string& propertyName,
55 const std::string& propertyValue, bool appendAsString,
56 bool appendMode, bool remove);
57 bool HandleTestMode(cmExecutionStatus& status, std::set<std::string>& names,
58 const std::string& propertyName,
59 const std::string& propertyValue, bool appendAsString,
60 bool appendMode, bool remove);
61 bool HandleTest(cmTest* test, const std::string& propertyName,
62 const std::string& propertyValue, bool appendAsString,
63 bool appendMode, bool remove);
64 bool HandleCacheMode(cmExecutionStatus& status,
65 const std::set<std::string>& names,
66 const std::string& propertyName,
67 const std::string& propertyValue, bool appendAsString,
68 bool appendMode, bool remove);
69 bool HandleCacheEntry(std::string const& cacheKey, const cmMakefile& makefile,
70 const std::string& propertyName,
71 const std::string& propertyValue, bool appendAsString,
72 bool appendMode, bool remove);
73 bool HandleInstallMode(cmExecutionStatus& status,
74 const std::set<std::string>& names,
75 const std::string& propertyName,
76 const std::string& propertyValue, bool appendAsString,
77 bool appendMode, bool remove);
78 bool HandleInstall(cmInstalledFile* file, cmMakefile& makefile,
79 const std::string& propertyName,
80 const std::string& propertyValue, bool appendAsString,
81 bool appendMode, bool remove);
82 }
83
84 namespace SetPropertyCommand {
HandleSourceFileDirectoryScopes(cmExecutionStatus & status,std::vector<std::string> & source_file_directories,std::vector<std::string> & source_file_target_directories,std::vector<cmMakefile * > & directory_makefiles)85 bool HandleSourceFileDirectoryScopes(
86 cmExecutionStatus& status, std::vector<std::string>& source_file_directories,
87 std::vector<std::string>& source_file_target_directories,
88 std::vector<cmMakefile*>& directory_makefiles)
89 {
90 std::unordered_set<cmMakefile*> directory_makefiles_set;
91
92 cmMakefile* current_dir_mf = &status.GetMakefile();
93 if (!source_file_directories.empty()) {
94 for (const std::string& dir_path : source_file_directories) {
95 const std::string absolute_dir_path = cmSystemTools::CollapseFullPath(
96 dir_path, current_dir_mf->GetCurrentSourceDirectory());
97 cmMakefile* dir_mf =
98 status.GetMakefile().GetGlobalGenerator()->FindMakefile(
99 absolute_dir_path);
100 if (!dir_mf) {
101 status.SetError(cmStrCat("given non-existent DIRECTORY ", dir_path));
102 return false;
103 }
104 if (directory_makefiles_set.find(dir_mf) ==
105 directory_makefiles_set.end()) {
106 directory_makefiles.push_back(dir_mf);
107 directory_makefiles_set.insert(dir_mf);
108 }
109 }
110 }
111
112 if (!source_file_target_directories.empty()) {
113 for (const std::string& target_name : source_file_target_directories) {
114 cmTarget* target = current_dir_mf->FindTargetToUse(target_name);
115 if (!target) {
116 status.SetError(cmStrCat(
117 "given non-existent target for TARGET_DIRECTORY ", target_name));
118 return false;
119 }
120 cmValue target_source_dir = target->GetProperty("BINARY_DIR");
121 cmMakefile* target_dir_mf =
122 status.GetMakefile().GetGlobalGenerator()->FindMakefile(
123 *target_source_dir);
124
125 if (directory_makefiles_set.find(target_dir_mf) ==
126 directory_makefiles_set.end()) {
127 directory_makefiles.push_back(target_dir_mf);
128 directory_makefiles_set.insert(target_dir_mf);
129 }
130 }
131 }
132
133 if (source_file_directories.empty() &&
134 source_file_target_directories.empty()) {
135 directory_makefiles.push_back(current_dir_mf);
136 }
137 return true;
138 }
139
HandleSourceFileDirectoryScopeValidation(cmExecutionStatus & status,bool source_file_directory_option_enabled,bool source_file_target_option_enabled,std::vector<std::string> & source_file_directories,std::vector<std::string> & source_file_target_directories)140 bool HandleSourceFileDirectoryScopeValidation(
141 cmExecutionStatus& status, bool source_file_directory_option_enabled,
142 bool source_file_target_option_enabled,
143 std::vector<std::string>& source_file_directories,
144 std::vector<std::string>& source_file_target_directories)
145 {
146 // Validate source file directory scopes.
147 if (source_file_directory_option_enabled &&
148 source_file_directories.empty()) {
149 std::string errors = "called with incorrect number of arguments "
150 "no value provided to the DIRECTORY option";
151 status.SetError(errors);
152 return false;
153 }
154 if (source_file_target_option_enabled &&
155 source_file_target_directories.empty()) {
156 std::string errors = "called with incorrect number of arguments "
157 "no value provided to the TARGET_DIRECTORY option";
158 status.SetError(errors);
159 return false;
160 }
161 return true;
162 }
163
HandleAndValidateSourceFileDirectoryScopes(cmExecutionStatus & status,bool source_file_directory_option_enabled,bool source_file_target_option_enabled,std::vector<std::string> & source_file_directories,std::vector<std::string> & source_file_target_directories,std::vector<cmMakefile * > & source_file_directory_makefiles)164 bool HandleAndValidateSourceFileDirectoryScopes(
165 cmExecutionStatus& status, bool source_file_directory_option_enabled,
166 bool source_file_target_option_enabled,
167 std::vector<std::string>& source_file_directories,
168 std::vector<std::string>& source_file_target_directories,
169 std::vector<cmMakefile*>& source_file_directory_makefiles)
170 {
171 bool scope_options_valid =
172 SetPropertyCommand::HandleSourceFileDirectoryScopeValidation(
173 status, source_file_directory_option_enabled,
174 source_file_target_option_enabled, source_file_directories,
175 source_file_target_directories);
176 if (!scope_options_valid) {
177 return false;
178 }
179
180 scope_options_valid = SetPropertyCommand::HandleSourceFileDirectoryScopes(
181 status, source_file_directories, source_file_target_directories,
182 source_file_directory_makefiles);
183 return scope_options_valid;
184 }
185
MakeSourceFilePathAbsoluteIfNeeded(cmExecutionStatus & status,const std::string & source_file_path,const bool needed)186 std::string MakeSourceFilePathAbsoluteIfNeeded(
187 cmExecutionStatus& status, const std::string& source_file_path,
188 const bool needed)
189 {
190 if (!needed) {
191 return source_file_path;
192 }
193 std::string absolute_file_path = cmSystemTools::CollapseFullPath(
194 source_file_path, status.GetMakefile().GetCurrentSourceDirectory());
195 return absolute_file_path;
196 }
197
MakeSourceFilePathsAbsoluteIfNeeded(cmExecutionStatus & status,std::vector<std::string> & source_files_absolute_paths,std::vector<std::string>::const_iterator files_it_begin,std::vector<std::string>::const_iterator files_it_end,const bool needed)198 void MakeSourceFilePathsAbsoluteIfNeeded(
199 cmExecutionStatus& status,
200 std::vector<std::string>& source_files_absolute_paths,
201 std::vector<std::string>::const_iterator files_it_begin,
202 std::vector<std::string>::const_iterator files_it_end, const bool needed)
203 {
204
205 // Make the file paths absolute, so that relative source file paths are
206 // picked up relative to the command calling site, regardless of the
207 // directory scope.
208 std::vector<std::string>::difference_type num_files =
209 files_it_end - files_it_begin;
210 source_files_absolute_paths.reserve(num_files);
211
212 if (!needed) {
213 source_files_absolute_paths.assign(files_it_begin, files_it_end);
214 return;
215 }
216
217 for (; files_it_begin != files_it_end; ++files_it_begin) {
218 const std::string absolute_file_path =
219 MakeSourceFilePathAbsoluteIfNeeded(status, *files_it_begin, true);
220 source_files_absolute_paths.push_back(absolute_file_path);
221 }
222 }
223
HandleAndValidateSourceFilePropertyGENERATED(cmSourceFile * sf,std::string const & propertyValue,PropertyOp op)224 bool HandleAndValidateSourceFilePropertyGENERATED(
225 cmSourceFile* sf, std::string const& propertyValue, PropertyOp op)
226 {
227 const auto& mf = *sf->GetLocation().GetMakefile();
228 auto policyStatus = mf.GetPolicyStatus(cmPolicies::CMP0118);
229
230 const bool policyWARN = policyStatus == cmPolicies::WARN;
231 const bool policyNEW = policyStatus != cmPolicies::OLD && !policyWARN;
232
233 if (policyWARN) {
234 if (!cmIsOn(propertyValue) && !cmIsOff(propertyValue)) {
235 mf.IssueMessage(
236 MessageType::AUTHOR_WARNING,
237 cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0118),
238 "\nAttempt to set property 'GENERATED' with the following "
239 "non-boolean value (which will be interpreted as \"0\"):\n",
240 propertyValue,
241 "\nThat exact value will not be retrievable. A value of "
242 "\"0\" will be returned instead.\n"
243 "This will be an error under policy CMP0118.\n"));
244 }
245 if (cmIsOff(propertyValue)) {
246 mf.IssueMessage(
247 MessageType::AUTHOR_WARNING,
248 cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0118),
249 "\nUnsetting property 'GENERATED' will not be allowed under "
250 "policy CMP0118!\n"));
251 }
252 if (op == PropertyOp::Append || op == PropertyOp::AppendAsString) {
253 mf.IssueMessage(
254 MessageType::AUTHOR_WARNING,
255 cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0118),
256 "\nAppending to property 'GENERATED' will not be allowed "
257 "under policy CMP0118!\n"));
258 }
259 } else if (policyNEW) {
260 if (!cmIsOn(propertyValue) && !cmIsOff(propertyValue)) {
261 mf.IssueMessage(
262 MessageType::AUTHOR_ERROR,
263 cmStrCat(
264 "Policy CMP0118 is set to NEW and the following non-boolean value "
265 "given for property 'GENERATED' is therefore not allowed:\n",
266 propertyValue, "\nReplace it with a boolean value!\n"));
267 return true;
268 }
269 if (cmIsOff(propertyValue)) {
270 mf.IssueMessage(
271 MessageType::AUTHOR_ERROR,
272 "Unsetting the 'GENERATED' property is not allowed under CMP0118!\n");
273 return true;
274 }
275 if (op == PropertyOp::Append || op == PropertyOp::AppendAsString) {
276 mf.IssueMessage(MessageType::AUTHOR_ERROR,
277 "Policy CMP0118 is set to NEW and appending to the "
278 "'GENERATED' property is therefore not allowed. Only "
279 "setting it to \"1\" is allowed!\n");
280 return true;
281 }
282 }
283
284 // Set property.
285 if (!policyNEW) {
286 // Do it the traditional way.
287 switch (op) {
288 case PropertyOp::Append:
289 sf->AppendProperty("GENERATED", propertyValue, false);
290 break;
291 case PropertyOp::AppendAsString:
292 sf->AppendProperty("GENERATED", propertyValue, true);
293 break;
294 case PropertyOp::Remove:
295 sf->SetProperty("GENERATED", nullptr);
296 break;
297 case PropertyOp::Set:
298 sf->SetProperty("GENERATED", propertyValue);
299 break;
300 }
301 } else {
302 sf->MarkAsGenerated();
303 }
304 return true;
305 }
306
307 } // END: namespace SetPropertyCommand
308
cmSetPropertyCommand(std::vector<std::string> const & args,cmExecutionStatus & status)309 bool cmSetPropertyCommand(std::vector<std::string> const& args,
310 cmExecutionStatus& status)
311 {
312 if (args.size() < 2) {
313 status.SetError("called with incorrect number of arguments");
314 return false;
315 }
316
317 // Get the scope on which to set the property.
318 std::string const& scopeName = args.front();
319 cmProperty::ScopeType scope;
320 if (scopeName == "GLOBAL") {
321 scope = cmProperty::GLOBAL;
322 } else if (scopeName == "DIRECTORY") {
323 scope = cmProperty::DIRECTORY;
324 } else if (scopeName == "TARGET") {
325 scope = cmProperty::TARGET;
326 } else if (scopeName == "SOURCE") {
327 scope = cmProperty::SOURCE_FILE;
328 } else if (scopeName == "TEST") {
329 scope = cmProperty::TEST;
330 } else if (scopeName == "CACHE") {
331 scope = cmProperty::CACHE;
332 } else if (scopeName == "INSTALL") {
333 scope = cmProperty::INSTALL;
334 } else {
335 status.SetError(cmStrCat("given invalid scope ", scopeName,
336 ". "
337 "Valid scopes are GLOBAL, DIRECTORY, "
338 "TARGET, SOURCE, TEST, CACHE, INSTALL."));
339 return false;
340 }
341
342 bool appendAsString = false;
343 bool appendMode = false;
344 bool remove = true;
345 std::set<std::string> names;
346 std::string propertyName;
347 std::string propertyValue;
348
349 std::vector<std::string> source_file_directories;
350 std::vector<std::string> source_file_target_directories;
351 bool source_file_directory_option_enabled = false;
352 bool source_file_target_option_enabled = false;
353
354 // Parse the rest of the arguments up to the values.
355 enum Doing
356 {
357 DoingNone,
358 DoingNames,
359 DoingProperty,
360 DoingValues,
361 DoingSourceDirectory,
362 DoingSourceTargetDirectory
363 };
364 Doing doing = DoingNames;
365 const char* sep = "";
366 for (std::string const& arg : cmMakeRange(args).advance(1)) {
367 if (arg == "PROPERTY") {
368 doing = DoingProperty;
369 } else if (arg == "APPEND") {
370 doing = DoingNone;
371 appendMode = true;
372 remove = false;
373 appendAsString = false;
374 } else if (arg == "APPEND_STRING") {
375 doing = DoingNone;
376 appendMode = true;
377 remove = false;
378 appendAsString = true;
379 } else if (doing != DoingProperty && doing != DoingValues &&
380 scope == cmProperty::SOURCE_FILE && arg == "DIRECTORY") {
381 doing = DoingSourceDirectory;
382 source_file_directory_option_enabled = true;
383 } else if (doing != DoingProperty && doing != DoingValues &&
384 scope == cmProperty::SOURCE_FILE && arg == "TARGET_DIRECTORY") {
385 doing = DoingSourceTargetDirectory;
386 source_file_target_option_enabled = true;
387 } else if (doing == DoingNames) {
388 names.insert(arg);
389 } else if (doing == DoingSourceDirectory) {
390 source_file_directories.push_back(arg);
391 } else if (doing == DoingSourceTargetDirectory) {
392 source_file_target_directories.push_back(arg);
393 } else if (doing == DoingProperty) {
394 propertyName = arg;
395 doing = DoingValues;
396 } else if (doing == DoingValues) {
397 propertyValue += sep;
398 sep = ";";
399 propertyValue += arg;
400 remove = false;
401 } else {
402 status.SetError(cmStrCat("given invalid argument \"", arg, "\"."));
403 return false;
404 }
405 }
406
407 // Make sure a property name was found.
408 if (propertyName.empty()) {
409 status.SetError("not given a PROPERTY <name> argument.");
410 return false;
411 }
412
413 std::vector<cmMakefile*> source_file_directory_makefiles;
414 bool file_scopes_handled =
415 SetPropertyCommand::HandleAndValidateSourceFileDirectoryScopes(
416 status, source_file_directory_option_enabled,
417 source_file_target_option_enabled, source_file_directories,
418 source_file_target_directories, source_file_directory_makefiles);
419 if (!file_scopes_handled) {
420 return false;
421 }
422 bool source_file_paths_should_be_absolute =
423 source_file_directory_option_enabled || source_file_target_option_enabled;
424
425 // Dispatch property setting.
426 switch (scope) {
427 case cmProperty::GLOBAL:
428 return HandleGlobalMode(status, names, propertyName, propertyValue,
429 appendAsString, appendMode, remove);
430 case cmProperty::DIRECTORY:
431 return HandleDirectoryMode(status, names, propertyName, propertyValue,
432 appendAsString, appendMode, remove);
433 case cmProperty::TARGET:
434 return HandleTargetMode(status, names, propertyName, propertyValue,
435 appendAsString, appendMode, remove);
436 case cmProperty::SOURCE_FILE:
437 return HandleSourceMode(status, names, propertyName, propertyValue,
438 appendAsString, appendMode, remove,
439 source_file_directory_makefiles,
440 source_file_paths_should_be_absolute);
441 case cmProperty::TEST:
442 return HandleTestMode(status, names, propertyName, propertyValue,
443 appendAsString, appendMode, remove);
444 case cmProperty::CACHE:
445 return HandleCacheMode(status, names, propertyName, propertyValue,
446 appendAsString, appendMode, remove);
447 case cmProperty::INSTALL:
448 return HandleInstallMode(status, names, propertyName, propertyValue,
449 appendAsString, appendMode, remove);
450
451 case cmProperty::VARIABLE:
452 case cmProperty::CACHED_VARIABLE:
453 break; // should never happen
454 }
455 return true;
456 }
457
458 namespace /* anonymous */ {
HandleGlobalMode(cmExecutionStatus & status,const std::set<std::string> & names,const std::string & propertyName,const std::string & propertyValue,bool appendAsString,bool appendMode,bool remove)459 bool HandleGlobalMode(cmExecutionStatus& status,
460 const std::set<std::string>& names,
461 const std::string& propertyName,
462 const std::string& propertyValue, bool appendAsString,
463 bool appendMode, bool remove)
464 {
465 if (!names.empty()) {
466 status.SetError("given names for GLOBAL scope.");
467 return false;
468 }
469
470 // Set or append the property.
471 cmake* cm = status.GetMakefile().GetCMakeInstance();
472 if (appendMode) {
473 cm->AppendProperty(propertyName, propertyValue, appendAsString);
474 } else {
475 if (remove) {
476 cm->SetProperty(propertyName, nullptr);
477 } else {
478 cm->SetProperty(propertyName, propertyValue);
479 }
480 }
481
482 return true;
483 }
484
HandleDirectoryMode(cmExecutionStatus & status,const std::set<std::string> & names,const std::string & propertyName,const std::string & propertyValue,bool appendAsString,bool appendMode,bool remove)485 bool HandleDirectoryMode(cmExecutionStatus& status,
486 const std::set<std::string>& names,
487 const std::string& propertyName,
488 const std::string& propertyValue, bool appendAsString,
489 bool appendMode, bool remove)
490 {
491 if (names.size() > 1) {
492 status.SetError("allows at most one name for DIRECTORY scope.");
493 return false;
494 }
495
496 // Default to the current directory.
497 cmMakefile* mf = &status.GetMakefile();
498
499 // Lookup the directory if given.
500 if (!names.empty()) {
501 // Construct the directory name. Interpret relative paths with
502 // respect to the current directory.
503 std::string dir = cmSystemTools::CollapseFullPath(
504 *names.begin(), status.GetMakefile().GetCurrentSourceDirectory());
505
506 mf = status.GetMakefile().GetGlobalGenerator()->FindMakefile(dir);
507 if (!mf) {
508 // Could not find the directory.
509 status.SetError(
510 "DIRECTORY scope provided but requested directory was not found. "
511 "This could be because the directory argument was invalid or, "
512 "it is valid but has not been processed yet.");
513 return false;
514 }
515 }
516
517 // Set or append the property.
518 if (appendMode) {
519 mf->AppendProperty(propertyName, propertyValue, appendAsString);
520 } else {
521 if (remove) {
522 mf->SetProperty(propertyName, nullptr);
523 } else {
524 mf->SetProperty(propertyName, propertyValue);
525 }
526 }
527
528 return true;
529 }
530
HandleTargetMode(cmExecutionStatus & status,const std::set<std::string> & names,const std::string & propertyName,const std::string & propertyValue,bool appendAsString,bool appendMode,bool remove)531 bool HandleTargetMode(cmExecutionStatus& status,
532 const std::set<std::string>& names,
533 const std::string& propertyName,
534 const std::string& propertyValue, bool appendAsString,
535 bool appendMode, bool remove)
536 {
537 for (std::string const& name : names) {
538 if (status.GetMakefile().IsAlias(name)) {
539 status.SetError("can not be used on an ALIAS target.");
540 return false;
541 }
542 if (cmTarget* target = status.GetMakefile().FindTargetToUse(name)) {
543 // Handle the current target.
544 if (!HandleTarget(target, status.GetMakefile(), propertyName,
545 propertyValue, appendAsString, appendMode, remove)) {
546 return false;
547 }
548 } else {
549 status.SetError(cmStrCat("could not find TARGET ", name,
550 ". Perhaps it has not yet been created."));
551 return false;
552 }
553 }
554 return true;
555 }
556
HandleTarget(cmTarget * target,cmMakefile & makefile,const std::string & propertyName,const std::string & propertyValue,bool appendAsString,bool appendMode,bool remove)557 bool HandleTarget(cmTarget* target, cmMakefile& makefile,
558 const std::string& propertyName,
559 const std::string& propertyValue, bool appendAsString,
560 bool appendMode, bool remove)
561 {
562 // Set or append the property.
563 if (appendMode) {
564 target->AppendProperty(propertyName, propertyValue, appendAsString);
565 } else {
566 if (remove) {
567 target->SetProperty(propertyName, nullptr);
568 } else {
569 target->SetProperty(propertyName, propertyValue);
570 }
571 }
572
573 // Check the resulting value.
574 target->CheckProperty(propertyName, &makefile);
575
576 return true;
577 }
578
HandleSourceMode(cmExecutionStatus & status,const std::set<std::string> & names,const std::string & propertyName,const std::string & propertyValue,bool appendAsString,bool appendMode,bool remove,const std::vector<cmMakefile * > & directory_makefiles,const bool source_file_paths_should_be_absolute)579 bool HandleSourceMode(cmExecutionStatus& status,
580 const std::set<std::string>& names,
581 const std::string& propertyName,
582 const std::string& propertyValue, bool appendAsString,
583 bool appendMode, bool remove,
584 const std::vector<cmMakefile*>& directory_makefiles,
585 const bool source_file_paths_should_be_absolute)
586 {
587 std::vector<std::string> files_absolute;
588 std::vector<std::string> unique_files(names.begin(), names.end());
589 SetPropertyCommand::MakeSourceFilePathsAbsoluteIfNeeded(
590 status, files_absolute, unique_files.begin(), unique_files.end(),
591 source_file_paths_should_be_absolute);
592
593 for (auto* const mf : directory_makefiles) {
594 for (std::string const& name : files_absolute) {
595 // Get the source file.
596 if (cmSourceFile* sf = mf->GetOrCreateSource(name)) {
597 if (!HandleSource(sf, propertyName, propertyValue, appendAsString,
598 appendMode, remove)) {
599 return false;
600 }
601 } else {
602 status.SetError(cmStrCat(
603 "given SOURCE name that could not be found or created: ", name));
604 return false;
605 }
606 }
607 }
608
609 return true;
610 }
611
HandleSource(cmSourceFile * sf,const std::string & propertyName,const std::string & propertyValue,bool appendAsString,bool appendMode,bool remove)612 bool HandleSource(cmSourceFile* sf, const std::string& propertyName,
613 const std::string& propertyValue, bool appendAsString,
614 bool appendMode, bool remove)
615 {
616 // Special validation and handling of GENERATED flag?
617 if (propertyName == "GENERATED") {
618 SetPropertyCommand::PropertyOp op = (remove)
619 ? SetPropertyCommand::PropertyOp::Remove
620 : (appendAsString)
621 ? SetPropertyCommand::PropertyOp::AppendAsString
622 : (appendMode) ? SetPropertyCommand::PropertyOp::Append
623 : SetPropertyCommand::PropertyOp::Set;
624 return SetPropertyCommand::HandleAndValidateSourceFilePropertyGENERATED(
625 sf, propertyValue, op);
626 }
627
628 // Set or append the property.
629 if (appendMode) {
630 sf->AppendProperty(propertyName, propertyValue, appendAsString);
631 } else {
632 if (remove) {
633 sf->SetProperty(propertyName, nullptr);
634 } else {
635 sf->SetProperty(propertyName, propertyValue);
636 }
637 }
638 return true;
639 }
640
HandleTestMode(cmExecutionStatus & status,std::set<std::string> & names,const std::string & propertyName,const std::string & propertyValue,bool appendAsString,bool appendMode,bool remove)641 bool HandleTestMode(cmExecutionStatus& status, std::set<std::string>& names,
642 const std::string& propertyName,
643 const std::string& propertyValue, bool appendAsString,
644 bool appendMode, bool remove)
645 {
646 // Look for tests with all names given.
647 std::set<std::string>::iterator next;
648 for (auto ni = names.begin(); ni != names.end(); ni = next) {
649 next = ni;
650 ++next;
651 if (cmTest* test = status.GetMakefile().GetTest(*ni)) {
652 if (HandleTest(test, propertyName, propertyValue, appendAsString,
653 appendMode, remove)) {
654 names.erase(ni);
655 } else {
656 return false;
657 }
658 }
659 }
660
661 // Names that are still left were not found.
662 if (!names.empty()) {
663 std::ostringstream e;
664 e << "given TEST names that do not exist:\n";
665 for (std::string const& name : names) {
666 e << " " << name << "\n";
667 }
668 status.SetError(e.str());
669 return false;
670 }
671 return true;
672 }
673
HandleTest(cmTest * test,const std::string & propertyName,const std::string & propertyValue,bool appendAsString,bool appendMode,bool remove)674 bool HandleTest(cmTest* test, const std::string& propertyName,
675 const std::string& propertyValue, bool appendAsString,
676 bool appendMode, bool remove)
677 {
678 // Set or append the property.
679 if (appendMode) {
680 test->AppendProperty(propertyName, propertyValue, appendAsString);
681 } else {
682 if (remove) {
683 test->SetProperty(propertyName, nullptr);
684 } else {
685 test->SetProperty(propertyName, propertyValue);
686 }
687 }
688
689 return true;
690 }
691
HandleCacheMode(cmExecutionStatus & status,const std::set<std::string> & names,const std::string & propertyName,const std::string & propertyValue,bool appendAsString,bool appendMode,bool remove)692 bool HandleCacheMode(cmExecutionStatus& status,
693 const std::set<std::string>& names,
694 const std::string& propertyName,
695 const std::string& propertyValue, bool appendAsString,
696 bool appendMode, bool remove)
697 {
698 if (propertyName == "ADVANCED") {
699 if (!remove && !cmIsOn(propertyValue) && !cmIsOff(propertyValue)) {
700 status.SetError(cmStrCat("given non-boolean value \"", propertyValue,
701 R"(" for CACHE property "ADVANCED". )"));
702 return false;
703 }
704 } else if (propertyName == "TYPE") {
705 if (!cmState::IsCacheEntryType(propertyValue)) {
706 status.SetError(
707 cmStrCat("given invalid CACHE entry TYPE \"", propertyValue, "\""));
708 return false;
709 }
710 } else if (propertyName != "HELPSTRING" && propertyName != "STRINGS" &&
711 propertyName != "VALUE") {
712 status.SetError(
713 cmStrCat("given invalid CACHE property ", propertyName,
714 ". "
715 "Settable CACHE properties are: "
716 "ADVANCED, HELPSTRING, STRINGS, TYPE, and VALUE."));
717 return false;
718 }
719
720 for (std::string const& name : names) {
721 // Get the source file.
722 cmake* cm = status.GetMakefile().GetCMakeInstance();
723 cmValue existingValue = cm->GetState()->GetCacheEntryValue(name);
724 if (existingValue) {
725 if (!HandleCacheEntry(name, status.GetMakefile(), propertyName,
726 propertyValue, appendAsString, appendMode,
727 remove)) {
728 return false;
729 }
730 } else {
731 status.SetError(cmStrCat("could not find CACHE variable ", name,
732 ". Perhaps it has not yet been created."));
733 return false;
734 }
735 }
736 return true;
737 }
738
HandleCacheEntry(std::string const & cacheKey,const cmMakefile & makefile,const std::string & propertyName,const std::string & propertyValue,bool appendAsString,bool appendMode,bool remove)739 bool HandleCacheEntry(std::string const& cacheKey, const cmMakefile& makefile,
740 const std::string& propertyName,
741 const std::string& propertyValue, bool appendAsString,
742 bool appendMode, bool remove)
743 {
744 // Set or append the property.
745 cmState* state = makefile.GetState();
746 if (remove) {
747 state->RemoveCacheEntryProperty(cacheKey, propertyName);
748 }
749 if (appendMode) {
750 state->AppendCacheEntryProperty(cacheKey, propertyName, propertyValue,
751 appendAsString);
752 } else {
753 state->SetCacheEntryProperty(cacheKey, propertyName, propertyValue);
754 }
755
756 return true;
757 }
758
HandleInstallMode(cmExecutionStatus & status,const std::set<std::string> & names,const std::string & propertyName,const std::string & propertyValue,bool appendAsString,bool appendMode,bool remove)759 bool HandleInstallMode(cmExecutionStatus& status,
760 const std::set<std::string>& names,
761 const std::string& propertyName,
762 const std::string& propertyValue, bool appendAsString,
763 bool appendMode, bool remove)
764 {
765 cmake* cm = status.GetMakefile().GetCMakeInstance();
766
767 for (std::string const& name : names) {
768 if (cmInstalledFile* file =
769 cm->GetOrCreateInstalledFile(&status.GetMakefile(), name)) {
770 if (!HandleInstall(file, status.GetMakefile(), propertyName,
771 propertyValue, appendAsString, appendMode, remove)) {
772 return false;
773 }
774 } else {
775 status.SetError(cmStrCat(
776 "given INSTALL name that could not be found or created: ", name));
777 return false;
778 }
779 }
780 return true;
781 }
782
HandleInstall(cmInstalledFile * file,cmMakefile & makefile,const std::string & propertyName,const std::string & propertyValue,bool appendAsString,bool appendMode,bool remove)783 bool HandleInstall(cmInstalledFile* file, cmMakefile& makefile,
784 const std::string& propertyName,
785 const std::string& propertyValue, bool appendAsString,
786 bool appendMode, bool remove)
787 {
788 // Set or append the property.
789 if (remove) {
790 file->RemoveProperty(propertyName);
791 } else if (appendMode) {
792 file->AppendProperty(&makefile, propertyName, propertyValue,
793 appendAsString);
794 } else {
795 file->SetProperty(&makefile, propertyName, propertyValue);
796 }
797 return true;
798 }
799 }
800