cmSetPropertyCommand.cxx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  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 <sstream>
  5. #include "cmGlobalGenerator.h"
  6. #include "cmInstalledFile.h"
  7. #include "cmMakefile.h"
  8. #include "cmProperty.h"
  9. #include "cmSourceFile.h"
  10. #include "cmState.h"
  11. #include "cmSystemTools.h"
  12. #include "cmTarget.h"
  13. #include "cmTest.h"
  14. #include "cmake.h"
  15. class cmExecutionStatus;
  16. cmSetPropertyCommand::cmSetPropertyCommand()
  17. {
  18. this->AppendMode = false;
  19. this->AppendAsString = false;
  20. this->Remove = true;
  21. }
  22. bool cmSetPropertyCommand::InitialPass(std::vector<std::string> const& args,
  23. cmExecutionStatus&)
  24. {
  25. if (args.size() < 2) {
  26. this->SetError("called with incorrect number of arguments");
  27. return false;
  28. }
  29. // Get the scope on which to set the property.
  30. std::vector<std::string>::const_iterator arg = args.begin();
  31. cmProperty::ScopeType scope;
  32. if (*arg == "GLOBAL") {
  33. scope = cmProperty::GLOBAL;
  34. } else if (*arg == "DIRECTORY") {
  35. scope = cmProperty::DIRECTORY;
  36. } else if (*arg == "TARGET") {
  37. scope = cmProperty::TARGET;
  38. } else if (*arg == "SOURCE") {
  39. scope = cmProperty::SOURCE_FILE;
  40. } else if (*arg == "TEST") {
  41. scope = cmProperty::TEST;
  42. } else if (*arg == "CACHE") {
  43. scope = cmProperty::CACHE;
  44. } else if (*arg == "INSTALL") {
  45. scope = cmProperty::INSTALL;
  46. } else {
  47. std::ostringstream e;
  48. e << "given invalid scope " << *arg << ". "
  49. << "Valid scopes are GLOBAL, DIRECTORY, "
  50. "TARGET, SOURCE, TEST, CACHE, INSTALL.";
  51. this->SetError(e.str());
  52. return false;
  53. }
  54. // Parse the rest of the arguments up to the values.
  55. enum Doing
  56. {
  57. DoingNone,
  58. DoingNames,
  59. DoingProperty,
  60. DoingValues
  61. };
  62. Doing doing = DoingNames;
  63. const char* sep = "";
  64. for (++arg; arg != args.end(); ++arg) {
  65. if (*arg == "PROPERTY") {
  66. doing = DoingProperty;
  67. } else if (*arg == "APPEND") {
  68. doing = DoingNone;
  69. this->AppendMode = true;
  70. this->Remove = false;
  71. this->AppendAsString = false;
  72. } else if (*arg == "APPEND_STRING") {
  73. doing = DoingNone;
  74. this->AppendMode = true;
  75. this->Remove = false;
  76. this->AppendAsString = true;
  77. } else if (doing == DoingNames) {
  78. this->Names.insert(*arg);
  79. } else if (doing == DoingProperty) {
  80. this->PropertyName = *arg;
  81. doing = DoingValues;
  82. } else if (doing == DoingValues) {
  83. this->PropertyValue += sep;
  84. sep = ";";
  85. this->PropertyValue += *arg;
  86. this->Remove = false;
  87. } else {
  88. std::ostringstream e;
  89. e << "given invalid argument \"" << *arg << "\".";
  90. this->SetError(e.str());
  91. return false;
  92. }
  93. }
  94. // Make sure a property name was found.
  95. if (this->PropertyName.empty()) {
  96. this->SetError("not given a PROPERTY <name> argument.");
  97. return false;
  98. }
  99. // Dispatch property setting.
  100. switch (scope) {
  101. case cmProperty::GLOBAL:
  102. return this->HandleGlobalMode();
  103. case cmProperty::DIRECTORY:
  104. return this->HandleDirectoryMode();
  105. case cmProperty::TARGET:
  106. return this->HandleTargetMode();
  107. case cmProperty::SOURCE_FILE:
  108. return this->HandleSourceMode();
  109. case cmProperty::TEST:
  110. return this->HandleTestMode();
  111. case cmProperty::CACHE:
  112. return this->HandleCacheMode();
  113. case cmProperty::INSTALL:
  114. return this->HandleInstallMode();
  115. case cmProperty::VARIABLE:
  116. case cmProperty::CACHED_VARIABLE:
  117. break; // should never happen
  118. }
  119. return true;
  120. }
  121. bool cmSetPropertyCommand::HandleGlobalMode()
  122. {
  123. if (!this->Names.empty()) {
  124. this->SetError("given names for GLOBAL scope.");
  125. return false;
  126. }
  127. // Set or append the property.
  128. cmake* cm = this->Makefile->GetCMakeInstance();
  129. std::string const& name = this->PropertyName;
  130. const char* value = this->PropertyValue.c_str();
  131. if (this->Remove) {
  132. value = nullptr;
  133. }
  134. if (this->AppendMode) {
  135. cm->AppendProperty(name, value ? value : "", this->AppendAsString);
  136. } else {
  137. cm->SetProperty(name, value);
  138. }
  139. return true;
  140. }
  141. bool cmSetPropertyCommand::HandleDirectoryMode()
  142. {
  143. if (this->Names.size() > 1) {
  144. this->SetError("allows at most one name for DIRECTORY scope.");
  145. return false;
  146. }
  147. // Default to the current directory.
  148. cmMakefile* mf = this->Makefile;
  149. // Lookup the directory if given.
  150. if (!this->Names.empty()) {
  151. // Construct the directory name. Interpret relative paths with
  152. // respect to the current directory.
  153. std::string dir = *this->Names.begin();
  154. if (!cmSystemTools::FileIsFullPath(dir)) {
  155. dir = this->Makefile->GetCurrentSourceDirectory();
  156. dir += "/";
  157. dir += *this->Names.begin();
  158. }
  159. // The local generators are associated with collapsed paths.
  160. dir = cmSystemTools::CollapseFullPath(dir);
  161. mf = this->Makefile->GetGlobalGenerator()->FindMakefile(dir);
  162. if (!mf) {
  163. // Could not find the directory.
  164. this->SetError(
  165. "DIRECTORY scope provided but requested directory was not found. "
  166. "This could be because the directory argument was invalid or, "
  167. "it is valid but has not been processed yet.");
  168. return false;
  169. }
  170. }
  171. // Set or append the property.
  172. std::string const& name = this->PropertyName;
  173. const char* value = this->PropertyValue.c_str();
  174. if (this->Remove) {
  175. value = nullptr;
  176. }
  177. if (this->AppendMode) {
  178. mf->AppendProperty(name, value ? value : "", this->AppendAsString);
  179. } else {
  180. mf->SetProperty(name, value);
  181. }
  182. return true;
  183. }
  184. bool cmSetPropertyCommand::HandleTargetMode()
  185. {
  186. for (std::string const& name : this->Names) {
  187. if (this->Makefile->IsAlias(name)) {
  188. this->SetError("can not be used on an ALIAS target.");
  189. return false;
  190. }
  191. if (cmTarget* target = this->Makefile->FindTargetToUse(name)) {
  192. // Handle the current target.
  193. if (!this->HandleTarget(target)) {
  194. return false;
  195. }
  196. } else {
  197. std::ostringstream e;
  198. e << "could not find TARGET " << name
  199. << ". Perhaps it has not yet been created.";
  200. this->SetError(e.str());
  201. return false;
  202. }
  203. }
  204. return true;
  205. }
  206. bool cmSetPropertyCommand::HandleTarget(cmTarget* target)
  207. {
  208. // Set or append the property.
  209. std::string const& name = this->PropertyName;
  210. const char* value = this->PropertyValue.c_str();
  211. if (this->Remove) {
  212. value = nullptr;
  213. }
  214. if (this->AppendMode) {
  215. target->AppendProperty(name, value, this->AppendAsString);
  216. } else {
  217. target->SetProperty(name, value);
  218. }
  219. // Check the resulting value.
  220. target->CheckProperty(name, this->Makefile);
  221. return true;
  222. }
  223. bool cmSetPropertyCommand::HandleSourceMode()
  224. {
  225. for (std::string const& name : this->Names) {
  226. // Get the source file.
  227. if (cmSourceFile* sf = this->Makefile->GetOrCreateSource(name)) {
  228. if (!this->HandleSource(sf)) {
  229. return false;
  230. }
  231. } else {
  232. std::ostringstream e;
  233. e << "given SOURCE name that could not be found or created: " << name;
  234. this->SetError(e.str());
  235. return false;
  236. }
  237. }
  238. return true;
  239. }
  240. bool cmSetPropertyCommand::HandleSource(cmSourceFile* sf)
  241. {
  242. // Set or append the property.
  243. std::string const& name = this->PropertyName;
  244. const char* value = this->PropertyValue.c_str();
  245. if (this->Remove) {
  246. value = nullptr;
  247. }
  248. if (this->AppendMode) {
  249. sf->AppendProperty(name, value, this->AppendAsString);
  250. } else {
  251. sf->SetProperty(name, value);
  252. }
  253. return true;
  254. }
  255. bool cmSetPropertyCommand::HandleTestMode()
  256. {
  257. // Look for tests with all names given.
  258. std::set<std::string>::iterator next;
  259. for (std::set<std::string>::iterator ni = this->Names.begin();
  260. ni != this->Names.end(); ni = next) {
  261. next = ni;
  262. ++next;
  263. if (cmTest* test = this->Makefile->GetTest(*ni)) {
  264. if (this->HandleTest(test)) {
  265. this->Names.erase(ni);
  266. } else {
  267. return false;
  268. }
  269. }
  270. }
  271. // Names that are still left were not found.
  272. if (!this->Names.empty()) {
  273. std::ostringstream e;
  274. e << "given TEST names that do not exist:\n";
  275. for (std::string const& name : this->Names) {
  276. e << " " << name << "\n";
  277. }
  278. this->SetError(e.str());
  279. return false;
  280. }
  281. return true;
  282. }
  283. bool cmSetPropertyCommand::HandleTest(cmTest* test)
  284. {
  285. // Set or append the property.
  286. std::string const& name = this->PropertyName;
  287. const char* value = this->PropertyValue.c_str();
  288. if (this->Remove) {
  289. value = nullptr;
  290. }
  291. if (this->AppendMode) {
  292. test->AppendProperty(name, value, this->AppendAsString);
  293. } else {
  294. test->SetProperty(name, value);
  295. }
  296. return true;
  297. }
  298. bool cmSetPropertyCommand::HandleCacheMode()
  299. {
  300. if (this->PropertyName == "ADVANCED") {
  301. if (!this->Remove && !cmSystemTools::IsOn(this->PropertyValue.c_str()) &&
  302. !cmSystemTools::IsOff(this->PropertyValue.c_str())) {
  303. std::ostringstream e;
  304. e << "given non-boolean value \"" << this->PropertyValue
  305. << "\" for CACHE property \"ADVANCED\". ";
  306. this->SetError(e.str());
  307. return false;
  308. }
  309. } else if (this->PropertyName == "TYPE") {
  310. if (!cmState::IsCacheEntryType(this->PropertyValue)) {
  311. std::ostringstream e;
  312. e << "given invalid CACHE entry TYPE \"" << this->PropertyValue << "\"";
  313. this->SetError(e.str());
  314. return false;
  315. }
  316. } else if (this->PropertyName != "HELPSTRING" &&
  317. this->PropertyName != "STRINGS" &&
  318. this->PropertyName != "VALUE") {
  319. std::ostringstream e;
  320. e << "given invalid CACHE property " << this->PropertyName << ". "
  321. << "Settable CACHE properties are: "
  322. << "ADVANCED, HELPSTRING, STRINGS, TYPE, and VALUE.";
  323. this->SetError(e.str());
  324. return false;
  325. }
  326. for (std::string const& name : this->Names) {
  327. // Get the source file.
  328. cmMakefile* mf = this->GetMakefile();
  329. cmake* cm = mf->GetCMakeInstance();
  330. const char* existingValue = cm->GetState()->GetCacheEntryValue(name);
  331. if (existingValue) {
  332. if (!this->HandleCacheEntry(name)) {
  333. return false;
  334. }
  335. } else {
  336. std::ostringstream e;
  337. e << "could not find CACHE variable " << name
  338. << ". Perhaps it has not yet been created.";
  339. this->SetError(e.str());
  340. return false;
  341. }
  342. }
  343. return true;
  344. }
  345. bool cmSetPropertyCommand::HandleCacheEntry(std::string const& cacheKey)
  346. {
  347. // Set or append the property.
  348. std::string const& name = this->PropertyName;
  349. const char* value = this->PropertyValue.c_str();
  350. cmState* state = this->Makefile->GetState();
  351. if (this->Remove) {
  352. state->RemoveCacheEntryProperty(cacheKey, name);
  353. }
  354. if (this->AppendMode) {
  355. state->AppendCacheEntryProperty(cacheKey, name, value,
  356. this->AppendAsString);
  357. } else {
  358. state->SetCacheEntryProperty(cacheKey, name, value);
  359. }
  360. return true;
  361. }
  362. bool cmSetPropertyCommand::HandleInstallMode()
  363. {
  364. cmake* cm = this->Makefile->GetCMakeInstance();
  365. for (std::string const& name : this->Names) {
  366. if (cmInstalledFile* file =
  367. cm->GetOrCreateInstalledFile(this->Makefile, name)) {
  368. if (!this->HandleInstall(file)) {
  369. return false;
  370. }
  371. } else {
  372. std::ostringstream e;
  373. e << "given INSTALL name that could not be found or created: " << name;
  374. this->SetError(e.str());
  375. return false;
  376. }
  377. }
  378. return true;
  379. }
  380. bool cmSetPropertyCommand::HandleInstall(cmInstalledFile* file)
  381. {
  382. // Set or append the property.
  383. std::string const& name = this->PropertyName;
  384. cmMakefile* mf = this->Makefile;
  385. const char* value = this->PropertyValue.c_str();
  386. if (this->Remove) {
  387. file->RemoveProperty(name);
  388. } else if (this->AppendMode) {
  389. file->AppendProperty(mf, name, value, this->AppendAsString);
  390. } else {
  391. file->SetProperty(mf, name, value);
  392. }
  393. return true;
  394. }