cmGlobalXCodeGenerator.cxx 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968
  1. /*=========================================================================
  2. Program: CMake - Cross-Platform Makefile Generator
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
  8. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
  9. This software is distributed WITHOUT ANY WARRANTY; without even
  10. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the above copyright notices for more information.
  12. =========================================================================*/
  13. #include "cmGlobalXCodeGenerator.h"
  14. #include "cmLocalXCodeGenerator.h"
  15. #include "cmMakefile.h"
  16. #include "cmXCodeObject.h"
  17. #include "cmake.h"
  18. #include "cmGeneratedFileStream.h"
  19. #include "cmSourceFile.h"
  20. //TODO
  21. // custom commands
  22. // custom targets
  23. // ALL_BUILD
  24. // RUN_TESTS
  25. // add a group for Sources Headers, and other cmake group stuff
  26. // for each target create a custom build phase that is run first
  27. // it can have inputs and outputs should just be a makefile
  28. // per file flags howto
  29. // 115281011528101152810000 = {
  30. // fileEncoding = 4;
  31. // isa = PBXFileReference;
  32. // lastKnownFileType = sourcecode.cpp.cpp;
  33. // path = /Users/kitware/Bill/CMake/Source/cmakemain.cxx;
  34. // refType = 0;
  35. // sourceTree = "<absolute>";
  36. // };
  37. // 115285011528501152850000 = {
  38. // fileRef = 115281011528101152810000;
  39. // isa = PBXBuildFile;
  40. // settings = {
  41. // COMPILER_FLAGS = "-Dcmakemakeindefflag";
  42. // };
  43. // };
  44. // custom commands and clean up custom targets
  45. // do I need an ALL_BUILD yes
  46. // exe/lib output paths
  47. //----------------------------------------------------------------------------
  48. cmGlobalXCodeGenerator::cmGlobalXCodeGenerator()
  49. {
  50. m_FindMakeProgramFile = "CMakeFindXCode.cmake";
  51. m_RootObject = 0;
  52. m_MainGroupChildren = 0;
  53. m_SourcesGroupChildren = 0;
  54. m_ExternalGroupChildren = 0;
  55. }
  56. //----------------------------------------------------------------------------
  57. void cmGlobalXCodeGenerator::EnableLanguage(std::vector<std::string>const&
  58. lang,
  59. cmMakefile * mf)
  60. {
  61. mf->AddDefinition("CMAKE_GENERATOR_CC", "gcc");
  62. mf->AddDefinition("CMAKE_GENERATOR_CXX", "g++");
  63. mf->AddDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV", "1");
  64. this->cmGlobalGenerator::EnableLanguage(lang, mf);
  65. }
  66. //----------------------------------------------------------------------------
  67. int cmGlobalXCodeGenerator::TryCompile(const char *,
  68. const char * bindir,
  69. const char * projectName,
  70. const char * targetName,
  71. std::string * output,
  72. cmMakefile*)
  73. {
  74. // now build the test
  75. std::string makeCommand =
  76. m_CMakeInstance->GetCacheManager()->GetCacheValue("CMAKE_MAKE_PROGRAM");
  77. if(makeCommand.size() == 0)
  78. {
  79. cmSystemTools::Error(
  80. "Generator cannot find the appropriate make command.");
  81. return 1;
  82. }
  83. makeCommand = cmSystemTools::ConvertToOutputPath(makeCommand.c_str());
  84. std::string lowerCaseCommand = makeCommand;
  85. cmSystemTools::LowerCase(lowerCaseCommand);
  86. /**
  87. * Run an executable command and put the stdout in output.
  88. */
  89. std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
  90. cmSystemTools::ChangeDirectory(bindir);
  91. // Usage: xcodebuild [-project <projectname>] [-activetarget]
  92. // [-alltargets] [-target <targetname>]... [-activebuildstyle]
  93. // [-buildstyle <buildstylename>] [-optionalbuildstyle <buildstylename>]
  94. // [<buildsetting>=<value>]... [<buildaction>]...
  95. // xcodebuild [-list]
  96. makeCommand += " -project ";
  97. makeCommand += projectName;
  98. makeCommand += ".xcode";
  99. makeCommand += " build ";
  100. if (targetName)
  101. {
  102. makeCommand += "-target ";
  103. makeCommand += targetName;
  104. }
  105. makeCommand += " -buildstyle Development ";
  106. makeCommand += " SYMROOT=";
  107. makeCommand += cmSystemTools::ConvertToOutputPath(bindir);
  108. int retVal;
  109. int timeout = cmGlobalGenerator::s_TryCompileTimeout;
  110. if (!cmSystemTools::RunSingleCommand(makeCommand.c_str(), output, &retVal,
  111. 0, false, timeout))
  112. {
  113. cmSystemTools::Error("Generator: execution of xcodebuild failed.");
  114. // return to the original directory
  115. cmSystemTools::ChangeDirectory(cwd.c_str());
  116. return 1;
  117. }
  118. cmSystemTools::ChangeDirectory(cwd.c_str());
  119. return retVal;
  120. }
  121. void cmGlobalXCodeGenerator::ConfigureOutputPaths()
  122. {
  123. // Format the library and executable output paths.
  124. m_LibraryOutputPath =
  125. m_CurrentMakefile->GetSafeDefinition("LIBRARY_OUTPUT_PATH");
  126. if(m_LibraryOutputPath.size() == 0)
  127. {
  128. m_LibraryOutputPath = m_CurrentMakefile->GetCurrentOutputDirectory();
  129. }
  130. // make sure there is a trailing slash
  131. if(m_LibraryOutputPath.size() &&
  132. m_LibraryOutputPath[m_LibraryOutputPath.size()-1] != '/')
  133. {
  134. m_LibraryOutputPath += "/";
  135. if(!cmSystemTools::MakeDirectory(m_LibraryOutputPath.c_str()))
  136. {
  137. cmSystemTools::Error("Error creating directory ",
  138. m_LibraryOutputPath.c_str());
  139. }
  140. }
  141. m_CurrentMakefile->AddLinkDirectory(m_LibraryOutputPath.c_str());
  142. m_ExecutableOutputPath =
  143. m_CurrentMakefile->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH");
  144. if(m_ExecutableOutputPath.size() == 0)
  145. {
  146. m_ExecutableOutputPath = m_CurrentMakefile->GetCurrentOutputDirectory();
  147. }
  148. // make sure there is a trailing slash
  149. if(m_ExecutableOutputPath.size() &&
  150. m_ExecutableOutputPath[m_ExecutableOutputPath.size()-1] != '/')
  151. {
  152. m_ExecutableOutputPath += "/";
  153. if(!cmSystemTools::MakeDirectory(m_ExecutableOutputPath.c_str()))
  154. {
  155. cmSystemTools::Error("Error creating directory ",
  156. m_ExecutableOutputPath.c_str());
  157. }
  158. }
  159. }
  160. //----------------------------------------------------------------------------
  161. ///! Create a local generator appropriate to this Global Generator
  162. cmLocalGenerator *cmGlobalXCodeGenerator::CreateLocalGenerator()
  163. {
  164. cmLocalGenerator *lg = new cmLocalXCodeGenerator;
  165. lg->SetGlobalGenerator(this);
  166. return lg;
  167. }
  168. //----------------------------------------------------------------------------
  169. void cmGlobalXCodeGenerator::Generate()
  170. {
  171. this->cmGlobalGenerator::Generate();
  172. std::map<cmStdString, std::vector<cmLocalGenerator*> >::iterator it;
  173. for(it = m_ProjectMap.begin(); it!= m_ProjectMap.end(); ++it)
  174. {
  175. this->OutputXCodeProject(it->second[0], it->second);
  176. }
  177. }
  178. //----------------------------------------------------------------------------
  179. void cmGlobalXCodeGenerator::ClearXCodeObjects()
  180. {
  181. for(unsigned int i = 0; i < m_XCodeObjects.size(); ++i)
  182. {
  183. delete m_XCodeObjects[i];
  184. }
  185. m_XCodeObjects.clear();
  186. }
  187. //----------------------------------------------------------------------------
  188. cmXCodeObject*
  189. cmGlobalXCodeGenerator::CreateObject(cmXCodeObject::PBXType ptype)
  190. {
  191. cmXCodeObject* obj = new cmXCodeObject(ptype, cmXCodeObject::OBJECT);
  192. m_XCodeObjects.push_back(obj);
  193. return obj;
  194. }
  195. //----------------------------------------------------------------------------
  196. cmXCodeObject*
  197. cmGlobalXCodeGenerator::CreateObject(cmXCodeObject::Type type)
  198. {
  199. cmXCodeObject* obj = new cmXCodeObject(cmXCodeObject::None, type);
  200. m_XCodeObjects.push_back(obj);
  201. return obj;
  202. }
  203. cmXCodeObject*
  204. cmGlobalXCodeGenerator::CreateString(const char* s)
  205. {
  206. cmXCodeObject* obj = this->CreateObject(cmXCodeObject::STRING);
  207. obj->SetString(s);
  208. return obj;
  209. }
  210. cmXCodeObject* cmGlobalXCodeGenerator::CreateObjectReference(cmXCodeObject* ref)
  211. {
  212. cmXCodeObject* obj = this->CreateObject(cmXCodeObject::OBJECT_REF);
  213. obj->SetObject(ref);
  214. return obj;
  215. }
  216. cmXCodeObject*
  217. cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg,
  218. cmSourceFile* sf)
  219. {
  220. std::string flags;
  221. // Add flags from source file properties.
  222. m_CurrentLocalGenerator
  223. ->AppendFlags(flags, sf->GetProperty("COMPILE_FLAGS"));
  224. cmXCodeObject* fileRef = this->CreateObject(cmXCodeObject::PBXFileReference);
  225. m_SourcesGroupChildren->AddObject(fileRef);
  226. cmXCodeObject* buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
  227. buildFile->AddAttribute("fileRef", this->CreateObjectReference(fileRef));
  228. cmXCodeObject* settings = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
  229. settings->AddAttribute("COMPILER_FLAGS", this->CreateString(flags.c_str()));
  230. buildFile->AddAttribute("settings", settings);
  231. fileRef->AddAttribute("fileEncoding", this->CreateString("4"));
  232. const char* lang =
  233. this->GetLanguageFromExtension(sf->GetSourceExtension().c_str());
  234. std::string sourcecode = "sourcecode";
  235. if(!lang)
  236. {
  237. std::string ext = ".";
  238. ext = sf->GetSourceExtension();
  239. sourcecode += ext;
  240. sourcecode += ext;
  241. }
  242. else if(strcmp(lang, "C") == 0)
  243. {
  244. sourcecode += ".c.c";
  245. }
  246. // default to c++
  247. else
  248. {
  249. sourcecode += ".cpp.cpp";
  250. }
  251. fileRef->AddAttribute("lastKnownFileType",
  252. this->CreateString(sourcecode.c_str()));
  253. fileRef->AddAttribute("path", this->CreateString(
  254. lg->ConvertToRelativeOutputPath(sf->GetFullPath().c_str()).c_str()));
  255. fileRef->AddAttribute("refType", this->CreateString("4"));
  256. fileRef->AddAttribute("sourceTree", this->CreateString("<absolute>"));
  257. return buildFile;
  258. }
  259. //----------------------------------------------------------------------------
  260. void
  261. cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen,
  262. std::vector<cmXCodeObject*>&
  263. targets)
  264. {
  265. m_CurrentLocalGenerator = gen;
  266. m_CurrentMakefile = gen->GetMakefile();
  267. cmTargets &tgts = gen->GetMakefile()->GetTargets();
  268. for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++)
  269. {
  270. cmTarget& cmtarget = l->second;
  271. if(cmtarget.GetType() == cmTarget::UTILITY ||
  272. cmtarget.GetType() == cmTarget::INSTALL_FILES ||
  273. cmtarget.GetType() == cmTarget::INSTALL_PROGRAMS)
  274. {
  275. if(cmtarget.GetType() == cmTarget::UTILITY)
  276. {
  277. targets.push_back(this->CreateUtilityTarget(cmtarget));
  278. }
  279. continue;
  280. }
  281. // create source build phase
  282. cmXCodeObject* sourceBuildPhase =
  283. this->CreateObject(cmXCodeObject::PBXSourcesBuildPhase);
  284. sourceBuildPhase->AddAttribute("buildActionMask",
  285. this->CreateString("2147483647"));
  286. cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  287. sourceBuildPhase->AddAttribute("files", buildFiles);
  288. sourceBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
  289. this->CreateString("0"));
  290. std::vector<cmSourceFile*> &classes = l->second.GetSourceFiles();
  291. // add all the sources
  292. for(std::vector<cmSourceFile*>::iterator i = classes.begin();
  293. i != classes.end(); ++i)
  294. {
  295. buildFiles->AddObject(this->CreateXCodeSourceFile(gen, *i));
  296. }
  297. // create header build phase
  298. cmXCodeObject* headerBuildPhase =
  299. this->CreateObject(cmXCodeObject::PBXHeadersBuildPhase);
  300. headerBuildPhase->AddAttribute("buildActionMask",
  301. this->CreateString("2147483647"));
  302. buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  303. headerBuildPhase->AddAttribute("files", buildFiles);
  304. headerBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
  305. this->CreateString("0"));
  306. // create framework build phase
  307. cmXCodeObject* frameworkBuildPhase =
  308. this->CreateObject(cmXCodeObject::PBXFrameworksBuildPhase);
  309. frameworkBuildPhase->AddAttribute("buildActionMask",
  310. this->CreateString("2147483647"));
  311. buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  312. frameworkBuildPhase->AddAttribute("files", buildFiles);
  313. frameworkBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
  314. this->CreateString("0"));
  315. cmXCodeObject* buildPhases =
  316. this->CreateObject(cmXCodeObject::OBJECT_LIST);
  317. buildPhases->AddObject(sourceBuildPhase);
  318. buildPhases->AddObject(headerBuildPhase);
  319. buildPhases->AddObject(frameworkBuildPhase);
  320. targets.push_back(this->CreateXCodeTarget(l->second, buildPhases));
  321. }
  322. }
  323. void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
  324. cmXCodeObject* buildSettings,
  325. std::string& fileType,
  326. std::string& productType,
  327. std::string& productName)
  328. {
  329. this->ConfigureOutputPaths();
  330. std::string flags;
  331. bool shared = ((target.GetType() == cmTarget::SHARED_LIBRARY) ||
  332. (target.GetType() == cmTarget::MODULE_LIBRARY));
  333. if(shared)
  334. {
  335. flags += "-D";
  336. if(const char* custom_export_name = target.GetProperty("DEFINE_SYMBOL"))
  337. {
  338. flags += custom_export_name;
  339. }
  340. else
  341. {
  342. std::string in = target.GetName();
  343. in += "_EXPORTS";
  344. flags += cmSystemTools::MakeCindentifier(in.c_str());
  345. }
  346. }
  347. const char* lang = target.GetLinkerLanguage(this);
  348. if(lang)
  349. {
  350. // Add language-specific flags.
  351. m_CurrentLocalGenerator->AddLanguageFlags(flags, lang);
  352. // Add shared-library flags if needed.
  353. m_CurrentLocalGenerator->AddSharedFlags(flags, lang, shared);
  354. }
  355. // Add define flags
  356. m_CurrentLocalGenerator->AppendFlags(flags,
  357. m_CurrentMakefile->GetDefineFlags());
  358. cmSystemTools::ReplaceString(flags, "\"", "\\\"");
  359. productName = target.GetName();
  360. bool needLinkDirs = true;
  361. switch(target.GetType())
  362. {
  363. case cmTarget::STATIC_LIBRARY:
  364. {
  365. needLinkDirs = false;
  366. if(m_LibraryOutputPath.size())
  367. {
  368. buildSettings->AddAttribute("SYMROOT",
  369. this->CreateString
  370. (m_LibraryOutputPath.c_str()));
  371. }
  372. productName += ".a";
  373. std::string t = "lib";
  374. t += productName;
  375. productName = t;
  376. productType = "com.apple.product-type.library.static";
  377. fileType = "archive.ar";
  378. buildSettings->AddAttribute("LIBRARY_STYLE",
  379. this->CreateString("STATIC"));
  380. break;
  381. }
  382. case cmTarget::MODULE_LIBRARY:
  383. {
  384. if(m_LibraryOutputPath.size())
  385. {
  386. buildSettings->AddAttribute("SYMROOT",
  387. this->CreateString
  388. (m_LibraryOutputPath.c_str()));
  389. }
  390. buildSettings->AddAttribute("LIBRARY_STYLE",
  391. this->CreateString("DYNAMIC"));
  392. productName += ".so";
  393. std::string t = "lib";
  394. t += productName;
  395. productName = t;
  396. buildSettings->AddAttribute("OTHER_LDFLAGS",
  397. this->CreateString("-bundle"));
  398. productType = "com.apple.product-type.library.dynamic";
  399. fileType = "compiled.mach-o.dylib";
  400. break;
  401. }
  402. case cmTarget::SHARED_LIBRARY:
  403. {
  404. if(m_LibraryOutputPath.size())
  405. {
  406. buildSettings->AddAttribute("SYMROOT",
  407. this->CreateString
  408. (m_LibraryOutputPath.c_str()));
  409. }
  410. buildSettings->AddAttribute("LIBRARY_STYLE",
  411. this->CreateString("DYNAMIC"));
  412. productName += ".dylib";
  413. std::string t = "lib";
  414. t += productName;
  415. productName = t;
  416. buildSettings->AddAttribute("DYLIB_COMPATIBILITY_VERSION",
  417. this->CreateString("1"));
  418. buildSettings->AddAttribute("DYLIB_CURRENT_VERSION",
  419. this->CreateString("1"));
  420. buildSettings->AddAttribute("OTHER_LDFLAGS",
  421. this->CreateString("-dynamiclib"));
  422. productType = "com.apple.product-type.library.dynamic";
  423. fileType = "compiled.mach-o.dylib";
  424. break;
  425. }
  426. case cmTarget::EXECUTABLE:
  427. if(m_ExecutableOutputPath.size())
  428. {
  429. buildSettings->AddAttribute("SYMROOT",
  430. this->CreateString
  431. (m_ExecutableOutputPath.c_str()));
  432. }
  433. fileType = "compiled.mach-o.executable";
  434. productType = "com.apple.product-type.tool";
  435. break;
  436. case cmTarget::UTILITY:
  437. break;
  438. case cmTarget::INSTALL_FILES:
  439. break;
  440. case cmTarget::INSTALL_PROGRAMS:
  441. break;
  442. }
  443. std::string dirs;
  444. if(needLinkDirs)
  445. {
  446. // Try to emit each search path once
  447. std::set<cmStdString> emitted;
  448. // Some search paths should never be emitted
  449. emitted.insert("");
  450. emitted.insert("/usr/lib");
  451. std::vector<std::string> const& linkdirs =
  452. target.GetLinkDirectories();
  453. for(std::vector<std::string>::const_iterator l = linkdirs.begin();
  454. l != linkdirs.end(); ++l)
  455. {
  456. std::string libpath =
  457. m_CurrentLocalGenerator->ConvertToOutputForExisting(l->c_str());
  458. if(emitted.insert(libpath).second)
  459. {
  460. dirs += libpath + " ";
  461. }
  462. }
  463. if(dirs.size())
  464. {
  465. buildSettings->AddAttribute("LIBRARY_SEARCH_PATHS",
  466. this->CreateString(dirs.c_str()));
  467. }
  468. }
  469. dirs = "";
  470. std::vector<std::string>& includes =
  471. m_CurrentMakefile->GetIncludeDirectories();
  472. std::vector<std::string>::iterator i = includes.begin();
  473. for(;i != includes.end(); ++i)
  474. {
  475. std::string incpath =
  476. m_CurrentLocalGenerator->ConvertToOutputForExisting(i->c_str());
  477. dirs += incpath + " ";
  478. }
  479. if(dirs.size())
  480. {
  481. buildSettings->AddAttribute("HEADER_SEARCH_PATHS",
  482. this->CreateString(dirs.c_str()));
  483. }
  484. buildSettings->AddAttribute("GCC_OPTIMIZATION_LEVEL",
  485. this->CreateString("0"));
  486. buildSettings->AddAttribute("INSTALL_PATH",
  487. this->CreateString("/usr/local/bin"));
  488. buildSettings->AddAttribute("OPTIMIZATION_CFLAGS",
  489. this->CreateString(""));
  490. buildSettings->AddAttribute("OTHER_CFLAGS",
  491. this->CreateString(flags.c_str()));
  492. buildSettings->AddAttribute("OTHER_LDFLAGS",
  493. this->CreateString(""));
  494. buildSettings->AddAttribute("OTHER_REZFLAGS",
  495. this->CreateString(""));
  496. buildSettings->AddAttribute("SECTORDER_FLAGS",
  497. this->CreateString(""));
  498. buildSettings->AddAttribute("WARNING_CFLAGS",
  499. this->CreateString(
  500. "-Wmost -Wno-four-char-constants"
  501. " -Wno-unknown-pragmas"));
  502. buildSettings->AddAttribute("PRODUCT_NAME",
  503. this->CreateString(target.GetName()));
  504. }
  505. cmXCodeObject*
  506. cmGlobalXCodeGenerator::CreateUtilityTarget(cmTarget& cmtarget)
  507. {
  508. cmXCodeObject* shellBuildPhase =
  509. this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase);
  510. shellBuildPhase->AddAttribute("buildActionMask",
  511. this->CreateString("2147483647"));
  512. cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  513. shellBuildPhase->AddAttribute("files", buildFiles);
  514. cmXCodeObject* inputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  515. shellBuildPhase->AddAttribute("inputPaths", inputPaths);
  516. cmXCodeObject* outputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  517. shellBuildPhase->AddAttribute("outputPaths", outputPaths);
  518. shellBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
  519. this->CreateString("0"));
  520. shellBuildPhase->AddAttribute("shellPath",
  521. this->CreateString("/bin/sh"));
  522. shellBuildPhase->AddAttribute("shellScript",
  523. this->CreateString(
  524. "# shell script goes here\nexit 0"));
  525. cmXCodeObject* target =
  526. this->CreateObject(cmXCodeObject::PBXAggregateTarget);
  527. cmXCodeObject* buildPhases =
  528. this->CreateObject(cmXCodeObject::OBJECT_LIST);
  529. buildPhases->AddObject(shellBuildPhase);
  530. target->AddAttribute("buildPhases", buildPhases);
  531. cmXCodeObject* buildSettings =
  532. this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
  533. std::string fileTypeString;
  534. std::string productTypeString;
  535. std::string productName;
  536. this->CreateBuildSettings(cmtarget,
  537. buildSettings, fileTypeString,
  538. productTypeString, productName);
  539. target->AddAttribute("buildSettings", buildSettings);
  540. cmXCodeObject* dependencies = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  541. target->AddAttribute("dependencies", dependencies);
  542. target->AddAttribute("name", this->CreateString(cmtarget.GetName()));
  543. target->AddAttribute("productName",this->CreateString(cmtarget.GetName()));
  544. target->SetcmTarget(&cmtarget);
  545. return target;
  546. }
  547. cmXCodeObject*
  548. cmGlobalXCodeGenerator::CreateXCodeTarget(cmTarget& cmtarget,
  549. cmXCodeObject* buildPhases)
  550. {
  551. cmXCodeObject* target =
  552. this->CreateObject(cmXCodeObject::PBXNativeTarget);
  553. target->AddAttribute("buildPhases", buildPhases);
  554. cmXCodeObject* buildRules = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  555. target->AddAttribute("buildRules", buildRules);
  556. cmXCodeObject* buildSettings =
  557. this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
  558. std::string fileTypeString;
  559. std::string productTypeString;
  560. std::string productName;
  561. this->CreateBuildSettings(cmtarget,
  562. buildSettings, fileTypeString,
  563. productTypeString, productName);
  564. target->AddAttribute("buildSettings", buildSettings);
  565. cmXCodeObject* dependencies = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  566. target->AddAttribute("dependencies", dependencies);
  567. target->AddAttribute("name", this->CreateString(cmtarget.GetName()));
  568. target->AddAttribute("productName",this->CreateString(cmtarget.GetName()));
  569. cmXCodeObject* fileRef = this->CreateObject(cmXCodeObject::PBXFileReference);
  570. fileRef->AddAttribute("explicitFileType",
  571. this->CreateString(fileTypeString.c_str()));
  572. fileRef->AddAttribute("path", this->CreateString(productName.c_str()));
  573. fileRef->AddAttribute("refType", this->CreateString("0"));
  574. fileRef->AddAttribute("sourceTree",
  575. this->CreateString("BUILT_PRODUCTS_DIR"));
  576. target->AddAttribute("productReference",
  577. this->CreateObjectReference(fileRef));
  578. target->AddAttribute("productType",
  579. this->CreateString(productTypeString.c_str()));
  580. target->SetcmTarget(&cmtarget);
  581. return target;
  582. }
  583. cmXCodeObject* cmGlobalXCodeGenerator::FindXCodeTarget(cmTarget* t)
  584. {
  585. if(!t)
  586. {
  587. return 0;
  588. }
  589. for(std::vector<cmXCodeObject*>::iterator i = m_XCodeObjects.begin();
  590. i != m_XCodeObjects.end(); ++i)
  591. {
  592. cmXCodeObject* o = *i;
  593. if(o->GetcmTarget() == t)
  594. {
  595. return o;
  596. }
  597. }
  598. return 0;
  599. }
  600. void cmGlobalXCodeGenerator::AddDependTarget(cmXCodeObject* target,
  601. cmXCodeObject* dependTarget)
  602. {
  603. cmXCodeObject* targetdep = dependTarget->GetPBXTargetDependency();
  604. if(!targetdep)
  605. {
  606. cmXCodeObject* container =
  607. this->CreateObject(cmXCodeObject::PBXContainerItemProxy);
  608. container->AddAttribute("containerPortal",
  609. this->CreateObjectReference(m_RootObject));
  610. container->AddAttribute("proxyType", this->CreateString("1"));
  611. container->AddAttribute("remoteGlobalIDString",
  612. this->CreateObjectReference(dependTarget));
  613. container->AddAttribute("remoteInfo",
  614. this->CreateString(
  615. dependTarget->GetcmTarget()->GetName()));
  616. targetdep =
  617. this->CreateObject(cmXCodeObject::PBXTargetDependency);
  618. targetdep->AddAttribute("target",
  619. this->CreateObjectReference(dependTarget));
  620. targetdep->AddAttribute("targetProxy",
  621. this->CreateObjectReference(container));
  622. dependTarget->SetPBXTargetDependency(targetdep);
  623. }
  624. cmXCodeObject* depends = target->GetObject("dependencies");
  625. if(!depends)
  626. {
  627. std::cerr << "target does not have dependencies attribute error...\n";
  628. }
  629. else
  630. {
  631. depends->AddObject(targetdep);
  632. }
  633. }
  634. void cmGlobalXCodeGenerator::AddLinkTarget(cmXCodeObject* target ,
  635. cmXCodeObject* dependTarget )
  636. {
  637. cmXCodeObject* ref = dependTarget->GetObject("productReference");
  638. cmXCodeObject* buildfile = this->CreateObject(cmXCodeObject::PBXBuildFile);
  639. buildfile->AddAttribute("fileRef", ref);
  640. cmXCodeObject* settings =
  641. this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
  642. buildfile->AddAttribute("settings", settings);
  643. cmXCodeObject* buildPhases = target->GetObject("buildPhases");
  644. cmXCodeObject* frameworkBuildPhase =
  645. buildPhases->GetObject(cmXCodeObject::PBXFrameworksBuildPhase);
  646. cmXCodeObject* files = frameworkBuildPhase->GetObject("files");
  647. files->AddObject(buildfile);
  648. }
  649. void cmGlobalXCodeGenerator::AddLinkLibrary(cmXCodeObject* target,
  650. const char* library)
  651. {
  652. // if the library is a full path then create a file reference
  653. // and build file and add them to the PBXFrameworksBuildPhase
  654. // for the target
  655. if(cmSystemTools::FileIsFullPath(library))
  656. {
  657. std::string libPath = library;
  658. cmXCodeObject* fileRef =
  659. this->CreateObject(cmXCodeObject::PBXFileReference);
  660. if(libPath[libPath.size()-1] == 'a')
  661. {
  662. fileRef->AddAttribute("lastKnownFileType",
  663. this->CreateString("archive.ar"));
  664. }
  665. else
  666. {
  667. fileRef->AddAttribute("lastKnownFileType",
  668. this->CreateString("compiled.mach-o.dylib"));
  669. }
  670. fileRef->AddAttribute("name",
  671. this->CreateString(
  672. cmSystemTools::GetFilenameName(libPath).c_str()));
  673. fileRef->AddAttribute("path", this->CreateString(libPath.c_str()));
  674. fileRef->AddAttribute("refType", this->CreateString("0"));
  675. fileRef->AddAttribute("sourceTree", this->CreateString("<absolute>"));
  676. cmXCodeObject* buildfile = this->CreateObject(cmXCodeObject::PBXBuildFile);
  677. buildfile->AddAttribute("fileRef", this->CreateObjectReference(fileRef));
  678. cmXCodeObject* settings =
  679. this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
  680. buildfile->AddAttribute("settings", settings);
  681. // get the framework build phase from the target
  682. cmXCodeObject* buildPhases = target->GetObject("buildPhases");
  683. cmXCodeObject* frameworkBuildPhase =
  684. buildPhases->GetObject(cmXCodeObject::PBXFrameworksBuildPhase);
  685. cmXCodeObject* files = frameworkBuildPhase->GetObject("files");
  686. files->AddObject(buildfile);
  687. m_ExternalGroupChildren->AddObject(fileRef);
  688. }
  689. else
  690. {
  691. // if the library is not a full path then add it with a -l flag
  692. // to the settings of the target
  693. cmXCodeObject* settings = target->GetObject("buildSettings");
  694. cmXCodeObject* ldflags = settings->GetObject("OTHER_LDFLAGS");
  695. std::string link = ldflags->GetString();
  696. cmSystemTools::ReplaceString(link, "\"", "");
  697. cmsys::RegularExpression reg("^([ \t]*\\-[lWRB])|([ \t]*\\-framework)|(\\${)|([ \t]*\\-pthread)|([ \t]*`)");
  698. // if the library is not already in the form required by the compiler
  699. // add a -l infront of the name
  700. if(!reg.find(library))
  701. {
  702. link += " -l";
  703. }
  704. link += library;
  705. ldflags->SetString(link.c_str());
  706. }
  707. }
  708. void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
  709. {
  710. cmTarget* cmtarget = target->GetcmTarget();
  711. if(!cmtarget)
  712. {
  713. std::cerr << "Error no target on xobject\n";
  714. return;
  715. }
  716. cmTarget::LinkLibraries::const_iterator j, jend;
  717. j = cmtarget->GetLinkLibraries().begin();
  718. jend = cmtarget->GetLinkLibraries().end();
  719. for(;j!= jend; ++j)
  720. {
  721. cmTarget* t = this->FindTarget(j->first.c_str());
  722. cmXCodeObject* dptarget = this->FindXCodeTarget(t);
  723. if(dptarget)
  724. {
  725. this->AddDependTarget(target, dptarget);
  726. if(cmtarget->GetType() != cmTarget::STATIC_LIBRARY)
  727. {
  728. this->AddLinkTarget(target, dptarget);
  729. }
  730. }
  731. else
  732. {
  733. if(cmtarget->GetType() != cmTarget::STATIC_LIBRARY)
  734. {
  735. this->AddLinkLibrary(target, j->first.c_str());
  736. }
  737. }
  738. }
  739. std::set<cmStdString>::const_iterator i, end;
  740. // write utility dependencies.
  741. i = cmtarget->GetUtilities().begin();
  742. end = cmtarget->GetUtilities().end();
  743. for(;i!= end; ++i)
  744. {
  745. cmTarget* t = this->FindTarget(i->c_str());
  746. cmXCodeObject* dptarget = this->FindXCodeTarget(t);
  747. if(dptarget)
  748. {
  749. this->AddDependTarget(target, dptarget);
  750. }
  751. else
  752. {
  753. std::cerr << "Error External Util???: " << i->c_str() << "\n";
  754. }
  755. }
  756. }
  757. // to force the location of a target
  758. // add this to build settings of target SYMROOT = /tmp/;
  759. //----------------------------------------------------------------------------
  760. void cmGlobalXCodeGenerator::CreateXCodeObjects(cmLocalGenerator* ,
  761. std::vector<cmLocalGenerator*>&
  762. generators
  763. )
  764. {
  765. this->ClearXCodeObjects();
  766. m_RootObject = 0;
  767. m_ExternalGroupChildren = 0;
  768. m_SourcesGroupChildren = 0;
  769. m_MainGroupChildren = 0;
  770. cmXCodeObject* group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
  771. group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
  772. cmXCodeObject* developBuildStyle =
  773. this->CreateObject(cmXCodeObject::PBXBuildStyle);
  774. developBuildStyle->AddAttribute("name", this->CreateString("Development"));
  775. developBuildStyle->AddAttribute("buildSettings", group);
  776. group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
  777. group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("YES"));
  778. cmXCodeObject* deployBuildStyle =
  779. this->CreateObject(cmXCodeObject::PBXBuildStyle);
  780. deployBuildStyle->AddAttribute("name", this->CreateString("Deployment"));
  781. deployBuildStyle->AddAttribute("buildSettings", group);
  782. cmXCodeObject* listObjs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  783. listObjs->AddObject(developBuildStyle);
  784. listObjs->AddObject(deployBuildStyle);
  785. cmXCodeObject* mainGroup = this->CreateObject(cmXCodeObject::PBXGroup);
  786. m_MainGroupChildren =
  787. this->CreateObject(cmXCodeObject::OBJECT_LIST);
  788. mainGroup->AddAttribute("children", m_MainGroupChildren);
  789. mainGroup->AddAttribute("refType", this->CreateString("4"));
  790. mainGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
  791. cmXCodeObject* sourcesGroup = this->CreateObject(cmXCodeObject::PBXGroup);
  792. m_SourcesGroupChildren =
  793. this->CreateObject(cmXCodeObject::OBJECT_LIST);
  794. sourcesGroup->AddAttribute("name", this->CreateString("Sources"));
  795. sourcesGroup->AddAttribute("children", m_SourcesGroupChildren);
  796. sourcesGroup->AddAttribute("refType", this->CreateString("4"));
  797. sourcesGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
  798. m_MainGroupChildren->AddObject(sourcesGroup);
  799. cmXCodeObject* externalGroup = this->CreateObject(cmXCodeObject::PBXGroup);
  800. m_ExternalGroupChildren =
  801. this->CreateObject(cmXCodeObject::OBJECT_LIST);
  802. externalGroup->AddAttribute("name",
  803. this->CreateString("External Libraries and Frameworks"));
  804. externalGroup->AddAttribute("children", m_ExternalGroupChildren);
  805. externalGroup->AddAttribute("refType", this->CreateString("4"));
  806. externalGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
  807. m_MainGroupChildren->AddObject(externalGroup);
  808. cmXCodeObject* productGroup = this->CreateObject(cmXCodeObject::PBXGroup);
  809. productGroup->AddAttribute("name", this->CreateString("Products"));
  810. productGroup->AddAttribute("refType", this->CreateString("4"));
  811. productGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
  812. cmXCodeObject* productGroupChildren =
  813. this->CreateObject(cmXCodeObject::OBJECT_LIST);
  814. productGroup->AddAttribute("children", productGroupChildren);
  815. m_MainGroupChildren->AddObject(productGroup);
  816. m_RootObject = this->CreateObject(cmXCodeObject::PBXProject);
  817. group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
  818. m_RootObject->AddAttribute("mainGroup",
  819. this->CreateObjectReference(mainGroup));
  820. m_RootObject->AddAttribute("buildSettings", group);
  821. m_RootObject->AddAttribute("buildSyles", listObjs);
  822. m_RootObject->AddAttribute("hasScannedForEncodings",
  823. this->CreateString("0"));
  824. std::vector<cmXCodeObject*> targets;
  825. for(std::vector<cmLocalGenerator*>::iterator i = generators.begin();
  826. i != generators.end(); ++i)
  827. {
  828. this->CreateXCodeTargets(*i, targets);
  829. }
  830. cmXCodeObject* allTargets = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  831. for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
  832. i != targets.end(); ++i)
  833. {
  834. cmXCodeObject* t = *i;
  835. this->AddDependAndLinkInformation(t);
  836. allTargets->AddObject(t);
  837. cmXCodeObject* productRef = t->GetObject("productReference");
  838. if(productRef)
  839. {
  840. productGroupChildren->AddObject(productRef->GetObject());
  841. }
  842. }
  843. m_RootObject->AddAttribute("targets", allTargets);
  844. }
  845. //----------------------------------------------------------------------------
  846. void
  847. cmGlobalXCodeGenerator::OutputXCodeProject(cmLocalGenerator* root,
  848. std::vector<cmLocalGenerator*>&
  849. generators)
  850. {
  851. if(generators.size() == 0)
  852. {
  853. return;
  854. }
  855. this->CreateXCodeObjects(root,
  856. generators);
  857. std::string xcodeDir = root->GetMakefile()->GetStartOutputDirectory();
  858. xcodeDir += "/";
  859. xcodeDir += root->GetMakefile()->GetProjectName();
  860. xcodeDir += ".xcode";
  861. cmSystemTools::MakeDirectory(xcodeDir.c_str());
  862. xcodeDir += "/project.pbxproj";
  863. cmGeneratedFileStream fout(xcodeDir.c_str());
  864. fout.SetCopyIfDifferent(true);
  865. if(!fout)
  866. {
  867. return;
  868. }
  869. this->WriteXCodePBXProj(fout, root, generators);
  870. this->ClearXCodeObjects();
  871. }
  872. //----------------------------------------------------------------------------
  873. void
  874. cmGlobalXCodeGenerator::WriteXCodePBXProj(std::ostream& fout,
  875. cmLocalGenerator* ,
  876. std::vector<cmLocalGenerator*>& )
  877. {
  878. fout << "// !$*UTF8*$!\n";
  879. fout << "{\n";
  880. cmXCodeObject::Indent(1, fout);
  881. fout << "archiveVersion = 1;\n";
  882. cmXCodeObject::Indent(1, fout);
  883. fout << "classes = {\n";
  884. cmXCodeObject::Indent(1, fout);
  885. fout << "};\n";
  886. cmXCodeObject::Indent(1, fout);
  887. fout << "objectVersion = 39;\n";
  888. cmXCodeObject::PrintList(m_XCodeObjects, fout);
  889. cmXCodeObject::Indent(1, fout);
  890. fout << "rootObject = " << m_RootObject->GetId() << ";\n";
  891. fout << "}\n";
  892. }
  893. //----------------------------------------------------------------------------
  894. void cmGlobalXCodeGenerator::GetDocumentation(cmDocumentationEntry& entry)
  895. const
  896. {
  897. entry.name = this->GetName();
  898. entry.brief = "Generate XCode project files.";
  899. entry.full = "";
  900. }