Coverage Report

Created: 2026-10-28 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmSetPropertyCommand.cxx
Line
Count
Source
1
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2
   file LICENSE.rst or https://cmake.org/licensing for details.  */
3
#include "cmSetPropertyCommand.h"
4
5
#include <set>
6
#include <unordered_set>
7
8
#include <cm/optional>
9
#include <cm/string_view>
10
#include <cmext/string_view>
11
12
#include "cmDiagnostics.h"
13
#include "cmExecutionStatus.h"
14
#include "cmFileSet.h"
15
#include "cmGlobalGenerator.h"
16
#include "cmInstalledFile.h"
17
#include "cmListFileCache.h"
18
#include "cmMakefile.h"
19
#include "cmPolicies.h"
20
#include "cmProperty.h"
21
#include "cmRange.h"
22
#include "cmRule.h"
23
#include "cmSourceFile.h"
24
#include "cmSourceFileLocation.h"
25
#include "cmState.h"
26
#include "cmStringAlgorithms.h"
27
#include "cmSystemTools.h"
28
#include "cmTarget.h"
29
#include "cmTest.h"
30
#include "cmValue.h"
31
#include "cmake.h"
32
33
namespace {
34
bool HandleGlobalMode(cmExecutionStatus& status,
35
                      std::set<std::string> const& names,
36
                      std::string const& propertyName,
37
                      std::string const& propertyValue, bool appendAsString,
38
                      bool appendMode, bool remove);
39
bool HandleDirectoryMode(cmExecutionStatus& status,
40
                         std::set<std::string> const& names,
41
                         std::string const& propertyName,
42
                         std::string const& propertyValue, bool appendAsString,
43
                         bool appendMode, bool remove);
44
bool HandleRuleMode(cmExecutionStatus& status,
45
                    std::set<std::string> const& names,
46
                    std::string const& propertyName,
47
                    std::string const& propertyValue, bool appendAsString,
48
                    bool appendMode, bool remove);
49
bool HandleTargetMode(cmExecutionStatus& status,
50
                      std::set<std::string> const& names,
51
                      std::string const& propertyName,
52
                      std::string const& propertyValue, bool appendAsString,
53
                      bool appendMode, bool remove);
54
bool HandleTarget(cmTarget* target, cmMakefile& makefile,
55
                  std::string const& propertyName,
56
                  std::string const& propertyValue, bool appendAsString,
57
                  bool appendMode, bool remove);
58
bool HandleFileSetMode(cmExecutionStatus& status,
59
                       std::set<std::string> const& names,
60
                       std::string const& propertyName,
61
                       std::string const& propertyValue, bool appendAsString,
62
                       bool appendMode, bool remove, cmTarget* target);
63
bool HandleFileSet(cmFileSet* fileSet, std::string const& propertyName,
64
                   std::string const& propertyValue, bool appendAsString,
65
                   bool appendMode, bool remove);
66
bool HandleSourceMode(cmExecutionStatus& status,
67
                      std::set<std::string> const& names,
68
                      std::string const& propertyName,
69
                      std::string const& propertyValue, bool appendAsString,
70
                      bool appendMode, bool remove,
71
                      std::vector<cmMakefile*> const& directory_makefiles,
72
                      bool source_file_paths_should_be_absolute);
73
bool HandleSource(cmSourceFile* sf, std::string const& propertyName,
74
                  std::string const& propertyValue, bool appendAsString,
75
                  bool appendMode, bool remove);
76
bool HandleTestMode(cmExecutionStatus& status, std::set<std::string>& names,
77
                    std::string const& propertyName,
78
                    std::string const& propertyValue, bool appendAsString,
79
                    bool appendMode, bool remove,
80
                    cmMakefile* test_directory_makefile);
81
bool HandleTest(cmTest* test, std::string const& propertyName,
82
                std::string const& propertyValue, bool appendAsString,
83
                bool appendMode, bool remove);
84
bool HandleCacheMode(cmExecutionStatus& status,
85
                     std::set<std::string> const& names,
86
                     std::string const& propertyName,
87
                     std::string const& propertyValue, bool appendAsString,
88
                     bool appendMode, bool remove);
89
bool HandleCacheEntry(std::string const& cacheKey, cmMakefile const& makefile,
90
                      std::string const& propertyName,
91
                      std::string const& propertyValue, bool appendAsString,
92
                      bool appendMode, bool remove);
93
bool HandleInstallMode(cmExecutionStatus& status,
94
                       std::set<std::string> const& names,
95
                       std::string const& propertyName,
96
                       std::string const& propertyValue, bool appendAsString,
97
                       bool appendMode, bool remove);
98
bool HandleInstall(cmInstalledFile* file, cmMakefile& makefile,
99
                   std::string const& propertyName,
100
                   std::string const& propertyValue, bool appendAsString,
101
                   bool appendMode, bool remove);
102
}
103
104
namespace SetPropertyCommand {
105
bool HandleFileSetTargetScopes(cmExecutionStatus& status,
106
                               std::string& file_set_target_name,
107
                               cmTarget*& file_set_target)
108
0
{
109
0
  file_set_target = status.GetMakefile().FindTargetToUse(file_set_target_name);
110
0
  if (!file_set_target) {
111
0
    status.SetError(
112
0
      cmStrCat("given non-existent TARGET ", file_set_target_name));
113
0
    return false;
114
0
  }
115
0
  return true;
116
0
}
117
118
bool HandleFileSetTargetScopeValidation(cmExecutionStatus& status,
119
                                        bool file_set_target_option_enabled,
120
                                        std::string& file_set_target_name)
121
0
{
122
0
  if (!file_set_target_option_enabled) {
123
0
    status.SetError("required TARGET option is missing");
124
0
    return false;
125
0
  }
126
127
  // Validate file set target scopes.
128
0
  if (file_set_target_name.empty()) {
129
0
    status.SetError("called with incorrect number of arguments "
130
0
                    "no value provided to the TARGET option");
131
0
    return false;
132
0
  }
133
0
  return true;
134
0
}
135
136
bool HandleAndValidateFileSetTargetScopes(cmExecutionStatus& status,
137
                                          bool file_set_target_option_enabled,
138
                                          std::string& file_set_target_name,
139
                                          cmTarget*& file_set_target)
140
0
{
141
0
  bool scope_options_valid =
142
0
    SetPropertyCommand::HandleFileSetTargetScopeValidation(
143
0
      status, file_set_target_option_enabled, file_set_target_name);
144
0
  if (!scope_options_valid) {
145
0
    return false;
146
0
  }
147
148
0
  scope_options_valid = SetPropertyCommand::HandleFileSetTargetScopes(
149
0
    status, file_set_target_name, file_set_target);
150
0
  return scope_options_valid;
151
0
}
152
153
bool HandleSourceFileDirectoryScopes(
154
  cmExecutionStatus& status, std::vector<std::string>& source_file_directories,
155
  std::vector<std::string>& source_file_target_directories,
156
  std::vector<cmMakefile*>& directory_makefiles)
157
5.92k
{
158
5.92k
  std::unordered_set<cmMakefile*> directory_makefiles_set;
159
160
5.92k
  cmMakefile* current_dir_mf = &status.GetMakefile();
161
5.92k
  if (!source_file_directories.empty()) {
162
0
    for (std::string const& dir_path : source_file_directories) {
163
0
      std::string const absolute_dir_path = cmSystemTools::CollapseFullPath(
164
0
        dir_path, current_dir_mf->GetCurrentSourceDirectory());
165
0
      cmMakefile* dir_mf =
166
0
        status.GetMakefile().GetGlobalGenerator()->FindMakefile(
167
0
          absolute_dir_path);
168
0
      if (!dir_mf) {
169
0
        status.SetError(cmStrCat("given non-existent DIRECTORY ", dir_path));
170
0
        return false;
171
0
      }
172
0
      if (directory_makefiles_set.find(dir_mf) ==
173
0
          directory_makefiles_set.end()) {
174
0
        directory_makefiles.push_back(dir_mf);
175
0
        directory_makefiles_set.insert(dir_mf);
176
0
      }
177
0
    }
178
0
  }
179
180
5.92k
  if (!source_file_target_directories.empty()) {
181
0
    for (std::string const& target_name : source_file_target_directories) {
182
0
      cmTarget* target = current_dir_mf->FindTargetToUse(target_name);
183
0
      if (!target) {
184
0
        status.SetError(cmStrCat(
185
0
          "given non-existent target for TARGET_DIRECTORY ", target_name));
186
0
        return false;
187
0
      }
188
0
      cmValue target_source_dir = target->GetProperty("BINARY_DIR");
189
0
      cmMakefile* target_dir_mf =
190
0
        status.GetMakefile().GetGlobalGenerator()->FindMakefile(
191
0
          *target_source_dir);
192
193
0
      if (directory_makefiles_set.find(target_dir_mf) ==
194
0
          directory_makefiles_set.end()) {
195
0
        directory_makefiles.push_back(target_dir_mf);
196
0
        directory_makefiles_set.insert(target_dir_mf);
197
0
      }
198
0
    }
199
0
  }
200
201
5.92k
  if (source_file_directories.empty() &&
202
5.92k
      source_file_target_directories.empty()) {
203
5.92k
    directory_makefiles.push_back(current_dir_mf);
204
5.92k
  }
205
5.92k
  return true;
206
5.92k
}
207
208
bool HandleSourceFileDirectoryScopeValidation(
209
  cmExecutionStatus& status, bool source_file_directory_option_enabled,
210
  bool source_file_target_option_enabled,
211
  std::vector<std::string>& source_file_directories,
212
  std::vector<std::string>& source_file_target_directories)
213
5.92k
{
214
  // Validate source file directory scopes.
215
5.92k
  if (source_file_directory_option_enabled &&
216
0
      source_file_directories.empty()) {
217
0
    std::string errors = "called with incorrect number of arguments "
218
0
                         "no value provided to the DIRECTORY option";
219
0
    status.SetError(errors);
220
0
    return false;
221
0
  }
222
5.92k
  if (source_file_target_option_enabled &&
223
0
      source_file_target_directories.empty()) {
224
0
    std::string errors = "called with incorrect number of arguments "
225
0
                         "no value provided to the TARGET_DIRECTORY option";
226
0
    status.SetError(errors);
227
0
    return false;
228
0
  }
229
5.92k
  return true;
230
5.92k
}
231
232
bool HandleAndValidateSourceFileDirectoryScopes(
233
  cmExecutionStatus& status, bool source_file_directory_option_enabled,
234
  bool source_file_target_option_enabled,
235
  std::vector<std::string>& source_file_directories,
236
  std::vector<std::string>& source_file_target_directories,
237
  std::vector<cmMakefile*>& source_file_directory_makefiles)
238
5.92k
{
239
5.92k
  bool scope_options_valid =
240
5.92k
    SetPropertyCommand::HandleSourceFileDirectoryScopeValidation(
241
5.92k
      status, source_file_directory_option_enabled,
242
5.92k
      source_file_target_option_enabled, source_file_directories,
243
5.92k
      source_file_target_directories);
244
5.92k
  if (!scope_options_valid) {
245
0
    return false;
246
0
  }
247
248
5.92k
  scope_options_valid = SetPropertyCommand::HandleSourceFileDirectoryScopes(
249
5.92k
    status, source_file_directories, source_file_target_directories,
250
5.92k
    source_file_directory_makefiles);
251
5.92k
  return scope_options_valid;
252
5.92k
}
253
254
bool HandleTestDirectoryScopes(cmExecutionStatus& status,
255
                               std::string& test_directory,
256
                               cmMakefile*& directory_makefile)
257
0
{
258
0
  cmMakefile* current_dir_mf = &status.GetMakefile();
259
0
  if (!test_directory.empty()) {
260
0
    std::string const absolute_dir_path = cmSystemTools::CollapseFullPath(
261
0
      test_directory, current_dir_mf->GetCurrentSourceDirectory());
262
0
    cmMakefile* dir_mf =
263
0
      status.GetMakefile().GetGlobalGenerator()->FindMakefile(
264
0
        absolute_dir_path);
265
0
    if (!dir_mf) {
266
0
      status.SetError(
267
0
        cmStrCat("given non-existent DIRECTORY ", test_directory));
268
0
      return false;
269
0
    }
270
0
    directory_makefile = dir_mf;
271
0
  } else {
272
0
    directory_makefile = current_dir_mf;
273
0
  }
274
0
  return true;
275
0
}
276
277
bool HandleTestDirectoryScopeValidation(cmExecutionStatus& status,
278
                                        bool test_directory_option_enabled,
279
                                        std::string& test_directory)
280
0
{
281
  // Validate source file directory scopes.
282
0
  if (test_directory_option_enabled && test_directory.empty()) {
283
0
    std::string errors = "called with incorrect number of arguments "
284
0
                         "no value provided to the DIRECTORY option";
285
0
    status.SetError(errors);
286
0
    return false;
287
0
  }
288
0
  return true;
289
0
}
290
291
bool HandleAndValidateTestDirectoryScopes(cmExecutionStatus& status,
292
                                          bool test_directory_option_enabled,
293
                                          std::string& test_directory,
294
                                          cmMakefile*& test_directory_makefile)
295
0
{
296
0
  bool scope_options_valid =
297
0
    SetPropertyCommand::HandleTestDirectoryScopeValidation(
298
0
      status, test_directory_option_enabled, test_directory);
299
0
  if (!scope_options_valid) {
300
0
    return false;
301
0
  }
302
303
0
  scope_options_valid = SetPropertyCommand::HandleTestDirectoryScopes(
304
0
    status, test_directory, test_directory_makefile);
305
0
  return scope_options_valid;
306
0
}
307
308
std::string MakeSourceFilePathAbsoluteIfNeeded(
309
  cmExecutionStatus& status, std::string const& source_file_path,
310
  bool const needed)
311
0
{
312
0
  if (!needed) {
313
0
    return source_file_path;
314
0
  }
315
0
  std::string absolute_file_path = cmSystemTools::CollapseFullPath(
316
0
    source_file_path, status.GetMakefile().GetCurrentSourceDirectory());
317
0
  return absolute_file_path;
318
0
}
319
320
void MakeSourceFilePathsAbsoluteIfNeeded(
321
  cmExecutionStatus& status,
322
  std::vector<std::string>& source_files_absolute_paths,
323
  std::vector<std::string>::const_iterator files_it_begin,
324
  std::vector<std::string>::const_iterator files_it_end, bool const needed)
325
5.92k
{
326
327
  // Make the file paths absolute, so that relative source file paths are
328
  // picked up relative to the command calling site, regardless of the
329
  // directory scope.
330
5.92k
  std::vector<std::string>::difference_type num_files =
331
5.92k
    files_it_end - files_it_begin;
332
5.92k
  source_files_absolute_paths.reserve(num_files);
333
334
5.92k
  if (!needed) {
335
5.92k
    source_files_absolute_paths.assign(files_it_begin, files_it_end);
336
5.92k
    return;
337
5.92k
  }
338
339
0
  for (; files_it_begin != files_it_end; ++files_it_begin) {
340
0
    std::string const absolute_file_path =
341
0
      MakeSourceFilePathAbsoluteIfNeeded(status, *files_it_begin, true);
342
0
    source_files_absolute_paths.push_back(absolute_file_path);
343
0
  }
344
0
}
345
346
bool HandleAndValidateSourceFilePropertyGENERATED(
347
  cmSourceFile* sf, std::string const& propertyValue, PropertyOp op)
348
0
{
349
0
  auto const& mf = *sf->GetLocation().GetMakefile();
350
351
0
  auto isProblematic = [&mf, &propertyValue,
352
0
                        op](cm::string_view policy) -> bool {
353
0
    if (!cmIsOn(propertyValue) && !cmIsOff(propertyValue)) {
354
0
      mf.IssueDiagnostic(
355
0
        cmDiagnostics::CMD_AUTHOR,
356
0
        cmStrCat("Policy ", policy,
357
0
                 " is set to NEW and the following non-boolean value given "
358
0
                 "for property 'GENERATED' is therefore not allowed:\n",
359
0
                 propertyValue, "\nReplace it with a boolean value!\n"));
360
0
      return true;
361
0
    }
362
0
    if (cmIsOff(propertyValue)) {
363
0
      mf.IssueDiagnostic(
364
0
        cmDiagnostics::CMD_AUTHOR,
365
0
        cmStrCat("Unsetting the 'GENERATED' property is not allowed under ",
366
0
                 policy, "!\n"));
367
0
      return true;
368
0
    }
369
0
    if (op == PropertyOp::Append || op == PropertyOp::AppendAsString) {
370
0
      mf.IssueDiagnostic(
371
0
        cmDiagnostics::CMD_AUTHOR,
372
0
        cmStrCat(
373
0
          "Policy ", policy,
374
0
          " is set to NEW and appending to the 'GENERATED' property is "
375
0
          "therefore not allowed. Only setting it to \"1\" is allowed!\n"));
376
0
      return true;
377
0
    }
378
0
    return false;
379
0
  };
380
381
0
  auto const cmp0163PolicyStatus = mf.GetPolicyStatus(cmPolicies::CMP0163);
382
0
  bool const cmp0163PolicyNEW = cmp0163PolicyStatus != cmPolicies::OLD &&
383
0
    cmp0163PolicyStatus != cmPolicies::WARN;
384
0
  if (cmp0163PolicyNEW) {
385
0
    if (!isProblematic("CMP0163")) {
386
0
      sf->MarkAsGenerated();
387
0
    }
388
0
    return true;
389
0
  }
390
391
0
  auto const cmp0118PolicyStatus = mf.GetPolicyStatus(cmPolicies::CMP0118);
392
0
  bool const cmp0118PolicyWARN = cmp0118PolicyStatus == cmPolicies::WARN;
393
0
  bool const cmp0118PolicyNEW =
394
0
    cmp0118PolicyStatus != cmPolicies::OLD && !cmp0118PolicyWARN;
395
396
0
  if (cmp0118PolicyNEW) {
397
0
    if (!isProblematic("CMP0118")) {
398
0
      sf->MarkAsGenerated();
399
0
    }
400
0
    return true;
401
0
  }
402
403
0
  if (cmp0118PolicyWARN) {
404
0
    if (!cmIsOn(propertyValue) && !cmIsOff(propertyValue)) {
405
0
      mf.IssuePolicyWarning(
406
0
        cmPolicies::CMP0118, {},
407
0
        cmStrCat("Attempt to set property 'GENERATED' with the following "
408
0
                 "non-boolean value (which will be interpreted as \"0\"):\n"_s,
409
0
                 propertyValue,
410
0
                 "\nThat exact value will not be retrievable. A value of "
411
0
                 "\"0\" will be returned instead.\n"
412
0
                 "This will be an error under policy CMP0118."_s));
413
0
    }
414
0
    if (cmIsOff(propertyValue)) {
415
0
      mf.IssuePolicyWarning(cmPolicies::CMP0118, {},
416
0
                            "Unsetting property 'GENERATED' "
417
0
                            "will not be allowed under policy CMP0118!"_s);
418
0
    }
419
0
    if (op == PropertyOp::Append || op == PropertyOp::AppendAsString) {
420
0
      mf.IssuePolicyWarning(cmPolicies::CMP0118, {},
421
0
                            "Appending to property 'GENERATED' "
422
0
                            "will not be allowed under policy CMP0118!"_s);
423
0
    }
424
0
  }
425
426
  // Set property the traditional way.
427
0
  switch (op) {
428
0
    case PropertyOp::Append:
429
0
      sf->AppendProperty("GENERATED", propertyValue, false);
430
0
      break;
431
0
    case PropertyOp::AppendAsString:
432
0
      sf->AppendProperty("GENERATED", propertyValue, true);
433
0
      break;
434
0
    case PropertyOp::Remove:
435
0
      sf->RemoveProperty("GENERATED");
436
0
      break;
437
0
    case PropertyOp::Set:
438
0
      sf->SetProperty("GENERATED", propertyValue);
439
0
      break;
440
0
  }
441
0
  return true;
442
0
}
443
444
} // END: namespace SetPropertyCommand
445
446
bool cmSetPropertyCommand(std::vector<std::string> const& args,
447
                          cmExecutionStatus& status)
