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