cmSetPropertyCommand.cxx 32 KB

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