cmSetPropertyCommand.cxx 28 KB

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