448
29.6k
{
449
29.6k
  if (args.size() < 2) {
450
0
    status.SetError("called with incorrect number of arguments");
451
0
    return false;
452
0
  }
453
454
  // Get the scope on which to set the property.
455
29.6k
  std::string const& scopeName = args.front();
456
29.6k
  cmProperty::ScopeType scope;
457
29.6k
  if (scopeName == "GLOBAL") {
458
11.8k
    scope = cmProperty::GLOBAL;
459
17.7k
  } else if (scopeName == "DIRECTORY") {
460
5.92k
    scope = cmProperty::DIRECTORY;
461
11.8k
  } else if (scopeName == "RULE") {
462
0
    scope = cmProperty::RULE;
463
11.8k
  } else if (scopeName == "TARGET") {
464
11.8k
    scope = cmProperty::TARGET;
465
11.8k
  } else if (scopeName == "FILE_SET") {
466
0
    scope = cmProperty::FILE_SET;
467
0
  } else if (scopeName == "SOURCE") {
468
0
    scope = cmProperty::SOURCE_FILE;
469
0
  } else if (scopeName == "TEST") {
470
0
    scope = cmProperty::TEST;
471
0
  } else if (scopeName == "CACHE") {
472
0
    scope = cmProperty::CACHE;
473
0
  } else if (scopeName == "INSTALL") {
474
0
    scope = cmProperty::INSTALL;
475
0
  } else {
476
0
    status.SetError(
477
0
      cmStrCat("given invalid scope ", scopeName,
478
0
               ".  Valid scopes are GLOBAL, DIRECTORY, RULE, TARGET, "
479
0
               "FILE_SET, SOURCE, TEST, CACHE, INSTALL."));
480
0
    return false;
481
0
  }
482
483
29.6k
  bool appendAsString = false;
484
29.6k
  bool appendMode = false;
485
29.6k
  bool remove = true;
486
29.6k
  std::set<std::string> names;
487
29.6k
  std::string propertyName;
488
29.6k
  std::string propertyValue;
489
490
29.6k
  std::string file_set_target_name;
491
29.6k
  bool file_set_target_option_enabled = false;
492
493
29.6k
  std::vector<std::string> source_file_directories;
494
29.6k
  std::vector<std::string> source_file_target_directories;
495
29.6k
  bool source_file_directory_option_enabled = false;
496
29.6k
  bool source_file_target_option_enabled = false;
497
498
29.6k
  std::string test_directory;
499
29.6k
  bool test_directory_option_enabled = false;
500
501
  // Parse the rest of the arguments up to the values.
502
29.6k
  enum Doing
503
29.6k
  {
504
29.6k
    DoingNone,
505
29.6k
    DoingNames,
506
29.6k
    DoingProperty,
507
29.6k
    DoingValues,
508
29.6k
    DoingFileSetTarget,
509
29.6k
    DoingSourceDirectory,
510
29.6k
    DoingSourceTargetDirectory,
511
29.6k
    DoingTestDirectory,
512
29.6k
  };
513
29.6k
  Doing doing = DoingNames;
514
29.6k
  char const* sep = "";
515
100k
  for (std::string const& arg : cmMakeRange(args).advance(1)) {
516
100k
    if (arg == "PROPERTY") {
517
29.6k
      doing = DoingProperty;
518
71.1k
    } else if (arg == "APPEND") {
519
0
      doing = DoingNone;
520
0
      appendMode = true;
521
0
      remove = false;
522
0
      appendAsString = false;
523
71.1k
    } else if (arg == "APPEND_STRING") {
524
0
      doing = DoingNone;
525
0
      appendMode = true;
526
0
      remove = false;
527
0
      appendAsString = true;
528
71.1k
    } else if (doing != DoingProperty && doing != DoingValues &&
529
11.8k
               scope == cmProperty::FILE_SET && arg == "TARGET") {
530
0
      doing = DoingFileSetTarget;
531
0
      file_set_target_option_enabled = true;
532
71.1k
    } else if (doing != DoingProperty && doing != DoingValues &&
533
11.8k
               scope == cmProperty::SOURCE_FILE && arg == "DIRECTORY") {
534
0
      doing = DoingSourceDirectory;
535
0
      source_file_directory_option_enabled = true;
536
71.1k
    } else if (doing != DoingProperty && doing != DoingValues &&
537
11.8k
               scope == cmProperty::SOURCE_FILE && arg == "TARGET_DIRECTORY") {
538
0
      doing = DoingSourceTargetDirectory;
539
0
      source_file_target_option_enabled = true;
540
71.1k
    } else if (doing != DoingProperty && doing != DoingValues &&
541
11.8k
               scope == cmProperty::TEST && arg == "DIRECTORY") {
542
0
      doing = DoingTestDirectory;
543
0
      test_directory_option_enabled = true;
544
71.1k
    } else if (doing == DoingNames) {
545
11.8k
      names.insert(arg);
546
59.2k
    } else if (doing == DoingFileSetTarget) {
547
0
      file_set_target_name = arg;
548
0
      file_set_target_option_enabled = true;
549
0
      doing = DoingNone;
550
59.2k
    } else if (doing == DoingSourceDirectory) {
551
0
      source_file_directories.push_back(arg);
552
59.2k
    } else if (doing == DoingSourceTargetDirectory) {
553
0
      source_file_target_directories.push_back(arg);
554
59.2k
    } else if (doing == DoingTestDirectory) {
555
0
      test_directory = arg;
556
0
      doing = DoingNone;
557
59.2k
    } else if (doing == DoingProperty) {
558
29.6k
      propertyName = arg;
559
29.6k
      doing = DoingValues;
560
29.6k
    } else if (doing == DoingValues) {
561
29.6k
      propertyValue += sep;
562
29.6k
      sep = ";";
563
29.6k
      propertyValue += arg;
564
29.6k
      remove = false;
565
29.6k
    } else {
566
0
      status.SetError(cmStrCat("given invalid argument \"", arg, "\"."));
567
0
      return false;
568
0
    }
569
100k
  }
570
571
  // Make sure a property name was found.
572
29.6k
  if (propertyName.empty()) {
573
0
    status.SetError("not given a PROPERTY <name> argument.");
574
0
    return false;
575
0
  }
576
577
  // Dispatch property setting.
578
29.6k
  switch (scope) {
579
11.8k
    case cmProperty::GLOBAL:
580
11.8k
      return HandleGlobalMode(status, names, propertyName, propertyValue,
581
11.8k
                              appendAsString, appendMode, remove);
582
5.92k
    case cmProperty::DIRECTORY:
583
5.92k
      return HandleDirectoryMode(status, names, propertyName, propertyValue,
584
5.92k
                                 appendAsString, appendMode, remove);
585
0
    case cmProperty::RULE:
586
0
      return HandleRuleMode(status, names, propertyName, propertyValue,
587
0
                            appendAsString, appendMode, remove);
588
11.8k
    case cmProperty::TARGET:
589
11.8k
      return HandleTargetMode(status, names, propertyName, propertyValue,
590
11.8k
                              appendAsString, appendMode, remove);
591
0
    case cmProperty::FILE_SET: {
592
0
      cmTarget* file_set_target;
593
0
      if (!SetPropertyCommand::HandleAndValidateFileSetTargetScopes(
594
0
            status, file_set_target_option_enabled, file_set_target_name,
595
0
            file_set_target)) {
596
0
        return false;
597
0
      }
598
0
      return HandleFileSetMode(status, names, propertyName, propertyValue,
599
0
                               appendAsString, appendMode, remove,
600
0
                               file_set_target);
601
0
    }
602
0
    case cmProperty::SOURCE_FILE: {
603
0
      std::vector<cmMakefile*> source_file_directory_makefiles;
604
0
      if (!SetPropertyCommand::HandleAndValidateSourceFileDirectoryScopes(
605
0
            status, source_file_directory_option_enabled,
606
0
            source_file_target_option_enabled, source_file_directories,
607
0
            source_file_target_directories, source_file_directory_makefiles)) {
608
0
        return false;
609
0
      }
610
0
      bool source_file_paths_should_be_absolute =
611
0
        source_file_directory_option_enabled ||
612
0
        source_file_target_option_enabled;
613
0
      return HandleSourceMode(status, names, propertyName, propertyValue,
614
0
                              appendAsString, appendMode, remove,
615
0
                              source_file_directory_makefiles,
616
0
                              source_file_paths_should_be_absolute);
617
0
    }
618
0
    case cmProperty::TEST: {
619
0
      cmMakefile* test_directory_makefile;
620
0
      if (!SetPropertyCommand::HandleAndValidateTestDirectoryScopes(
621
0
            status, test_directory_option_enabled, test_directory,
622
0
            test_directory_makefile)) {
623
0
        return false;
624
0
      }
625
0
      return HandleTestMode(status, names, propertyName, propertyValue,
626
0
                            appendAsString, appendMode, remove,
627
0
                            test_directory_makefile);
628
0
    }
629
0
    case cmProperty::CACHE:
630
0
      return HandleCacheMode(status, names, propertyName, propertyValue,
631
0
                             appendAsString, appendMode, remove);
632
0
    case cmProperty::INSTALL:
633
0
      return HandleInstallMode(status, names, propertyName, propertyValue,
634
0
                               appendAsString, appendMode, remove);
635
636
0
    case cmProperty::VARIABLE:
637
0
    case cmProperty::CACHED_VARIABLE:
638
0
      break; // should never happen
639
29.6k
  }
640
0
  return true;
641
29.6k
}
642
643
namespace /* anonymous */ {
644
bool HandleGlobalMode(cmExecutionStatus& status,
645
                      std::set<std::string> const& names,
646
                      std::string const& propertyName,
647
                      std::string const& propertyValue, bool appendAsString,
648
                      bool appendMode, bool remove)
649
11.8k
{
650
11.8k
  if (!names.empty()) {
651
0
    status.SetError("given names for GLOBAL scope.");
652
0
    return false;
653
0
  }
654
655
  // Set or append the property.
656
11.8k
  cmake* cm = status.GetMakefile().GetCMakeInstance();
657
11.8k
  if (appendMode) {
658
0
    cm->AppendProperty(propertyName, propertyValue, appendAsString);
659
11.8k
  } else {
660
11.8k
    if (remove) {
661
0
      cm->SetProperty(propertyName, nullptr);
662
11.8k
    } else {
663
11.8k
      cm->SetProperty(propertyName, propertyValue);
664
11.8k
    }
665
11.8k
  }
666
667
11.8k
  return true;
668
11.8k
}
669
670
bool HandleDirectoryMode(cmExecutionStatus& status,
671
                         std::set<std::string> const& names,
672
                         std::string const& propertyName,
673
                         std::string const& propertyValue, bool appendAsString,
674
                         bool appendMode, bool remove)
675
5.92k
{
676
5.92k
  if (names.size() > 1) {
677
0
    status.SetError("allows at most one name for DIRECTORY scope.");
678
0
    return false;
679
0
  }
680
681
  // Default to the current directory.
682
5.92k
  cmMakefile* mf = &status.GetMakefile();
683
684
  // Lookup the directory if given.
685
5.92k
  if (!names.empty()) {
686
    // Construct the directory name.  Interpret relative paths with
687
    // respect to the current directory.
688
0
    std::string dir = cmSystemTools::CollapseFullPath(
689
0
      *names.begin(), status.GetMakefile().GetCurrentSourceDirectory());
690
691
0
    mf = status.GetMakefile().GetGlobalGenerator()->FindMakefile(dir);
692
0
    if (!mf) {
693
      // Could not find the directory.
694
0
      status.SetError(
695
0
        "DIRECTORY scope provided but requested directory was not found. "
696
0
        "This could be because the directory argument was invalid or, "
697
0
        "it is valid but has not been processed yet.");
698
0
      return false;
699
0
    }
700
0
  }
701
702
  // Set or append the property.
703
5.92k
  if (appendMode) {
704
0
    mf->AppendProperty(propertyName, propertyValue, appendAsString);
705
5.92k
  } else {
706
5.92k
    if (remove) {
707
0
      mf->SetProperty(propertyName, nullptr);
708
5.92k
    } else {
709
5.92k
      mf->SetProperty(propertyName, propertyValue);
710
5.92k
    }
711
5.92k
  }
712
713
5.92k
  return true;
714
5.92k
}
715
716
bool HandleRuleMode(cmExecutionStatus& status,
717
                    std::set<std::string> const& names,
718
                    std::string const& propertyName,
719
                    std::string const& propertyValue, bool appendAsString,
720
                    bool appendMode, bool remove)
721
0
{
722
0
  for (std::string const& name : names) {
723
0
    if (cmRule* rule = status.GetMakefile().FindRuleToUse(name)) {
724
      // Handle the current rule.
725
      // Set or append the property.
726
0
      if (appendMode) {
727
0
        rule->AppendProperty(propertyName, propertyValue, appendAsString);
728
0
      } else {
729
0
        if (remove) {
730
0
          rule->SetProperty(propertyName, nullptr);
731
0
        } else {
732
0
          rule->SetProperty(propertyName, propertyValue);
733
0
        }
734
0
      }
735
      // Check the resulting value.
736
0
      rule->CheckProperty(propertyName, status.GetMakefile());
737
0
    } else {
738
0
      status.SetError(cmStrCat("could not find RULE ", name,
739
0
                               ".  Perhaps it has not yet been created."));
740
0
      return false;
741
0
    }
742
0
  }
743
0
  return true;
744
0
}
745
746
bool HandleTargetMode(cmExecutionStatus& status,
747
                      std::set<std::string> const& names,
748
                      std::string const& propertyName,
749
                      std::string const& propertyValue, bool appendAsString,
750
                      bool appendMode, bool remove)
751
11.8k
{
752
11.8k
  for (std::string const& name : names) {
753
    // Better error message for alias properties set on an alias target.
754
11.8k
    if (propertyName == "ALIASED_TARGET" || propertyName == "ALIAS_GLOBAL") {
755
0
      if (status.GetMakefile().IsAlias(name)) {
756
0
        status.SetError(cmStrCat("can not set property ", propertyName,
757
0
                                 " on an ALIAS target: ", name));
758
0
        return false;
759
0
      }
760
0
    }
761
11.8k
    if (cmTarget* target = status.GetMakefile().FindTargetToUse(name)) {
762
11.8k
      if (target->IsSymbolic()) {
763
0
        status.SetError("can not be used on a SYMBOLIC target.");
764
0
        return false;
765
0
      }
766
767
      // Handle the current target.
768
11.8k
      if (!HandleTarget(target, status.GetMakefile(), propertyName,
769
11.8k
                        propertyValue, appendAsString, appendMode, remove)) {
770
0
        return false;
771
0
      }
772
11.8k
    } else {
773
0
      status.SetError(cmStrCat("could not find TARGET ", name,
774
0
                               ".  Perhaps it has not yet been created."));
775
0
      return false;
776
0
    }
777
11.8k
  }
778
11.8k
  return true;
779
11.8k
}
780
781
bool HandleTarget(cmTarget* target, cmMakefile& makefile,
782
                  std::string const& propertyName,
783
                  std::string const& propertyValue, bool appendAsString,
784
                  bool appendMode, bool remove)
785
11.8k
{
786
  // Set or append the property.
787
11.8k
  if (appendMode) {
788
0
    target->AppendProperty(propertyName, propertyValue,
789
0
                           makefile.GetBacktrace(), appendAsString);
790
11.8k
  } else {
791
11.8k
    if (remove) {
792
0
      target->SetProperty(propertyName, nullptr);
793
11.8k
    } else {
794
11.8k
      target->SetProperty(propertyName, propertyValue);
795
11.8k
    }
796
11.8k
  }
797
798
  // Check the resulting value.
799
11.8k
  target->CheckProperty(propertyName, &makefile);
800
801
11.8k
  return true;
802
11.8k
}
803
804
bool HandleFileSetMode(cmExecutionStatus& status,
805
                       std::set<std::string> const& names,
806
                       std::string const& propertyName,
807
                       std::string const& propertyValue, bool appendAsString,
808
                       bool appendMode, bool remove, cmTarget* target)
809
0
{
810
0
  for (std::string const& name : names) {
811
0
    if (cmFileSet* fileSet = target->GetFileSet(name)) {
812
      // Handle the current file set.
813
0
      if (!HandleFileSet(fileSet, propertyName, propertyValue, appendAsString,
814
0
                         appendMode, remove)) {
815
0
        return false;
816
0
      }
817
0
    } else {
818
0
      status.SetError(cmStrCat("could not find FILE_SET ", name,
819
0
                               " for TARGET ", target->GetName(),
820
0
                               ".  Perhaps it has not yet been created."));
821
0
      return false;
822
0
    }
823
0
  }
824
0
  return true;
825
0
}
826
827
bool HandleFileSet(cmFileSet* fileSet, std::string const& propertyName,
828
                   std::string const& propertyValue, bool appendAsString,
829
                   bool appendMode, bool remove)
830
0
{
831
  // Set or append the property.
832
0
  if (appendMode) {
833
0
    fileSet->AppendProperty(propertyName, propertyValue, appendAsString);
834
0
  } else {
835
0
    if (remove) {
836
0
      fileSet->SetProperty(propertyName, nullptr);
837
0
    } else {
838
0
      fileSet->SetProperty(propertyName, propertyValue);
839
0
    }
840
0
  }
841
0
  return true;
842
0
}
843
844
bool HandleSourceMode(cmExecutionStatus& status,
845
                      std::set<std::string> const& names,
846
                      std::string const& propertyName,
847
                      std::string const& propertyValue, bool appendAsString,
848
                      bool appendMode, bool remove,
849
                      std::vector<cmMakefile*> const& directory_makefiles,
850
                      bool const source_file_paths_should_be_absolute)
851
0
{
852
0
  std::vector<std::string> files_absolute;
853
0
  std::vector<std::string> unique_files(names.begin(), names.end());
854
0
  SetPropertyCommand::MakeSourceFilePathsAbsoluteIfNeeded(
855
0
    status, files_absolute, unique_files.begin(), unique_files.end(),
856
0
    source_file_paths_should_be_absolute);
857
858
0
  for (auto* const mf : directory_makefiles) {
859
0
    for (std::string const& name : files_absolute) {
860
      // Get the source file.
861
0
      if (cmSourceFile* sf = mf->GetOrCreateSource(name)) {
862
0
        if (!HandleSource(sf, propertyName, propertyValue, appendAsString,
863
0
                          appendMode, remove)) {
864
0
          return false;
865
0
        }
866
0
      } else {
867
0
        status.SetError(cmStrCat(
868
0
          "given SOURCE name that could not be found or created: ", name));
869
0
        return false;
870
0
      }
871
0
    }
872
0
  }
873
874
0
  return true;
875
0
}
876
877
bool HandleSource(cmSourceFile* sf, std::string const& propertyName,
878
                  std::string const& propertyValue, bool appendAsString,
879
                  bool appendMode, bool remove)
880
0
{
881
  // Special validation and handling of GENERATED flag?
882
0
  if (propertyName == "GENERATED") {
883
0
    SetPropertyCommand::PropertyOp op = (remove)
884
0
      ? SetPropertyCommand::PropertyOp::Remove
885
0
      : (appendAsString) ? SetPropertyCommand::PropertyOp::AppendAsString
886
0
      : (appendMode)     ? SetPropertyCommand::PropertyOp::Append
887
0
                         : SetPropertyCommand::PropertyOp::Set;
888
0
    return SetPropertyCommand::HandleAndValidateSourceFilePropertyGENERATED(
889
0
      sf, propertyValue, op);
890
0
  }
891
892
  // Set or append the property.
893
0
  if (appendMode) {
894
0
    sf->AppendProperty(propertyName, propertyValue, appendAsString);
895
0
  } else {
896
0
    if (remove) {
897
0
      sf->RemoveProperty(propertyName);
898
0
    } else {
899
0
      sf->SetProperty(propertyName, propertyValue);
900
0
    }
901
0
  }
902
0
  return true;
903
0
}
904
905
bool HandleTestMode(cmExecutionStatus& status, std::set<std::string>& names,
906
                    std::string const& propertyName,
907
                    std::string const& propertyValue, bool appendAsString,
908
                    bool appendMode, bool remove, cmMakefile* test_makefile)
909
0
{
910
  // Look for tests with all names given.
911
0
  std::set<std::string>::iterator next;
912
0
  for (auto ni = names.begin(); ni != names.end(); ni = next) {
913
0
    next = ni;
914
0
    ++next;
915
0
    if (cmTest* test = test_makefile->GetTest(*ni)) {
916
0
      if (HandleTest(test, propertyName, propertyValue, appendAsString,
917
0
                     appendMode, remove)) {
918
0
        names.erase(ni);
919
0
      } else {
920
0
        return false;
921
0
      }
922
0
    }
923
0
  }
924
925
  // Names that are still left were not found.
926
0
  if (!names.empty()) {
927
0
    status.SetError(cmStrCat("given TEST names that do not exist:\n",
928
0
                             cmWrap("  ", names, "\n", "")));
929
0
    return false;
930
0
  }
931
0
  return true;
932
0
}
933
934
bool HandleTest(cmTest* test, std::string const& propertyName,
935
                std::string const& propertyValue, bool appendAsString,
936
                bool appendMode, bool remove)
937
0
{
938
  // Set or append the property.
939
0
  if (appendMode) {
940
0
    test->AppendProperty(propertyName, propertyValue, appendAsString);
941
0
  } else {
942
0
    if (remove) {
943
0
      test->SetProperty(propertyName, nullptr);
944
0
    } else {
945
0
      test->SetProperty(propertyName, propertyValue);
946
0
    }
947
0
  }
948
949
0
  return true;
950
0
}
951
952
bool HandleCacheMode(cmExecutionStatus& status,
953
                     std::set<std::string> const& names,
954
                     std::string const& propertyName,
955
                     std::string const& propertyValue, bool appendAsString,
956
                     bool appendMode, bool remove)
957
0
{
958
0
  if (propertyName == "ADVANCED") {
959
0
    if (!remove && !cmIsOn(propertyValue) && !cmIsOff(propertyValue)) {
960
0
      status.SetError(cmStrCat("given non-boolean value \"", propertyValue,
961
0
                               R"(" for CACHE property "ADVANCED".  )"));
962
0
      return false;
963
0
    }
964
0
  } else if (propertyName == "TYPE") {
965
0
    if (!cmState::IsCacheEntryType(propertyValue)) {
966
0
      status.SetError(
967
0
        cmStrCat("given invalid CACHE entry TYPE \"", propertyValue, '"'));
968
0
      return false;
969
0
    }
970
0
  } else if (propertyName != "HELPSTRING" && propertyName != "STRINGS" &&
971
0
             propertyName != "VALUE") {
972
0
    status.SetError(
973
0
      cmStrCat("given invalid CACHE property ", propertyName,
974
0
               ".  "
975
0
               "Settable CACHE properties are: "
976
0
               "ADVANCED, HELPSTRING, STRINGS, TYPE, and VALUE."));
977
0
    return false;
978
0
  }
979
980
0
  for (std::string const& name : names) {
981
    // Get the source file.
982
0
    cmake* cm = status.GetMakefile().GetCMakeInstance();
983
0
    cmValue existingValue = cm->GetState()->GetCacheEntryValue(name);
984
0
    if (existingValue) {
985
0
      if (!HandleCacheEntry(name, status.GetMakefile(), propertyName,
986
0
                            propertyValue, appendAsString, appendMode,
987
0
                            remove)) {
988
0
        return false;
989
0
      }
990
0
    } else {
991
0
      status.SetError(cmStrCat("could not find CACHE variable ", name,
992
0
                               ".  Perhaps it has not yet been created."));
993
0
      return false;
994
0
    }
995
0
  }
996
0
  return true;
997
0
}
998
999
bool HandleCacheEntry(std::string const& cacheKey, cmMakefile const& makefile,
1000
                      std::string const& propertyName,
1001
                      std::string const& propertyValue, bool appendAsString,
1002
                      bool appendMode, bool remove)
1003
0
{
1004
  // Set or append the property.
1005
0
  cmState* state = makefile.GetState();
1006
0
  if (remove) {
1007
0
    state->RemoveCacheEntryProperty(cacheKey, propertyName);
1008
0
  }
1009
0
  if (appendMode) {
1010
0
    state->AppendCacheEntryProperty(cacheKey, propertyName, propertyValue,
1011
0
                                    appendAsString);
1012
0
  } else {
1013
0
    state->SetCacheEntryProperty(cacheKey, propertyName, propertyValue);
1014
0
  }
1015
1016
0
  return true;
1017
0
}
1018
1019
bool HandleInstallMode(cmExecutionStatus& status,
1020
                       std::set<std::string> const& names,
1021
                       std::string const& propertyName,
1022
                       std::string const& propertyValue, bool appendAsString,
1023
                       bool appendMode, bool remove)
1024
0
{
1025
0
  cmake* cm = status.GetMakefile().GetCMakeInstance();
1026
1027
0
  for (std::string const& name : names) {
1028
0
    if (cmInstalledFile* file =
1029
0
          cm->GetOrCreateInstalledFile(&status.GetMakefile(), name)) {
1030
0
      if (!HandleInstall(file, status.GetMakefile(), propertyName,
1031
0
                         propertyValue, appendAsString, appendMode, remove)) {
1032
0
        return false;
1033
0
      }
1034
0
    } else {
1035
0
      status.SetError(cmStrCat(
1036
0
        "given INSTALL name that could not be found or created: ", name));
1037
0
      return false;
1038
0
    }
1039
0
  }
1040
0
  return true;
1041
0
}
1042
1043
bool HandleInstall(cmInstalledFile* file, cmMakefile& makefile,
1044
                   std::string const& propertyName,
1045
                   std::string const& propertyValue, bool appendAsString,
1046
                   bool appendMode, bool remove)
1047
0
{
1048
  // Set or append the property.
1049
0
  if (remove) {
1050
0
    file->RemoveProperty(propertyName);
1051
0
  } else if (appendMode) {
1052
0
    file->AppendProperty(&makefile, propertyName, propertyValue,
1053
0
                         appendAsString);
1054
0
  } else {
1055
0
    file->SetProperty(&makefile, propertyName, propertyValue);
1056
0
  }
1057
0
  return true;
1058
0
}
1059
}