cmSetPropertyCommand.cxx 12 KB

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