cmSetPropertyCommand.cxx 12 KB

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