cmSetPropertyCommand.cxx 12 KB

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