cmGlobalXCodeGenerator.cxx 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538
  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. // RUN_TESTS
  22. // add a group for Sources Headers, and other cmake group stuff
  23. // for each target create a custom build phase that is run first
  24. // it can have inputs and outputs should just be a makefile
  25. // per file flags howto
  26. // 115281011528101152810000 = {
  27. // fileEncoding = 4;
  28. // isa = PBXFileReference;
  29. // lastKnownFileType = sourcecode.cpp.cpp;
  30. // path = /Users/kitware/Bill/CMake/Source/cmakemain.cxx;
  31. // refType = 0;
  32. // sourceTree = "<absolute>";
  33. // };
  34. // 115285011528501152850000 = {
  35. // fileRef = 115281011528101152810000;
  36. // isa = PBXBuildFile;
  37. // settings = {
  38. // COMPILER_FLAGS = "-Dcmakemakeindefflag";
  39. // };
  40. // };
  41. // custom commands and clean up custom targets
  42. // do I need an ALL_BUILD yes
  43. // exe/lib output paths
  44. //----------------------------------------------------------------------------
  45. cmGlobalXCodeGenerator::cmGlobalXCodeGenerator()
  46. {
  47. m_FindMakeProgramFile = "CMakeFindXCode.cmake";
  48. m_RootObject = 0;
  49. m_MainGroupChildren = 0;
  50. m_SourcesGroupChildren = 0;
  51. m_CurrentMakefile = 0;
  52. m_CurrentLocalGenerator = 0;
  53. m_ExternalGroupChildren = 0;
  54. }
  55. //----------------------------------------------------------------------------
  56. void cmGlobalXCodeGenerator::EnableLanguage(std::vector<std::string>const&
  57. lang,
  58. cmMakefile * mf)
  59. {
  60. mf->AddDefinition("CMAKE_CFG_INTDIR",".");
  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. makeCommand += " -project ";
  92. makeCommand += projectName;
  93. makeCommand += ".xcode";
  94. makeCommand += " build -target ";
  95. if (targetName)
  96. {
  97. makeCommand += targetName;
  98. }
  99. else
  100. {
  101. makeCommand += "ALL_BUILD";
  102. }
  103. makeCommand += " -buildstyle Development ";
  104. makeCommand += " SYMROOT=";
  105. makeCommand += cmSystemTools::ConvertToOutputPath(bindir);
  106. int retVal;
  107. int timeout = cmGlobalGenerator::s_TryCompileTimeout;
  108. if (!cmSystemTools::RunSingleCommand(makeCommand.c_str(), output, &retVal,
  109. 0, false, timeout))
  110. {
  111. cmSystemTools::Error("Generator: execution of xcodebuild failed.");
  112. // return to the original directory
  113. cmSystemTools::ChangeDirectory(cwd.c_str());
  114. return 1;
  115. }
  116. cmSystemTools::ChangeDirectory(cwd.c_str());
  117. return retVal;
  118. }
  119. //----------------------------------------------------------------------------
  120. void cmGlobalXCodeGenerator::ConfigureOutputPaths()
  121. {
  122. // Format the library and executable output paths.
  123. m_LibraryOutputPath =
  124. m_CurrentMakefile->GetSafeDefinition("LIBRARY_OUTPUT_PATH");
  125. if(m_LibraryOutputPath.size() == 0)
  126. {
  127. m_LibraryOutputPath = m_CurrentMakefile->GetCurrentOutputDirectory();
  128. }
  129. // make sure there is a trailing slash
  130. if(m_LibraryOutputPath.size() &&
  131. m_LibraryOutputPath[m_LibraryOutputPath.size()-1] != '/')
  132. {
  133. m_LibraryOutputPath += "/";
  134. if(!cmSystemTools::MakeDirectory(m_LibraryOutputPath.c_str()))
  135. {
  136. cmSystemTools::Error("Error creating directory ",
  137. m_LibraryOutputPath.c_str());
  138. }
  139. }
  140. m_CurrentMakefile->AddLinkDirectory(m_LibraryOutputPath.c_str());
  141. m_ExecutableOutputPath =
  142. m_CurrentMakefile->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH");
  143. if(m_ExecutableOutputPath.size() == 0)
  144. {
  145. m_ExecutableOutputPath = m_CurrentMakefile->GetCurrentOutputDirectory();
  146. }
  147. // make sure there is a trailing slash
  148. if(m_ExecutableOutputPath.size() &&
  149. m_ExecutableOutputPath[m_ExecutableOutputPath.size()-1] != '/')
  150. {
  151. m_ExecutableOutputPath += "/";
  152. if(!cmSystemTools::MakeDirectory(m_ExecutableOutputPath.c_str()))
  153. {
  154. cmSystemTools::Error("Error creating directory ",
  155. m_ExecutableOutputPath.c_str());
  156. }
  157. }
  158. }
  159. //----------------------------------------------------------------------------
  160. ///! Create a local generator appropriate to this Global Generator
  161. cmLocalGenerator *cmGlobalXCodeGenerator::CreateLocalGenerator()
  162. {
  163. cmLocalGenerator *lg = new cmLocalXCodeGenerator;
  164. lg->SetGlobalGenerator(this);
  165. return lg;
  166. }
  167. //----------------------------------------------------------------------------
  168. void cmGlobalXCodeGenerator::Generate()
  169. {
  170. this->cmGlobalGenerator::Generate();
  171. std::map<cmStdString, std::vector<cmLocalGenerator*> >::iterator it;
  172. for(it = m_ProjectMap.begin(); it!= m_ProjectMap.end(); ++it)
  173. {
  174. cmLocalGenerator* root = it->second[0];
  175. m_CurrentMakefile = root->GetMakefile();
  176. m_OutputDir = m_CurrentMakefile->GetHomeOutputDirectory();
  177. m_OutputDir = cmSystemTools::CollapseFullPath(m_OutputDir.c_str());
  178. m_CurrentLocalGenerator = root;
  179. // add ALL_BUILD, INSTALL, etc
  180. this->AddExtraTargets(root, it->second);
  181. // now create the project
  182. this->OutputXCodeProject(root, it->second);
  183. }
  184. }
  185. //----------------------------------------------------------------------------
  186. void
  187. cmGlobalXCodeGenerator::AddExtraTargets(cmLocalGenerator* root,
  188. std::vector<cmLocalGenerator*>& gens)
  189. {
  190. std::vector<std::string> srcs; // dummy list
  191. cmMakefile* mf = root->GetMakefile();
  192. // Add ALL_BUILD
  193. mf->AddUtilityCommand("ALL_BUILD", "echo",
  194. "\"Build all projects\"",false,srcs);
  195. cmTarget* allbuild = mf->FindTarget("ALL_BUILD");
  196. // ADD install
  197. std::string cmake_command = mf->GetRequiredDefinition("CMAKE_COMMAND");
  198. mf->AddUtilityCommand("install", cmake_command.c_str(),
  199. "-P cmake_install.cmake",false,srcs);
  200. // Add RUN_TESTS target if testing has been enabled
  201. std::string fname;
  202. fname = mf->GetStartOutputDirectory();
  203. fname += "/";
  204. fname += "DartTestfile.txt";
  205. if (cmSystemTools::FileExists(fname.c_str()))
  206. {
  207. std::string ctest_command =
  208. mf->GetRequiredDefinition("CMAKE_CTEST_COMMAND");
  209. mf->AddUtilityCommand("RUN_TESTS", ctest_command.c_str(), "",false,srcs);
  210. }
  211. // Add install
  212. mf->AddUtilityCommand("install", cmake_command.c_str(),
  213. "-P cmake_install.cmake", false, srcs);
  214. // Add XCODE depend helper
  215. std::string dir = this->ConvertToRelativeOutputPath(
  216. mf->GetCurrentOutputDirectory());
  217. m_CurrentXCodeHackMakefile = dir;
  218. m_CurrentXCodeHackMakefile += "/CMakeScripts";
  219. cmSystemTools::MakeDirectory(m_CurrentXCodeHackMakefile.c_str());
  220. m_CurrentXCodeHackMakefile += "/XCODE_DEPEND_HELPER.make";
  221. std::string makecommand = "make -C ";
  222. makecommand += dir;
  223. makecommand += " -f ";
  224. makecommand += m_CurrentXCodeHackMakefile;
  225. mf->AddUtilityCommand("XCODE_DEPEND_HELPER", makecommand.c_str(),
  226. "",
  227. false,srcs);
  228. // now make the allbuild depend on all the non-utility targets
  229. // in the project
  230. for(std::vector<cmLocalGenerator*>::iterator i = gens.begin();
  231. i != gens.end(); ++i)
  232. {
  233. cmLocalGenerator* lg = *i;
  234. if(this->IsExcluded(root, *i))
  235. {
  236. continue;
  237. }
  238. cmTargets& tgts = lg->GetMakefile()->GetTargets();
  239. for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++)
  240. {
  241. cmTarget& target = l->second;
  242. // make all exe, shared libs and modules depend
  243. // on the XCODE_DEPEND_HELPER target
  244. if((target.GetType() == cmTarget::EXECUTABLE ||
  245. target.GetType() == cmTarget::SHARED_LIBRARY ||
  246. target.GetType() == cmTarget::MODULE_LIBRARY))
  247. {
  248. target.AddUtility("XCODE_DEPEND_HELPER");
  249. }
  250. if(target.IsInAll())
  251. {
  252. allbuild->AddUtility(target.GetName());
  253. }
  254. }
  255. }
  256. }
  257. //----------------------------------------------------------------------------
  258. void cmGlobalXCodeGenerator::ClearXCodeObjects()
  259. {
  260. m_TargetDoneSet.clear();
  261. for(unsigned int i = 0; i < m_XCodeObjects.size(); ++i)
  262. {
  263. delete m_XCodeObjects[i];
  264. }
  265. m_XCodeObjects.clear();
  266. }
  267. //----------------------------------------------------------------------------
  268. cmXCodeObject*
  269. cmGlobalXCodeGenerator::CreateObject(cmXCodeObject::PBXType ptype)
  270. {
  271. cmXCodeObject* obj = new cmXCodeObject(ptype, cmXCodeObject::OBJECT);
  272. m_XCodeObjects.push_back(obj);
  273. return obj;
  274. }
  275. //----------------------------------------------------------------------------
  276. cmXCodeObject*
  277. cmGlobalXCodeGenerator::CreateObject(cmXCodeObject::Type type)
  278. {
  279. cmXCodeObject* obj = new cmXCodeObject(cmXCodeObject::None, type);
  280. m_XCodeObjects.push_back(obj);
  281. return obj;
  282. }
  283. //----------------------------------------------------------------------------
  284. cmXCodeObject*
  285. cmGlobalXCodeGenerator::CreateString(const char* s)
  286. {
  287. cmXCodeObject* obj = this->CreateObject(cmXCodeObject::STRING);
  288. obj->SetString(s);
  289. return obj;
  290. }
  291. //----------------------------------------------------------------------------
  292. cmXCodeObject* cmGlobalXCodeGenerator::CreateObjectReference(cmXCodeObject* ref)
  293. {
  294. cmXCodeObject* obj = this->CreateObject(cmXCodeObject::OBJECT_REF);
  295. obj->SetObject(ref);
  296. return obj;
  297. }
  298. //----------------------------------------------------------------------------
  299. cmXCodeObject*
  300. cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg,
  301. cmSourceFile* sf)
  302. {
  303. std::string flags;
  304. // Add flags from source file properties.
  305. lg->AppendFlags(flags, sf->GetProperty("COMPILE_FLAGS"));
  306. cmXCodeObject* fileRef = this->CreateObject(cmXCodeObject::PBXFileReference);
  307. m_SourcesGroupChildren->AddObject(fileRef);
  308. cmXCodeObject* buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
  309. buildFile->AddAttribute("fileRef", this->CreateObjectReference(fileRef));
  310. cmXCodeObject* settings = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
  311. settings->AddAttribute("COMPILER_FLAGS", this->CreateString(flags.c_str()));
  312. buildFile->AddAttribute("settings", settings);
  313. fileRef->AddAttribute("fileEncoding", this->CreateString("4"));
  314. const char* lang =
  315. this->GetLanguageFromExtension(sf->GetSourceExtension().c_str());
  316. std::string sourcecode = "sourcecode";
  317. if(sf->GetSourceExtension() == "o")
  318. {
  319. sourcecode = "compiled.mach-o.objfile";
  320. }
  321. else if(sf->GetSourceExtension() == "mm")
  322. {
  323. sourcecode += ".cpp.objcpp";
  324. }
  325. else if(!lang)
  326. {
  327. std::string ext = ".";
  328. ext = sf->GetSourceExtension();
  329. sourcecode += ext;
  330. sourcecode += ext;
  331. }
  332. else if(strcmp(lang, "C") == 0)
  333. {
  334. sourcecode += ".c.c";
  335. }
  336. else
  337. {
  338. sourcecode += ".cpp.cpp";
  339. }
  340. fileRef->AddAttribute("lastKnownFileType",
  341. this->CreateString(sourcecode.c_str()));
  342. std::string path =
  343. this->ConvertToRelativeOutputPath(sf->GetFullPath().c_str());
  344. fileRef->AddAttribute("path", this->CreateString(path.c_str()));
  345. fileRef->AddAttribute("refType", this->CreateString("4"));
  346. if(path.size() > 1 && path[0] == '.' && path[1] == '.')
  347. {
  348. fileRef->AddAttribute("sourceTree", this->CreateString("<group>"));
  349. }
  350. else
  351. {
  352. fileRef->AddAttribute("sourceTree", this->CreateString("<absolute>"));
  353. }
  354. return buildFile;
  355. }
  356. //----------------------------------------------------------------------------
  357. bool cmGlobalXCodeGenerator::SpecialTargetEmitted(std::string const& tname)
  358. {
  359. if(tname == "ALL_BUILD" || tname == "XCODE_DEPEND_HELPER" ||
  360. tname == "install" || tname == "RUN_TESTS")
  361. {
  362. if(m_TargetDoneSet.find(tname) != m_TargetDoneSet.end())
  363. {
  364. return true;
  365. }
  366. m_TargetDoneSet.insert(tname);
  367. return false;
  368. }
  369. return false;
  370. }
  371. //----------------------------------------------------------------------------
  372. void
  373. cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen,
  374. std::vector<cmXCodeObject*>&
  375. targets)
  376. {
  377. m_CurrentLocalGenerator = gen;
  378. m_CurrentMakefile = gen->GetMakefile();
  379. cmTargets &tgts = gen->GetMakefile()->GetTargets();
  380. for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++)
  381. {
  382. cmTarget& cmtarget = l->second;
  383. // make sure ALL_BUILD, INSTALL, etc are only done once
  384. if(this->SpecialTargetEmitted(l->first.c_str()))
  385. {
  386. continue;
  387. }
  388. if(cmtarget.GetType() == cmTarget::UTILITY ||
  389. cmtarget.GetType() == cmTarget::INSTALL_FILES ||
  390. cmtarget.GetType() == cmTarget::INSTALL_PROGRAMS)
  391. {
  392. if(cmtarget.GetType() == cmTarget::UTILITY)
  393. {
  394. targets.push_back(this->CreateUtilityTarget(cmtarget));
  395. }
  396. continue;
  397. }
  398. // create source build phase
  399. cmXCodeObject* sourceBuildPhase =
  400. this->CreateObject(cmXCodeObject::PBXSourcesBuildPhase);
  401. sourceBuildPhase->AddAttribute("buildActionMask",
  402. this->CreateString("2147483647"));
  403. cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  404. sourceBuildPhase->AddAttribute("files", buildFiles);
  405. sourceBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
  406. this->CreateString("0"));
  407. std::vector<cmSourceFile*> &classes = l->second.GetSourceFiles();
  408. // add all the sources
  409. std::vector<cmXCodeObject*> externalObjFiles;
  410. for(std::vector<cmSourceFile*>::iterator i = classes.begin();
  411. i != classes.end(); ++i)
  412. {
  413. cmXCodeObject* xsf = this->CreateXCodeSourceFile(gen, *i);
  414. cmXCodeObject* fr = xsf->GetObject("fileRef");
  415. cmXCodeObject* filetype =
  416. fr->GetObject()->GetObject("lastKnownFileType");
  417. if(strcmp(filetype->GetString(), "\"compiled.mach-o.objfile\"") == 0)
  418. {
  419. externalObjFiles.push_back(xsf);
  420. }
  421. else
  422. {
  423. buildFiles->AddObject(xsf);
  424. }
  425. }
  426. // create header build phase
  427. cmXCodeObject* headerBuildPhase =
  428. this->CreateObject(cmXCodeObject::PBXHeadersBuildPhase);
  429. headerBuildPhase->AddAttribute("buildActionMask",
  430. this->CreateString("2147483647"));
  431. buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  432. headerBuildPhase->AddAttribute("files", buildFiles);
  433. headerBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
  434. this->CreateString("0"));
  435. // create framework build phase
  436. cmXCodeObject* frameworkBuildPhase =
  437. this->CreateObject(cmXCodeObject::PBXFrameworksBuildPhase);
  438. frameworkBuildPhase->AddAttribute("buildActionMask",
  439. this->CreateString("2147483647"));
  440. buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  441. frameworkBuildPhase->AddAttribute("files", buildFiles);
  442. for(std::vector<cmXCodeObject*>::iterator i = externalObjFiles.begin();
  443. i != externalObjFiles.end(); ++i)
  444. {
  445. buildFiles->AddObject(*i);
  446. }
  447. frameworkBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
  448. this->CreateString("0"));
  449. cmXCodeObject* buildPhases =
  450. this->CreateObject(cmXCodeObject::OBJECT_LIST);
  451. this->CreateCustomCommands(buildPhases, sourceBuildPhase,
  452. headerBuildPhase, frameworkBuildPhase,
  453. cmtarget);
  454. targets.push_back(this->CreateXCodeTarget(l->second, buildPhases));
  455. }
  456. }
  457. //----------------------------------------------------------------------------
  458. void cmGlobalXCodeGenerator::CreateCustomCommands(cmXCodeObject* buildPhases,
  459. cmXCodeObject*
  460. sourceBuildPhase,
  461. cmXCodeObject*
  462. headerBuildPhase,
  463. cmXCodeObject*
  464. frameworkBuildPhase,
  465. cmTarget& cmtarget)
  466. {
  467. std::vector<cmCustomCommand> const & prebuild
  468. = cmtarget.GetPreBuildCommands();
  469. std::vector<cmCustomCommand> const & prelink
  470. = cmtarget.GetPreLinkCommands();
  471. std::vector<cmCustomCommand> const & postbuild
  472. = cmtarget.GetPostBuildCommands();
  473. cmtarget.TraceVSDependencies(cmtarget.GetName(), m_CurrentMakefile);
  474. std::vector<cmSourceFile*> &classes = cmtarget.GetSourceFiles();
  475. // add all the sources
  476. std::vector<cmCustomCommand> commands;
  477. for(std::vector<cmSourceFile*>::iterator i = classes.begin();
  478. i != classes.end(); ++i)
  479. {
  480. if((*i)->GetCustomCommand())
  481. {
  482. commands.push_back(*(*i)->GetCustomCommand());
  483. }
  484. }
  485. // create prebuild phase
  486. cmXCodeObject* cmakeRulesBuildPhase = 0;
  487. if(commands.size())
  488. {
  489. cmakeRulesBuildPhase =
  490. this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase);
  491. cmakeRulesBuildPhase->AddAttribute("buildActionMask",
  492. this->CreateString("2147483647"));
  493. cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  494. cmakeRulesBuildPhase->AddAttribute("files", buildFiles);
  495. cmakeRulesBuildPhase->AddAttribute("name",
  496. this->CreateString("CMake Rules"));
  497. cmakeRulesBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
  498. this->CreateString("0"));
  499. cmakeRulesBuildPhase->AddAttribute("shellPath",
  500. this->CreateString("/bin/sh"));
  501. this->AddCommandsToBuildPhase(cmakeRulesBuildPhase, cmtarget, commands,
  502. "cmakeRulesCommands");
  503. }
  504. // create prebuild phase
  505. cmXCodeObject* preBuildPhase = 0;
  506. if(prebuild.size())
  507. {
  508. preBuildPhase =
  509. this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase);
  510. preBuildPhase->AddAttribute("buildActionMask",
  511. this->CreateString("2147483647"));
  512. cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  513. preBuildPhase->AddAttribute("files", buildFiles);
  514. preBuildPhase->AddAttribute("name",
  515. this->CreateString("CMake PreBuild Rules"));
  516. preBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
  517. this->CreateString("0"));
  518. preBuildPhase->AddAttribute("shellPath", this->CreateString("/bin/sh"));
  519. this->AddCommandsToBuildPhase(preBuildPhase, cmtarget, prebuild,
  520. "preBuildCommands");
  521. }
  522. // create prebuild phase
  523. cmXCodeObject* preLinkPhase = 0;
  524. if(prelink.size())
  525. {
  526. preLinkPhase =
  527. this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase);
  528. preLinkPhase->AddAttribute("buildActionMask",
  529. this->CreateString("2147483647"));
  530. cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  531. preLinkPhase->AddAttribute("files", buildFiles);
  532. preLinkPhase->AddAttribute("name",
  533. this->CreateString("CMake PreLink Rules"));
  534. preLinkPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
  535. this->CreateString("0"));
  536. preLinkPhase->AddAttribute("shellPath", this->CreateString("/bin/sh"));
  537. this->AddCommandsToBuildPhase(preLinkPhase, cmtarget, prelink,
  538. "preLinkCommands");
  539. }
  540. // create prebuild phase
  541. cmXCodeObject* postBuildPhase = 0;
  542. if(postbuild.size())
  543. {
  544. postBuildPhase =
  545. this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase);
  546. postBuildPhase->AddAttribute("buildActionMask",
  547. this->CreateString("2147483647"));
  548. cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  549. postBuildPhase->AddAttribute("files", buildFiles);
  550. postBuildPhase->AddAttribute("name",
  551. this->CreateString("CMake PostBuild Rules"));
  552. postBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
  553. this->CreateString("0"));
  554. postBuildPhase->AddAttribute("shellPath", this->CreateString("/bin/sh"));
  555. this->AddCommandsToBuildPhase(postBuildPhase, cmtarget, postbuild,
  556. "postBuildCommands");
  557. }
  558. // the order here is the order they will be built in
  559. if(preBuildPhase)
  560. {
  561. buildPhases->AddObject(preBuildPhase);
  562. }
  563. if(cmakeRulesBuildPhase)
  564. {
  565. buildPhases->AddObject(cmakeRulesBuildPhase);
  566. }
  567. if(sourceBuildPhase)
  568. {
  569. buildPhases->AddObject(sourceBuildPhase);
  570. }
  571. if(headerBuildPhase)
  572. {
  573. buildPhases->AddObject(headerBuildPhase);
  574. }
  575. if(preLinkPhase)
  576. {
  577. buildPhases->AddObject(preLinkPhase);
  578. }
  579. if(frameworkBuildPhase)
  580. {
  581. buildPhases->AddObject(frameworkBuildPhase);
  582. }
  583. if(postBuildPhase)
  584. {
  585. buildPhases->AddObject(postBuildPhase);
  586. }
  587. }
  588. //----------------------------------------------------------------------------
  589. void
  590. cmGlobalXCodeGenerator::AddCommandsToBuildPhase(cmXCodeObject* buildphase,
  591. cmTarget& target,
  592. std::vector<cmCustomCommand>
  593. const & commands,
  594. const char* name)
  595. {
  596. std::string dir = m_CurrentMakefile->GetCurrentOutputDirectory();
  597. dir += "/CMakeScripts";
  598. cmSystemTools::MakeDirectory(dir.c_str());
  599. std::string makefile = dir;
  600. makefile += "/";
  601. makefile += target.GetName();
  602. makefile += "_";
  603. makefile += name;
  604. makefile += ".make";
  605. cmGeneratedFileStream makefileStream(makefile.c_str());
  606. if(!makefileStream)
  607. {
  608. return;
  609. }
  610. makefileStream << "# Generated by CMake, DO NOT EDIT\n";
  611. makefileStream << "# Custom rules for " << target.GetName() << "\n";
  612. // have all depend on all outputs
  613. makefileStream << "all: ";
  614. std::map<const cmCustomCommand*, cmStdString> tname;
  615. int count = 0;
  616. for(std::vector<cmCustomCommand>::const_iterator i = commands.begin();
  617. i != commands.end(); ++i)
  618. {
  619. cmCustomCommand const& cc = *i;
  620. if(cc.GetCommand().size())
  621. {
  622. if(cc.GetOutput().size())
  623. {
  624. makefileStream << "\\\n\t" << this->
  625. ConvertToRelativeOutputPath(cc.GetOutput().c_str());
  626. }
  627. else
  628. {
  629. char c = '1' + count++;
  630. tname[&cc] = std::string(target.GetName()) + c;
  631. makefileStream << "\\\n\t" << tname[&cc];
  632. }
  633. }
  634. }
  635. makefileStream << "\n\n";
  636. for(std::vector<cmCustomCommand>::const_iterator i = commands.begin();
  637. i != commands.end(); ++i)
  638. {
  639. cmCustomCommand const& cc = *i;
  640. if(cc.GetCommand().size())
  641. {
  642. makefileStream << "\n#" << "Custom command rule: " <<
  643. cc.GetComment() << "\n";
  644. if(cc.GetOutput().size())
  645. {
  646. makefileStream << this
  647. ->ConvertToRelativeOutputPath(cc.GetOutput().c_str()) << ": ";
  648. }
  649. else
  650. {
  651. makefileStream << tname[&cc] << ": ";
  652. }
  653. for(std::vector<std::string>::const_iterator d = cc.GetDepends().begin();
  654. d != cc.GetDepends().end(); ++d)
  655. {
  656. if(!this->FindTarget(d->c_str()))
  657. {
  658. makefileStream << "\\\n" << *d;
  659. }
  660. else
  661. {
  662. // if the depend is a target then make
  663. // the target with the source that is a custom command
  664. // depend on the that target via a AddUtility call
  665. target.AddUtility(d->c_str());
  666. }
  667. }
  668. makefileStream << "\n";
  669. makefileStream << "\t" << cc.GetCommand() << " "
  670. << cc.GetArguments() << "\n";
  671. }
  672. }
  673. std::string cdir = m_CurrentMakefile->GetCurrentOutputDirectory();
  674. cdir = this->ConvertToRelativeOutputPath(cdir.c_str());
  675. std::string makecmd = "make -C ";
  676. makecmd += cdir;
  677. makecmd += " -f ";
  678. makecmd += makefile;
  679. buildphase->AddAttribute("shellScript", this->CreateString(makecmd.c_str()));
  680. }
  681. //----------------------------------------------------------------------------
  682. void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
  683. cmXCodeObject* buildSettings,
  684. std::string& fileType,
  685. std::string& productType,
  686. std::string& productName)
  687. {
  688. this->ConfigureOutputPaths();
  689. std::string flags;
  690. bool shared = ((target.GetType() == cmTarget::SHARED_LIBRARY) ||
  691. (target.GetType() == cmTarget::MODULE_LIBRARY));
  692. if(shared)
  693. {
  694. flags += "-D";
  695. if(const char* custom_export_name = target.GetProperty("DEFINE_SYMBOL"))
  696. {
  697. flags += custom_export_name;
  698. }
  699. else
  700. {
  701. std::string in = target.GetName();
  702. in += "_EXPORTS";
  703. flags += cmSystemTools::MakeCindentifier(in.c_str());
  704. }
  705. }
  706. const char* lang = target.GetLinkerLanguage(this);
  707. if(lang)
  708. {
  709. // Add language-specific flags.
  710. m_CurrentLocalGenerator->AddLanguageFlags(flags, lang);
  711. // Add shared-library flags if needed.
  712. m_CurrentLocalGenerator->AddSharedFlags(flags, lang, shared);
  713. }
  714. // Add define flags
  715. m_CurrentLocalGenerator->AppendFlags(flags,
  716. m_CurrentMakefile->GetDefineFlags());
  717. cmSystemTools::ReplaceString(flags, "\"", "\\\"");
  718. productName = target.GetName();
  719. bool needLinkDirs = true;
  720. switch(target.GetType())
  721. {
  722. case cmTarget::STATIC_LIBRARY:
  723. {
  724. needLinkDirs = false;
  725. if(m_LibraryOutputPath.size())
  726. {
  727. buildSettings->AddAttribute("SYMROOT",
  728. this->CreateString
  729. (m_LibraryOutputPath.c_str()));
  730. }
  731. productName += ".a";
  732. std::string t = "lib";
  733. t += productName;
  734. productName = t;
  735. productType = "com.apple.product-type.library.static";
  736. fileType = "archive.ar";
  737. buildSettings->AddAttribute("LIBRARY_STYLE",
  738. this->CreateString("STATIC"));
  739. break;
  740. }
  741. case cmTarget::MODULE_LIBRARY:
  742. {
  743. if(m_LibraryOutputPath.size())
  744. {
  745. buildSettings->AddAttribute("SYMROOT",
  746. this->CreateString
  747. (m_LibraryOutputPath.c_str()));
  748. }
  749. buildSettings->AddAttribute("EXECUTABLE_PREFIX",
  750. this->CreateString("lib"));
  751. buildSettings->AddAttribute("EXECUTABLE_EXTENSION",
  752. this->CreateString("so"));
  753. buildSettings->AddAttribute("LIBRARY_STYLE",
  754. this->CreateString("BUNDLE"));
  755. productName += ".so";
  756. std::string t = "lib";
  757. t += productName;
  758. productName = t;
  759. buildSettings->AddAttribute("OTHER_LDFLAGS",
  760. this->CreateString("-bundle"));
  761. productType = "com.apple.product-type.library.dynamic";
  762. fileType = "compiled.mach-o.dylib";
  763. break;
  764. }
  765. case cmTarget::SHARED_LIBRARY:
  766. {
  767. if(m_LibraryOutputPath.size())
  768. {
  769. buildSettings->AddAttribute("SYMROOT",
  770. this->CreateString
  771. (m_LibraryOutputPath.c_str()));
  772. }
  773. buildSettings->AddAttribute("LIBRARY_STYLE",
  774. this->CreateString("DYNAMIC"));
  775. productName += ".dylib";
  776. std::string t = "lib";
  777. t += productName;
  778. productName = t;
  779. buildSettings->AddAttribute("DYLIB_COMPATIBILITY_VERSION",
  780. this->CreateString("1"));
  781. buildSettings->AddAttribute("DYLIB_CURRENT_VERSION",
  782. this->CreateString("1"));
  783. buildSettings->AddAttribute("OTHER_LDFLAGS",
  784. this->CreateString("-dynamiclib"));
  785. productType = "com.apple.product-type.library.dynamic";
  786. fileType = "compiled.mach-o.dylib";
  787. break;
  788. }
  789. case cmTarget::EXECUTABLE:
  790. if(m_ExecutableOutputPath.size())
  791. {
  792. buildSettings->AddAttribute("SYMROOT",
  793. this->CreateString
  794. (m_ExecutableOutputPath.c_str()));
  795. }
  796. fileType = "compiled.mach-o.executable";
  797. productType = "com.apple.product-type.tool";
  798. break;
  799. case cmTarget::UTILITY:
  800. break;
  801. case cmTarget::INSTALL_FILES:
  802. break;
  803. case cmTarget::INSTALL_PROGRAMS:
  804. break;
  805. }
  806. std::string dirs;
  807. if(needLinkDirs)
  808. {
  809. // Try to emit each search path once
  810. std::set<cmStdString> emitted;
  811. // Some search paths should never be emitted
  812. emitted.insert("");
  813. emitted.insert("/usr/lib");
  814. std::vector<std::string> const& linkdirs =
  815. target.GetLinkDirectories();
  816. for(std::vector<std::string>::const_iterator l = linkdirs.begin();
  817. l != linkdirs.end(); ++l)
  818. {
  819. std::string libpath =
  820. this->ConvertToRelativeOutputPath(l->c_str());
  821. if(emitted.insert(libpath).second)
  822. {
  823. dirs += libpath + " ";
  824. }
  825. }
  826. if(dirs.size())
  827. {
  828. buildSettings->AddAttribute("LIBRARY_SEARCH_PATHS",
  829. this->CreateString(dirs.c_str()));
  830. }
  831. }
  832. dirs = "";
  833. std::vector<std::string>& includes =
  834. m_CurrentMakefile->GetIncludeDirectories();
  835. std::vector<std::string>::iterator i = includes.begin();
  836. for(;i != includes.end(); ++i)
  837. {
  838. std::string incpath =
  839. this->ConvertToRelativeOutputPath(i->c_str());
  840. dirs += incpath + " ";
  841. }
  842. if(dirs.size())
  843. {
  844. buildSettings->AddAttribute("HEADER_SEARCH_PATHS",
  845. this->CreateString(dirs.c_str()));
  846. }
  847. buildSettings->AddAttribute("GCC_OPTIMIZATION_LEVEL",
  848. this->CreateString("0"));
  849. buildSettings->AddAttribute("INSTALL_PATH",
  850. this->CreateString(""));
  851. buildSettings->AddAttribute("OPTIMIZATION_CFLAGS",
  852. this->CreateString(""));
  853. buildSettings->AddAttribute("OTHER_CFLAGS",
  854. this->CreateString(flags.c_str()));
  855. buildSettings->AddAttribute("OTHER_LDFLAGS",
  856. this->CreateString(""));
  857. buildSettings->AddAttribute("OTHER_REZFLAGS",
  858. this->CreateString(""));
  859. buildSettings->AddAttribute("SECTORDER_FLAGS",
  860. this->CreateString(""));
  861. buildSettings->AddAttribute("WARNING_CFLAGS",
  862. this->CreateString(
  863. "-Wmost -Wno-four-char-constants"
  864. " -Wno-unknown-pragmas"));
  865. std::string pname;
  866. if(target.GetType() == cmTarget::SHARED_LIBRARY)
  867. {
  868. pname = "lib";
  869. }
  870. pname += target.GetName();
  871. buildSettings->AddAttribute("PRODUCT_NAME",
  872. this->CreateString(pname.c_str()));
  873. }
  874. //----------------------------------------------------------------------------
  875. cmXCodeObject*
  876. cmGlobalXCodeGenerator::CreateUtilityTarget(cmTarget& cmtarget)
  877. {
  878. cmXCodeObject* shellBuildPhase =
  879. this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase);
  880. shellBuildPhase->AddAttribute("buildActionMask",
  881. this->CreateString("2147483647"));
  882. cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  883. shellBuildPhase->AddAttribute("files", buildFiles);
  884. cmXCodeObject* inputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  885. shellBuildPhase->AddAttribute("inputPaths", inputPaths);
  886. cmXCodeObject* outputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  887. shellBuildPhase->AddAttribute("outputPaths", outputPaths);
  888. shellBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
  889. this->CreateString("0"));
  890. shellBuildPhase->AddAttribute("shellPath",
  891. this->CreateString("/bin/sh"));
  892. shellBuildPhase->AddAttribute("shellScript",
  893. this->CreateString(
  894. "# shell script goes here\nexit 0"));
  895. cmXCodeObject* target =
  896. this->CreateObject(cmXCodeObject::PBXAggregateTarget);
  897. cmXCodeObject* buildPhases =
  898. this->CreateObject(cmXCodeObject::OBJECT_LIST);
  899. this->CreateCustomCommands(buildPhases, 0, 0, 0, cmtarget);
  900. target->AddAttribute("buildPhases", buildPhases);
  901. cmXCodeObject* buildSettings =
  902. this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
  903. std::string fileTypeString;
  904. std::string productTypeString;
  905. std::string productName;
  906. this->CreateBuildSettings(cmtarget,
  907. buildSettings, fileTypeString,
  908. productTypeString, productName);
  909. target->AddAttribute("buildSettings", buildSettings);
  910. cmXCodeObject* dependencies = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  911. target->AddAttribute("dependencies", dependencies);
  912. target->AddAttribute("name", this->CreateString(cmtarget.GetName()));
  913. target->AddAttribute("productName",this->CreateString(cmtarget.GetName()));
  914. target->SetcmTarget(&cmtarget);
  915. return target;
  916. }
  917. //----------------------------------------------------------------------------
  918. cmXCodeObject*
  919. cmGlobalXCodeGenerator::CreateXCodeTarget(cmTarget& cmtarget,
  920. cmXCodeObject* buildPhases)
  921. {
  922. cmXCodeObject* target =
  923. this->CreateObject(cmXCodeObject::PBXNativeTarget);
  924. target->AddAttribute("buildPhases", buildPhases);
  925. cmXCodeObject* buildRules = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  926. target->AddAttribute("buildRules", buildRules);
  927. cmXCodeObject* buildSettings =
  928. this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
  929. std::string fileTypeString;
  930. std::string productTypeString;
  931. std::string productName;
  932. this->CreateBuildSettings(cmtarget,
  933. buildSettings, fileTypeString,
  934. productTypeString, productName);
  935. target->AddAttribute("buildSettings", buildSettings);
  936. cmXCodeObject* dependencies = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  937. target->AddAttribute("dependencies", dependencies);
  938. target->AddAttribute("name", this->CreateString(cmtarget.GetName()));
  939. target->AddAttribute("productName",this->CreateString(cmtarget.GetName()));
  940. cmXCodeObject* fileRef = this->CreateObject(cmXCodeObject::PBXFileReference);
  941. fileRef->AddAttribute("explicitFileType",
  942. this->CreateString(fileTypeString.c_str()));
  943. fileRef->AddAttribute("path", this->CreateString(productName.c_str()));
  944. fileRef->AddAttribute("refType", this->CreateString("0"));
  945. fileRef->AddAttribute("sourceTree",
  946. this->CreateString("BUILT_PRODUCTS_DIR"));
  947. target->AddAttribute("productReference",
  948. this->CreateObjectReference(fileRef));
  949. target->AddAttribute("productType",
  950. this->CreateString(productTypeString.c_str()));
  951. target->SetcmTarget(&cmtarget);
  952. return target;
  953. }
  954. //----------------------------------------------------------------------------
  955. cmXCodeObject* cmGlobalXCodeGenerator::FindXCodeTarget(cmTarget* t)
  956. {
  957. if(!t)
  958. {
  959. return 0;
  960. }
  961. for(std::vector<cmXCodeObject*>::iterator i = m_XCodeObjects.begin();
  962. i != m_XCodeObjects.end(); ++i)
  963. {
  964. cmXCodeObject* o = *i;
  965. if(o->GetcmTarget() == t)
  966. {
  967. return o;
  968. }
  969. }
  970. return 0;
  971. }
  972. //----------------------------------------------------------------------------
  973. void cmGlobalXCodeGenerator::AddDependTarget(cmXCodeObject* target,
  974. cmXCodeObject* dependTarget)
  975. {
  976. // make sure a target does not depend on itself
  977. if(target == dependTarget)
  978. {
  979. return;
  980. }
  981. // now avoid circular references if dependTarget already
  982. // depends on target then skip it. Circular references crashes
  983. // xcode
  984. cmXCodeObject* dependTargetDepends = dependTarget->GetObject("dependencies");
  985. if(dependTargetDepends)
  986. {
  987. if(dependTargetDepends->HasObject(target->GetPBXTargetDependency()))
  988. {
  989. return;
  990. }
  991. }
  992. cmXCodeObject* targetdep = dependTarget->GetPBXTargetDependency();
  993. if(!targetdep)
  994. {
  995. cmXCodeObject* container =
  996. this->CreateObject(cmXCodeObject::PBXContainerItemProxy);
  997. container->AddAttribute("containerPortal",
  998. this->CreateObjectReference(m_RootObject));
  999. container->AddAttribute("proxyType", this->CreateString("1"));
  1000. container->AddAttribute("remoteGlobalIDString",
  1001. this->CreateObjectReference(dependTarget));
  1002. container->AddAttribute("remoteInfo",
  1003. this->CreateString(
  1004. dependTarget->GetcmTarget()->GetName()));
  1005. targetdep =
  1006. this->CreateObject(cmXCodeObject::PBXTargetDependency);
  1007. targetdep->AddAttribute("target",
  1008. this->CreateObjectReference(dependTarget));
  1009. targetdep->AddAttribute("targetProxy",
  1010. this->CreateObjectReference(container));
  1011. dependTarget->SetPBXTargetDependency(targetdep);
  1012. }
  1013. cmXCodeObject* depends = target->GetObject("dependencies");
  1014. if(!depends)
  1015. {
  1016. std::cerr << "target does not have dependencies attribute error...\n";
  1017. }
  1018. else
  1019. {
  1020. depends->AddUniqueObject(targetdep);
  1021. }
  1022. }
  1023. //----------------------------------------------------------------------------
  1024. void cmGlobalXCodeGenerator::AddLinkLibrary(cmXCodeObject* target,
  1025. const char* library,
  1026. cmTarget* dtarget)
  1027. {
  1028. // if the library is a full path then create a file reference
  1029. // and build file and add them to the PBXFrameworksBuildPhase
  1030. // for the target
  1031. std::string file = library;
  1032. if(cmSystemTools::FileIsFullPath(library))
  1033. {
  1034. target->AddDependLibrary(library);
  1035. std::string dir;
  1036. cmSystemTools::SplitProgramPath(library, dir, file);
  1037. // add the library path to the search path for the target
  1038. cmXCodeObject* bset = target->GetObject("buildSettings");
  1039. if(bset)
  1040. {
  1041. cmXCodeObject* spath = bset->GetObject("LIBRARY_SEARCH_PATHS");
  1042. if(spath)
  1043. {
  1044. std::string libs = spath->GetString();
  1045. // remove double quotes
  1046. libs = libs.substr(1, libs.size()-2);
  1047. libs += " ";
  1048. libs += this->ConvertToRelativeOutputPath(dir.c_str());
  1049. spath->SetString(libs.c_str());
  1050. }
  1051. else
  1052. {
  1053. std::string libs = this->ConvertToRelativeOutputPath(dir.c_str());
  1054. bset->AddAttribute("LIBRARY_SEARCH_PATHS",
  1055. this->CreateString(libs.c_str()));
  1056. }
  1057. }
  1058. cmsys::RegularExpression libname("^lib([^/]*)(\\.a|\\.dylib).*");
  1059. if(libname.find(file))
  1060. {
  1061. file = libname.match(1);
  1062. }
  1063. }
  1064. else
  1065. {
  1066. if(dtarget)
  1067. {
  1068. target->AddDependLibrary(this->GetTargetFullPath(dtarget).c_str());
  1069. }
  1070. }
  1071. // if the library is not a full path then add it with a -l flag
  1072. // to the settings of the target
  1073. cmXCodeObject* settings = target->GetObject("buildSettings");
  1074. cmXCodeObject* ldflags = settings->GetObject("OTHER_LDFLAGS");
  1075. std::string link = ldflags->GetString();
  1076. cmSystemTools::ReplaceString(link, "\"", "");
  1077. cmsys::RegularExpression reg("^([ \t]*\\-[lWRB])|([ \t]*\\-framework)|(\\${)|([ \t]*\\-pthread)|([ \t]*`)");
  1078. // if the library is not already in the form required by the compiler
  1079. // add a -l infront of the name
  1080. link += " ";
  1081. if(!reg.find(file))
  1082. {
  1083. link += "-l";
  1084. }
  1085. link += file;
  1086. ldflags->SetString(link.c_str());
  1087. }
  1088. //----------------------------------------------------------------------------
  1089. std::string cmGlobalXCodeGenerator::GetTargetFullPath(cmTarget* target)
  1090. {
  1091. std::string libPath;
  1092. cmXCodeObject* xtarget = this->FindXCodeTarget(target);
  1093. cmXCodeObject* bset = xtarget->GetObject("buildSettings");
  1094. cmXCodeObject* spath = bset->GetObject("SYMROOT");
  1095. libPath = spath->GetString();
  1096. libPath = libPath.substr(1, libPath.size()-2);
  1097. if(target->GetType() == cmTarget::STATIC_LIBRARY)
  1098. {
  1099. libPath += "lib";
  1100. libPath += target->GetName();
  1101. libPath += ".a";
  1102. }
  1103. else if(target->GetType() == cmTarget::SHARED_LIBRARY)
  1104. {
  1105. libPath += "lib";
  1106. libPath += target->GetName();
  1107. libPath += ".dylib";
  1108. }
  1109. else
  1110. {
  1111. libPath += target->GetName();
  1112. }
  1113. return libPath;
  1114. }
  1115. //----------------------------------------------------------------------------
  1116. void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
  1117. {
  1118. cmTarget* cmtarget = target->GetcmTarget();
  1119. if(!cmtarget)
  1120. {
  1121. std::cerr << "Error no target on xobject\n";
  1122. return;
  1123. }
  1124. cmTarget::LinkLibraries::const_iterator j, jend;
  1125. j = cmtarget->GetLinkLibraries().begin();
  1126. jend = cmtarget->GetLinkLibraries().end();
  1127. for(;j!= jend; ++j)
  1128. {
  1129. cmTarget* t = this->FindTarget(j->first.c_str());
  1130. cmXCodeObject* dptarget = this->FindXCodeTarget(t);
  1131. if(dptarget)
  1132. {
  1133. this->AddDependTarget(target, dptarget);
  1134. if(cmtarget->GetType() != cmTarget::STATIC_LIBRARY)
  1135. {
  1136. this->AddLinkLibrary(target, t->GetName(), t);
  1137. }
  1138. }
  1139. else
  1140. {
  1141. if(cmtarget->GetType() != cmTarget::STATIC_LIBRARY)
  1142. {
  1143. this->AddLinkLibrary(target, j->first.c_str());
  1144. }
  1145. }
  1146. }
  1147. std::set<cmStdString>::const_iterator i, end;
  1148. // write utility dependencies.
  1149. i = cmtarget->GetUtilities().begin();
  1150. end = cmtarget->GetUtilities().end();
  1151. for(;i!= end; ++i)
  1152. {
  1153. cmTarget* t = this->FindTarget(i->c_str());
  1154. cmXCodeObject* dptarget = this->FindXCodeTarget(t);
  1155. if(dptarget)
  1156. {
  1157. this->AddDependTarget(target, dptarget);
  1158. }
  1159. else
  1160. {
  1161. std::cerr << "Error Utility: " << i->c_str() << "\n";
  1162. std::cerr << "Is on the target " << cmtarget->GetName() << "\n";
  1163. std::cerr << "But it has no xcode target created yet??\n";
  1164. std::cerr << "Current project is "
  1165. << m_CurrentMakefile->GetProjectName() << "\n";
  1166. }
  1167. }
  1168. }
  1169. //----------------------------------------------------------------------------
  1170. void cmGlobalXCodeGenerator::CreateXCodeObjects(cmLocalGenerator* root,
  1171. std::vector<cmLocalGenerator*>&
  1172. generators
  1173. )
  1174. {
  1175. this->ClearXCodeObjects();
  1176. m_RootObject = 0;
  1177. m_ExternalGroupChildren = 0;
  1178. m_SourcesGroupChildren = 0;
  1179. m_MainGroupChildren = 0;
  1180. cmXCodeObject* group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
  1181. group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
  1182. cmXCodeObject* developBuildStyle =
  1183. this->CreateObject(cmXCodeObject::PBXBuildStyle);
  1184. developBuildStyle->AddAttribute("name", this->CreateString("Development"));
  1185. developBuildStyle->AddAttribute("buildSettings", group);
  1186. group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
  1187. group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("YES"));
  1188. cmXCodeObject* deployBuildStyle =
  1189. this->CreateObject(cmXCodeObject::PBXBuildStyle);
  1190. deployBuildStyle->AddAttribute("name", this->CreateString("Deployment"));
  1191. deployBuildStyle->AddAttribute("buildSettings", group);
  1192. cmXCodeObject* listObjs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  1193. listObjs->AddObject(developBuildStyle);
  1194. listObjs->AddObject(deployBuildStyle);
  1195. cmXCodeObject* mainGroup = this->CreateObject(cmXCodeObject::PBXGroup);
  1196. m_MainGroupChildren =
  1197. this->CreateObject(cmXCodeObject::OBJECT_LIST);
  1198. mainGroup->AddAttribute("children", m_MainGroupChildren);
  1199. mainGroup->AddAttribute("refType", this->CreateString("4"));
  1200. mainGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
  1201. cmXCodeObject* sourcesGroup = this->CreateObject(cmXCodeObject::PBXGroup);
  1202. m_SourcesGroupChildren =
  1203. this->CreateObject(cmXCodeObject::OBJECT_LIST);
  1204. sourcesGroup->AddAttribute("name", this->CreateString("Sources"));
  1205. sourcesGroup->AddAttribute("children", m_SourcesGroupChildren);
  1206. sourcesGroup->AddAttribute("refType", this->CreateString("4"));
  1207. sourcesGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
  1208. m_MainGroupChildren->AddObject(sourcesGroup);
  1209. cmXCodeObject* externalGroup = this->CreateObject(cmXCodeObject::PBXGroup);
  1210. m_ExternalGroupChildren =
  1211. this->CreateObject(cmXCodeObject::OBJECT_LIST);
  1212. externalGroup->AddAttribute("name",
  1213. this->CreateString("External Libraries and Frameworks"));
  1214. externalGroup->AddAttribute("children", m_ExternalGroupChildren);
  1215. externalGroup->AddAttribute("refType", this->CreateString("4"));
  1216. externalGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
  1217. m_MainGroupChildren->AddObject(externalGroup);
  1218. cmXCodeObject* productGroup = this->CreateObject(cmXCodeObject::PBXGroup);
  1219. productGroup->AddAttribute("name", this->CreateString("Products"));
  1220. productGroup->AddAttribute("refType", this->CreateString("4"));
  1221. productGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
  1222. cmXCodeObject* productGroupChildren =
  1223. this->CreateObject(cmXCodeObject::OBJECT_LIST);
  1224. productGroup->AddAttribute("children", productGroupChildren);
  1225. m_MainGroupChildren->AddObject(productGroup);
  1226. m_RootObject = this->CreateObject(cmXCodeObject::PBXProject);
  1227. group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
  1228. m_RootObject->AddAttribute("mainGroup",
  1229. this->CreateObjectReference(mainGroup));
  1230. m_RootObject->AddAttribute("buildSettings", group);
  1231. m_RootObject->AddAttribute("buildSyles", listObjs);
  1232. m_RootObject->AddAttribute("hasScannedForEncodings",
  1233. this->CreateString("0"));
  1234. std::vector<cmXCodeObject*> targets;
  1235. for(std::vector<cmLocalGenerator*>::iterator i = generators.begin();
  1236. i != generators.end(); ++i)
  1237. {
  1238. if(!this->IsExcluded(root, *i))
  1239. {
  1240. this->CreateXCodeTargets(*i, targets);
  1241. }
  1242. }
  1243. // loop over all targets and add link and depend info
  1244. for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
  1245. i != targets.end(); ++i)
  1246. {
  1247. cmXCodeObject* t = *i;
  1248. this->AddDependAndLinkInformation(t);
  1249. }
  1250. // now create xcode depend hack makefile
  1251. this->CreateXCodeDependHackTarget(targets);
  1252. // now add all targets to the root object
  1253. cmXCodeObject* allTargets = this->CreateObject(cmXCodeObject::OBJECT_LIST);
  1254. for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
  1255. i != targets.end(); ++i)
  1256. {
  1257. cmXCodeObject* t = *i;
  1258. allTargets->AddObject(t);
  1259. cmXCodeObject* productRef = t->GetObject("productReference");
  1260. if(productRef)
  1261. {
  1262. productGroupChildren->AddObject(productRef->GetObject());
  1263. }
  1264. }
  1265. m_RootObject->AddAttribute("targets", allTargets);
  1266. }
  1267. //----------------------------------------------------------------------------
  1268. void
  1269. cmGlobalXCodeGenerator::CreateXCodeDependHackTarget(
  1270. std::vector<cmXCodeObject*>& targets)
  1271. {
  1272. cmGeneratedFileStream makefileStream(m_CurrentXCodeHackMakefile.c_str());
  1273. if(!makefileStream)
  1274. {
  1275. cmSystemTools::Error("Could not create",
  1276. m_CurrentXCodeHackMakefile.c_str());
  1277. return;
  1278. }
  1279. // one more pass for external depend information not handled
  1280. // correctly by xcode
  1281. makefileStream << "# DO NOT EDIT\n";
  1282. makefileStream << "# This makefile makes sure all linkable targets are \n";
  1283. makefileStream
  1284. << "# up-to-date with anything they link to,avoiding a bug in XCode 1.5\n";
  1285. makefileStream << "all: ";
  1286. for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
  1287. i != targets.end(); ++i)
  1288. {
  1289. cmXCodeObject* target = *i;
  1290. cmTarget* t =target->GetcmTarget();
  1291. if(t->GetType() == cmTarget::EXECUTABLE ||
  1292. t->GetType() == cmTarget::SHARED_LIBRARY ||
  1293. t->GetType() == cmTarget::MODULE_LIBRARY)
  1294. {
  1295. makefileStream << "\\\n\t"
  1296. << this->GetTargetFullPath(target->GetcmTarget());
  1297. }
  1298. }
  1299. makefileStream << "\n\n";
  1300. makefileStream
  1301. << "# For each target create a dummy rule "
  1302. "so the target does not have to exist\n";
  1303. std::set<cmStdString> emitted;
  1304. for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
  1305. i != targets.end(); ++i)
  1306. {
  1307. cmXCodeObject* target = *i;
  1308. std::vector<cmStdString> const& deplibs = target->GetDependLibraries();
  1309. for(std::vector<cmStdString>::const_iterator d = deplibs.begin();
  1310. d != deplibs.end(); ++d)
  1311. {
  1312. if(emitted.insert(*d).second)
  1313. {
  1314. makefileStream << *d << ":\n";
  1315. }
  1316. }
  1317. }
  1318. makefileStream << "\n\n";
  1319. makefileStream <<
  1320. "# Each linkable target depends on everything it links to.\n";
  1321. makefileStream
  1322. << "#And the target is removed if it is older than what it linkes to\n";
  1323. for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
  1324. i != targets.end(); ++i)
  1325. {
  1326. cmXCodeObject* target = *i;
  1327. cmTarget* t =target->GetcmTarget();
  1328. if(t->GetType() == cmTarget::EXECUTABLE ||
  1329. t->GetType() == cmTarget::SHARED_LIBRARY ||
  1330. t->GetType() == cmTarget::MODULE_LIBRARY)
  1331. {
  1332. std::vector<cmStdString> const& deplibs = target->GetDependLibraries();
  1333. std::string tfull = this->GetTargetFullPath(target->GetcmTarget());
  1334. makefileStream << tfull << ": ";
  1335. for(std::vector<cmStdString>::const_iterator d = deplibs.begin();
  1336. d != deplibs.end(); ++d)
  1337. {
  1338. makefileStream << "\\\n\t" << *d;
  1339. }
  1340. makefileStream << "\n";
  1341. makefileStream << "\t/bin/rm -f " << tfull << "\n";
  1342. makefileStream << "\n\n";
  1343. }
  1344. }
  1345. }
  1346. //----------------------------------------------------------------------------
  1347. void
  1348. cmGlobalXCodeGenerator::OutputXCodeProject(cmLocalGenerator* root,
  1349. std::vector<cmLocalGenerator*>&
  1350. generators)
  1351. {
  1352. if(generators.size() == 0)
  1353. {
  1354. return;
  1355. }
  1356. this->CreateXCodeObjects(root,
  1357. generators);
  1358. std::string xcodeDir = root->GetMakefile()->GetStartOutputDirectory();
  1359. xcodeDir += "/";
  1360. xcodeDir += root->GetMakefile()->GetProjectName();
  1361. xcodeDir += ".xcode";
  1362. cmSystemTools::MakeDirectory(xcodeDir.c_str());
  1363. xcodeDir += "/project.pbxproj";
  1364. cmGeneratedFileStream fout(xcodeDir.c_str());
  1365. fout.SetCopyIfDifferent(true);
  1366. if(!fout)
  1367. {
  1368. return;
  1369. }
  1370. this->WriteXCodePBXProj(fout, root, generators);
  1371. this->ClearXCodeObjects();
  1372. }
  1373. //----------------------------------------------------------------------------
  1374. void
  1375. cmGlobalXCodeGenerator::WriteXCodePBXProj(std::ostream& fout,
  1376. cmLocalGenerator* ,
  1377. std::vector<cmLocalGenerator*>& )
  1378. {
  1379. fout << "// !$*UTF8*$!\n";
  1380. fout << "{\n";
  1381. cmXCodeObject::Indent(1, fout);
  1382. fout << "archiveVersion = 1;\n";
  1383. cmXCodeObject::Indent(1, fout);
  1384. fout << "classes = {\n";
  1385. cmXCodeObject::Indent(1, fout);
  1386. fout << "};\n";
  1387. cmXCodeObject::Indent(1, fout);
  1388. fout << "objectVersion = 39;\n";
  1389. cmXCodeObject::PrintList(m_XCodeObjects, fout);
  1390. cmXCodeObject::Indent(1, fout);
  1391. fout << "rootObject = " << m_RootObject->GetId() << ";\n";
  1392. fout << "}\n";
  1393. }
  1394. //----------------------------------------------------------------------------
  1395. void cmGlobalXCodeGenerator::GetDocumentation(cmDocumentationEntry& entry)
  1396. const
  1397. {
  1398. entry.name = this->GetName();
  1399. entry.brief = "Generate XCode project files.";
  1400. entry.full = "";
  1401. }
  1402. //----------------------------------------------------------------------------
  1403. std::string cmGlobalXCodeGenerator::ConvertToRelativeOutputPath(const char* p)
  1404. {
  1405. if ( !m_CurrentMakefile->IsOn("CMAKE_USE_RELATIVE_PATHS") )
  1406. {
  1407. return cmSystemTools::ConvertToOutputPath(p);
  1408. }
  1409. // NOTE, much of this was copied from
  1410. // cmLocalGenerator::ConvertToRelativeOutputPath
  1411. // fixes here should be made there as well.
  1412. //
  1413. // copy to a string class
  1414. std::string pathIn = p;
  1415. // check to see if the path is already relative, it is
  1416. // considered relative if one of the following is true
  1417. // - has no / in it at all
  1418. // - does not start with / or drive leter :
  1419. // - starts with a ".."
  1420. if(pathIn.find('/') == pathIn.npos ||
  1421. (pathIn[0] != '/' && pathIn[1] != ':') ||
  1422. pathIn.find("..") == 0)
  1423. {
  1424. return cmSystemTools::ConvertToOutputPath(p);
  1425. }
  1426. // Given that we are in m_CurrentOutputDirectory how to we
  1427. // get to pathIn with a relative path, store in ret
  1428. std::string ret =
  1429. cmSystemTools::RelativePath(m_OutputDir.c_str(), pathIn.c_str());
  1430. // If the path is 0 sized make it a .
  1431. // this happens when pathIn is the same as m_CurrentOutputDirectory
  1432. if(ret.size() == 0)
  1433. {
  1434. ret = ".";
  1435. }
  1436. // if there was a trailing / there still is one, and
  1437. // if there was not one, there still is not one
  1438. if(ret[ret.size()-1] == '/' &&
  1439. pathIn[pathIn.size()-1] != '/')
  1440. {
  1441. ret.erase(ret.size()-1, 1);
  1442. }
  1443. if(ret[ret.size()-1] != '/' &&
  1444. pathIn[pathIn.size()-1] == '/')
  1445. {
  1446. ret += "/";
  1447. }
  1448. // Now convert the relative path to an output path
  1449. ret = cmSystemTools::ConvertToOutputPath(ret.c_str());
  1450. // finally return the path
  1451. // at this point it should be relative and in the correct format
  1452. // for the native build system. (i.e. \ for windows and / for unix,
  1453. // and correct escaping/quoting of spaces in the path
  1454. return ret;
  1455. }