xcodebackend.py 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855
  1. # Copyright 2014-2016 The Meson development team
  2. # Licensed under the Apache License, Version 2.0 (the "License");
  3. # you may not use this file except in compliance with the License.
  4. # You may obtain a copy of the License at
  5. # http://www.apache.org/licenses/LICENSE-2.0
  6. # Unless required by applicable law or agreed to in writing, software
  7. # distributed under the License is distributed on an "AS IS" BASIS,
  8. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. # See the License for the specific language governing permissions and
  10. # limitations under the License.
  11. from . import backends
  12. from .. import build
  13. from .. import dependencies
  14. from .. import mesonlib
  15. import uuid, os, sys
  16. from ..mesonlib import MesonException
  17. class XCodeBackend(backends.Backend):
  18. def __init__(self, build):
  19. super().__init__(build)
  20. self.name = 'xcode'
  21. self.project_uid = self.environment.coredata.guid.replace('-', '')[:24]
  22. self.project_conflist = self.gen_id()
  23. self.indent = ' '
  24. self.indent_level = 0
  25. self.xcodetypemap = {'c': 'sourcecode.c.c',
  26. 'a': 'archive.ar',
  27. 'cc': 'sourcecode.cpp.cpp',
  28. 'cxx': 'sourcecode.cpp.cpp',
  29. 'cpp': 'sourcecode.cpp.cpp',
  30. 'c++': 'sourcecode.cpp.cpp',
  31. 'm': 'sourcecode.c.objc',
  32. 'mm': 'sourcecode.cpp.objcpp',
  33. 'h': 'sourcecode.c.h',
  34. 'hpp': 'sourcecode.cpp.h',
  35. 'hxx': 'sourcecode.cpp.h',
  36. 'hh': 'sourcecode.cpp.hh',
  37. 'inc': 'sourcecode.c.h',
  38. 'dylib': 'compiled.mach-o.dylib',
  39. 'o': 'compiled.mach-o.objfile',
  40. }
  41. self.maingroup_id = self.gen_id()
  42. self.all_id = self.gen_id()
  43. self.all_buildconf_id = self.gen_id()
  44. self.buildtypes = ['debug']
  45. self.test_id = self.gen_id()
  46. self.test_command_id = self.gen_id()
  47. self.test_buildconf_id = self.gen_id()
  48. def gen_id(self):
  49. return str(uuid.uuid4()).upper().replace('-', '')[:24]
  50. def get_target_dir(self, target):
  51. dirname = os.path.join(target.get_subdir(), self.environment.coredata.get_builtin_option('buildtype'))
  52. os.makedirs(os.path.join(self.environment.get_build_dir(), dirname), exist_ok=True)
  53. return dirname
  54. def write_line(self, text):
  55. self.ofile.write(self.indent * self.indent_level + text)
  56. if not text.endswith('\n'):
  57. self.ofile.write('\n')
  58. def generate(self, interp):
  59. self.interpreter = interp
  60. test_data = self.serialize_tests()[0]
  61. self.generate_filemap()
  62. self.generate_buildmap()
  63. self.generate_buildstylemap()
  64. self.generate_build_phase_map()
  65. self.generate_build_configuration_map()
  66. self.generate_build_configurationlist_map()
  67. self.generate_project_configurations_map()
  68. self.generate_buildall_configurations_map()
  69. self.generate_test_configurations_map()
  70. self.generate_native_target_map()
  71. self.generate_native_frameworks_map()
  72. self.generate_source_phase_map()
  73. self.generate_target_dependency_map()
  74. self.generate_pbxdep_map()
  75. self.generate_containerproxy_map()
  76. self.proj_dir = os.path.join(self.environment.get_build_dir(), self.build.project_name + '.xcodeproj')
  77. os.makedirs(self.proj_dir, exist_ok=True)
  78. self.proj_file = os.path.join(self.proj_dir, 'project.pbxproj')
  79. with open(self.proj_file, 'w') as self.ofile:
  80. self.generate_prefix()
  81. self.generate_pbx_aggregate_target()
  82. self.generate_pbx_build_file()
  83. self.generate_pbx_build_style()
  84. self.generate_pbx_container_item_proxy()
  85. self.generate_pbx_file_reference()
  86. self.generate_pbx_frameworks_buildphase()
  87. self.generate_pbx_group()
  88. self.generate_pbx_native_target()
  89. self.generate_pbx_project()
  90. self.generate_pbx_shell_build_phase(test_data)
  91. self.generate_pbx_sources_build_phase()
  92. self.generate_pbx_target_dependency()
  93. self.generate_xc_build_configuration()
  94. self.generate_xc_configurationList()
  95. self.generate_suffix()
  96. def get_xcodetype(self, fname):
  97. return self.xcodetypemap[fname.split('.')[-1]]
  98. def generate_filemap(self):
  99. self.filemap = {} # Key is source file relative to src root.
  100. self.target_filemap = {}
  101. for name, t in self.build.targets.items():
  102. for s in t.sources:
  103. if isinstance(s, mesonlib.File):
  104. s = os.path.join(s.subdir, s.fname)
  105. self.filemap[s] = self.gen_id()
  106. for o in t.objects:
  107. if isinstance(o, str):
  108. o = os.path.join(t.subdir, o)
  109. self.filemap[o] = self.gen_id()
  110. self.target_filemap[name] = self.gen_id()
  111. def generate_buildmap(self):
  112. self.buildmap = {}
  113. for t in self.build.targets.values():
  114. for s in t.sources:
  115. s = os.path.join(s.subdir, s.fname)
  116. self.buildmap[s] = self.gen_id()
  117. for o in t.objects:
  118. o = os.path.join(t.subdir, o)
  119. if isinstance(o, str):
  120. self.buildmap[o] = self.gen_id()
  121. def generate_buildstylemap(self):
  122. self.buildstylemap = {'debug': self.gen_id()}
  123. def generate_build_phase_map(self):
  124. for tname, t in self.build.targets.items():
  125. # generate id for our own target-name
  126. t.buildphasemap = {}
  127. t.buildphasemap[tname] = self.gen_id()
  128. # each target can have it's own Frameworks/Sources/..., generate id's for those
  129. t.buildphasemap['Frameworks'] = self.gen_id()
  130. t.buildphasemap['Resources'] = self.gen_id()
  131. t.buildphasemap['Sources'] = self.gen_id()
  132. def generate_build_configuration_map(self):
  133. self.buildconfmap = {}
  134. for t in self.build.targets:
  135. bconfs = {'debug': self.gen_id()}
  136. self.buildconfmap[t] = bconfs
  137. def generate_project_configurations_map(self):
  138. self.project_configurations = {'debug': self.gen_id()}
  139. def generate_buildall_configurations_map(self):
  140. self.buildall_configurations = {'debug': self.gen_id()}
  141. def generate_test_configurations_map(self):
  142. self.test_configurations = {'debug': self.gen_id()}
  143. def generate_build_configurationlist_map(self):
  144. self.buildconflistmap = {}
  145. for t in self.build.targets:
  146. self.buildconflistmap[t] = self.gen_id()
  147. def generate_native_target_map(self):
  148. self.native_targets = {}
  149. for t in self.build.targets:
  150. self.native_targets[t] = self.gen_id()
  151. def generate_native_frameworks_map(self):
  152. self.native_frameworks = {}
  153. self.native_frameworks_fileref = {}
  154. for t in self.build.targets.values():
  155. for dep in t.get_external_deps():
  156. if isinstance(dep, dependencies.AppleFrameworks):
  157. for f in dep.frameworks:
  158. self.native_frameworks[f] = self.gen_id()
  159. self.native_frameworks_fileref[f] = self.gen_id()
  160. def generate_target_dependency_map(self):
  161. self.target_dependency_map = {}
  162. for tname, t in self.build.targets.items():
  163. for target in t.link_targets:
  164. self.target_dependency_map[(tname, target.get_basename())] = self.gen_id()
  165. def generate_pbxdep_map(self):
  166. self.pbx_dep_map = {}
  167. for t in self.build.targets:
  168. self.pbx_dep_map[t] = self.gen_id()
  169. def generate_containerproxy_map(self):
  170. self.containerproxy_map = {}
  171. for t in self.build.targets:
  172. self.containerproxy_map[t] = self.gen_id()
  173. def generate_source_phase_map(self):
  174. self.source_phase = {}
  175. for t in self.build.targets:
  176. self.source_phase[t] = self.gen_id()
  177. def generate_pbx_aggregate_target(self):
  178. self.ofile.write('\n/* Begin PBXAggregateTarget section */\n')
  179. self.write_line('%s /* ALL_BUILD */ = {' % self.all_id)
  180. self.indent_level += 1
  181. self.write_line('isa = PBXAggregateTarget;')
  182. self.write_line('buildConfigurationList = %s;' % self.all_buildconf_id)
  183. self.write_line('buildPhases = (')
  184. self.write_line(');')
  185. self.write_line('dependencies = (')
  186. self.indent_level += 1
  187. for t in self.build.targets:
  188. self.write_line('%s /* PBXTargetDependency */,' % self.pbx_dep_map[t])
  189. self.indent_level -= 1
  190. self.write_line(');')
  191. self.write_line('name = ALL_BUILD;')
  192. self.write_line('productName = ALL_BUILD;')
  193. self.indent_level -= 1
  194. self.write_line('};')
  195. self.write_line('%s /* RUN_TESTS */ = {' % self.test_id)
  196. self.indent_level += 1
  197. self.write_line('isa = PBXAggregateTarget;')
  198. self.write_line('buildConfigurationList = %s;' % self.test_buildconf_id)
  199. self.write_line('buildPhases = (')
  200. self.indent_level += 1
  201. self.write_line('%s /* test run command */,' % self.test_command_id)
  202. self.indent_level -= 1
  203. self.write_line(');')
  204. self.write_line('dependencies = (')
  205. self.write_line(');')
  206. self.write_line('name = RUN_TESTS;')
  207. self.write_line('productName = RUN_TESTS;')
  208. self.indent_level -= 1
  209. self.write_line('};')
  210. self.ofile.write('/* End PBXAggregateTarget section */\n')
  211. def generate_pbx_build_file(self):
  212. self.ofile.write('\n/* Begin PBXBuildFile section */\n')
  213. templ = '%s /* %s */ = { isa = PBXBuildFile; fileRef = %s /* %s */; settings = { COMPILER_FLAGS = "%s"; }; };\n'
  214. otempl = '%s /* %s */ = { isa = PBXBuildFile; fileRef = %s /* %s */;};\n'
  215. for t in self.build.targets.values():
  216. for dep in t.get_external_deps():
  217. if isinstance(dep, dependencies.AppleFrameworks):
  218. for f in dep.frameworks:
  219. self.ofile.write('%s /* %s.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = %s /* %s.framework */; };\n' % (self.native_frameworks[f], f, self.native_frameworks_fileref[f], f))
  220. for s in t.sources:
  221. if isinstance(s, mesonlib.File):
  222. s = s.fname
  223. if isinstance(s, str):
  224. s = os.path.join(t.subdir, s)
  225. idval = self.buildmap[s]
  226. fullpath = os.path.join(self.environment.get_source_dir(), s)
  227. fileref = self.filemap[s]
  228. fullpath2 = fullpath
  229. compiler_args = ''
  230. self.ofile.write(templ % (idval, fullpath, fileref, fullpath2, compiler_args))
  231. for o in t.objects:
  232. o = os.path.join(t.subdir, o)
  233. idval = self.buildmap[o]
  234. fileref = self.filemap[o]
  235. fullpath = os.path.join(self.environment.get_source_dir(), o)
  236. fullpath2 = fullpath
  237. self.ofile.write(otempl % (idval, fullpath, fileref, fullpath2))
  238. self.ofile.write('/* End PBXBuildFile section */\n')
  239. def generate_pbx_build_style(self):
  240. self.ofile.write('\n/* Begin PBXBuildStyle section */\n')
  241. for name, idval in self.buildstylemap.items():
  242. self.write_line('%s /* %s */ = {\n' % (idval, name))
  243. self.indent_level += 1
  244. self.write_line('isa = PBXBuildStyle;\n')
  245. self.write_line('buildSettings = {\n')
  246. self.indent_level += 1
  247. self.write_line('COPY_PHASE_STRIP = NO;\n')
  248. self.indent_level -= 1
  249. self.write_line('};\n')
  250. self.write_line('name = "%s";\n' % name)
  251. self.indent_level -= 1
  252. self.write_line('};\n')
  253. self.ofile.write('/* End PBXBuildStyle section */\n')
  254. def generate_pbx_container_item_proxy(self):
  255. self.ofile.write('\n/* Begin PBXContainerItemProxy section */\n')
  256. for t in self.build.targets:
  257. self.write_line('%s /* PBXContainerItemProxy */ = {' % self.containerproxy_map[t])
  258. self.indent_level += 1
  259. self.write_line('isa = PBXContainerItemProxy;')
  260. self.write_line('containerPortal = %s /* Project object */;' % self.project_uid)
  261. self.write_line('proxyType = 1;')
  262. self.write_line('remoteGlobalIDString = %s;' % self.native_targets[t])
  263. self.write_line('remoteInfo = "%s";' % t)
  264. self.indent_level -= 1
  265. self.write_line('};')
  266. self.ofile.write('/* End PBXContainerItemProxy section */\n')
  267. def generate_pbx_file_reference(self):
  268. self.ofile.write('\n/* Begin PBXFileReference section */\n')
  269. for t in self.build.targets.values():
  270. for dep in t.get_external_deps():
  271. if isinstance(dep, dependencies.AppleFrameworks):
  272. for f in dep.frameworks:
  273. self.ofile.write('%s /* %s.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = %s.framework; path = System/Library/Frameworks/%s.framework; sourceTree = SDKROOT; };\n' % (self.native_frameworks_fileref[f], f, f, f))
  274. src_templ = '%s /* %s */ = { isa = PBXFileReference; explicitFileType = "%s"; fileEncoding = 4; name = "%s"; path = "%s"; sourceTree = SOURCE_ROOT; };\n'
  275. for fname, idval in self.filemap.items():
  276. fullpath = os.path.join(self.environment.get_source_dir(), fname)
  277. xcodetype = self.get_xcodetype(fname)
  278. name = os.path.split(fname)[-1]
  279. path = fname
  280. self.ofile.write(src_templ % (idval, fullpath, xcodetype, name, path))
  281. target_templ = '%s /* %s */ = { isa = PBXFileReference; explicitFileType = "%s"; path = %s; refType = %d; sourceTree = BUILT_PRODUCTS_DIR; };\n'
  282. for tname, idval in self.target_filemap.items():
  283. t = self.build.targets[tname]
  284. fname = t.get_filename()
  285. reftype = 0
  286. if isinstance(t, build.Executable):
  287. typestr = 'compiled.mach-o.executable'
  288. path = fname
  289. elif isinstance(t, build.SharedLibrary):
  290. typestr = self.get_xcodetype('dummy.dylib')
  291. path = fname
  292. else:
  293. typestr = self.get_xcodetype(fname)
  294. path = '"%s"' % t.get_filename()
  295. self.ofile.write(target_templ % (idval, tname, typestr, path, reftype))
  296. self.ofile.write('/* End PBXFileReference section */\n')
  297. def generate_pbx_frameworks_buildphase(self):
  298. for tname, t in self.build.targets.items():
  299. self.ofile.write('\n/* Begin PBXFrameworksBuildPhase section */\n')
  300. self.indent_level += 1
  301. self.write_line('%s /* %s */ = {\n' % (t.buildphasemap['Frameworks'], 'Frameworks'))
  302. self.indent_level += 1
  303. self.write_line('isa = PBXFrameworksBuildPhase;\n')
  304. self.write_line('buildActionMask = %s;\n' % (2147483647))
  305. self.write_line('files = (\n')
  306. self.indent_level += 1
  307. for dep in t.get_external_deps():
  308. if isinstance(dep, dependencies.AppleFrameworks):
  309. for f in dep.frameworks:
  310. self.write_line('%s /* %s.framework in Frameworks */,\n' % (self.native_frameworks[f], f))
  311. self.indent_level -= 1
  312. self.write_line(');\n')
  313. self.write_line('runOnlyForDeploymentPostprocessing = 0;\n')
  314. self.indent_level -= 1
  315. self.write_line('};\n')
  316. self.ofile.write('/* End PBXFrameworksBuildPhase section */\n')
  317. def generate_pbx_group(self):
  318. groupmap = {}
  319. target_src_map = {}
  320. for t in self.build.targets:
  321. groupmap[t] = self.gen_id()
  322. target_src_map[t] = self.gen_id()
  323. self.ofile.write('\n/* Begin PBXGroup section */\n')
  324. sources_id = self.gen_id()
  325. resources_id = self.gen_id()
  326. products_id = self.gen_id()
  327. frameworks_id = self.gen_id()
  328. self.write_line('%s = {' % self.maingroup_id)
  329. self.indent_level += 1
  330. self.write_line('isa = PBXGroup;')
  331. self.write_line('children = (')
  332. self.indent_level += 1
  333. self.write_line('%s /* Sources */,' % sources_id)
  334. self.write_line('%s /* Resources */,' % resources_id)
  335. self.write_line('%s /* Products */,' % products_id)
  336. self.write_line('%s /* Frameworks */,' % frameworks_id)
  337. self.indent_level -= 1
  338. self.write_line(');')
  339. self.write_line('sourceTree = "<group>";')
  340. self.indent_level -= 1
  341. self.write_line('};')
  342. # Sources
  343. self.write_line('%s /* Sources */ = {' % sources_id)
  344. self.indent_level += 1
  345. self.write_line('isa = PBXGroup;')
  346. self.write_line('children = (')
  347. self.indent_level += 1
  348. for t in self.build.targets:
  349. self.write_line('%s /* %s */,' % (groupmap[t], t))
  350. self.indent_level -= 1
  351. self.write_line(');')
  352. self.write_line('name = Sources;')
  353. self.write_line('sourcetree = "<group>";')
  354. self.indent_level -= 1
  355. self.write_line('};')
  356. self.write_line('%s /* Resources */ = {' % resources_id)
  357. self.indent_level += 1
  358. self.write_line('isa = PBXGroup;')
  359. self.write_line('children = (')
  360. self.write_line(');')
  361. self.write_line('name = Resources;')
  362. self.write_line('sourceTree = "<group>";')
  363. self.indent_level -= 1
  364. self.write_line('};')
  365. self.write_line('%s /* Frameworks */ = {' % frameworks_id)
  366. self.indent_level += 1
  367. self.write_line('isa = PBXGroup;')
  368. self.write_line('children = (')
  369. # write frameworks
  370. self.indent_level += 1
  371. for t in self.build.targets.values():
  372. for dep in t.get_external_deps():
  373. if isinstance(dep, dependencies.AppleFrameworks):
  374. for f in dep.frameworks:
  375. self.write_line('%s /* %s.framework */,\n' % (self.native_frameworks_fileref[f], f))
  376. self.indent_level -= 1
  377. self.write_line(');')
  378. self.write_line('name = Frameworks;')
  379. self.write_line('sourceTree = "<group>";')
  380. self.indent_level -= 1
  381. self.write_line('};')
  382. # Targets
  383. for t in self.build.targets:
  384. self.write_line('%s /* %s */ = {' % (groupmap[t], t))
  385. self.indent_level += 1
  386. self.write_line('isa = PBXGroup;')
  387. self.write_line('children = (')
  388. self.indent_level += 1
  389. self.write_line('%s /* Source files */,' % target_src_map[t])
  390. self.indent_level -= 1
  391. self.write_line(');')
  392. self.write_line('name = "%s";' % t)
  393. self.write_line('sourceTree = "<group>";')
  394. self.indent_level -= 1
  395. self.write_line('};')
  396. self.write_line('%s /* Source files */ = {' % target_src_map[t])
  397. self.indent_level += 1
  398. self.write_line('isa = PBXGroup;')
  399. self.write_line('children = (')
  400. self.indent_level += 1
  401. for s in self.build.targets[t].sources:
  402. s = os.path.join(s.subdir, s.fname)
  403. if isinstance(s, str):
  404. self.write_line('%s /* %s */,' % (self.filemap[s], s))
  405. for o in self.build.targets[t].objects:
  406. o = os.path.join(self.build.targets[t].subdir, o)
  407. self.write_line('%s /* %s */,' % (self.filemap[o], o))
  408. self.indent_level -= 1
  409. self.write_line(');')
  410. self.write_line('name = "Source files";')
  411. self.write_line('sourceTree = "<group>";')
  412. self.indent_level -= 1
  413. self.write_line('};')
  414. # And finally products
  415. self.write_line('%s /* Products */ = {' % products_id)
  416. self.indent_level += 1
  417. self.write_line('isa = PBXGroup;')
  418. self.write_line('children = (')
  419. self.indent_level += 1
  420. for t in self.build.targets:
  421. self.write_line('%s /* %s */,' % (self.target_filemap[t], t))
  422. self.indent_level -= 1
  423. self.write_line(');')
  424. self.write_line('name = Products;')
  425. self.write_line('sourceTree = "<group>";')
  426. self.indent_level -= 1
  427. self.write_line('};')
  428. self.ofile.write('/* End PBXGroup section */\n')
  429. def generate_pbx_native_target(self):
  430. self.ofile.write('\n/* Begin PBXNativeTarget section */\n')
  431. for tname, idval in self.native_targets.items():
  432. t = self.build.targets[tname]
  433. self.write_line('%s /* %s */ = {' % (idval, tname))
  434. self.indent_level += 1
  435. self.write_line('isa = PBXNativeTarget;')
  436. self.write_line('buildConfigurationList = %s /* Build configuration list for PBXNativeTarget "%s" */;'
  437. % (self.buildconflistmap[tname], tname))
  438. self.write_line('buildPhases = (')
  439. self.indent_level += 1
  440. for bpname, bpval in t.buildphasemap.items():
  441. self.write_line('%s /* %s yyy */,' % (bpval, bpname))
  442. self.indent_level -= 1
  443. self.write_line(');')
  444. self.write_line('buildRules = (')
  445. self.write_line(');')
  446. self.write_line('dependencies = (')
  447. self.indent_level += 1
  448. for lt in self.build.targets[tname].link_targets:
  449. # NOT DOCUMENTED, may need to make different links
  450. # to same target have different targetdependency item.
  451. idval = self.pbx_dep_map[lt.get_id()]
  452. self.write_line('%s /* PBXTargetDependency */,' % idval)
  453. self.indent_level -= 1
  454. self.write_line(");")
  455. self.write_line('name = "%s";' % tname)
  456. self.write_line('productName = "%s";' % tname)
  457. self.write_line('productReference = %s /* %s */;' % (self.target_filemap[tname], tname))
  458. if isinstance(t, build.Executable):
  459. typestr = 'com.apple.product-type.tool'
  460. elif isinstance(t, build.StaticLibrary):
  461. typestr = 'com.apple.product-type.library.static'
  462. elif isinstance(t, build.SharedLibrary):
  463. typestr = 'com.apple.product-type.library.dynamic'
  464. else:
  465. raise MesonException('Unknown target type for %s' % tname)
  466. self.write_line('productType = "%s";' % typestr)
  467. self.indent_level -= 1
  468. self.write_line('};')
  469. self.ofile.write('/* End PBXNativeTarget section */\n')
  470. def generate_pbx_project(self):
  471. self.ofile.write('\n/* Begin PBXProject section */\n')
  472. self.write_line('%s /* Project object */ = {' % self.project_uid)
  473. self.indent_level += 1
  474. self.write_line('isa = PBXProject;')
  475. self.write_line('attributes = {')
  476. self.indent_level += 1
  477. self.write_line('BuildIndependentTargetsInParallel = YES;')
  478. self.indent_level -= 1
  479. self.write_line('};')
  480. conftempl = 'buildConfigurationList = %s /* build configuration list for PBXProject "%s"*/;'
  481. self.write_line(conftempl % (self.project_conflist, self.build.project_name))
  482. self.write_line('buildSettings = {')
  483. self.write_line('};')
  484. self.write_line('buildStyles = (')
  485. self.indent_level += 1
  486. for name, idval in self.buildstylemap.items():
  487. self.write_line('%s /* %s */,' % (idval, name))
  488. self.indent_level -= 1
  489. self.write_line(');')
  490. self.write_line('compatibilityVersion = "Xcode 3.2";')
  491. self.write_line('hasScannedForEncodings = 0;')
  492. self.write_line('mainGroup = %s;' % self.maingroup_id)
  493. self.write_line('projectDirPath = "%s";' % self.build_to_src)
  494. self.write_line('projectRoot = "";')
  495. self.write_line('targets = (')
  496. self.indent_level += 1
  497. self.write_line('%s /* ALL_BUILD */,' % self.all_id)
  498. self.write_line('%s /* RUN_TESTS */,' % self.test_id)
  499. for t in self.build.targets:
  500. self.write_line('%s /* %s */,' % (self.native_targets[t], t))
  501. self.indent_level -= 1
  502. self.write_line(');')
  503. self.indent_level -= 1
  504. self.write_line('};')
  505. self.ofile.write('/* End PBXProject section */\n')
  506. def generate_pbx_shell_build_phase(self, test_data):
  507. self.ofile.write('\n/* Begin PBXShellScriptBuildPhase section */\n')
  508. self.write_line('%s = {' % self.test_command_id)
  509. self.indent_level += 1
  510. self.write_line('isa = PBXShellScriptBuildPhase;')
  511. self.write_line('buildActionMask = 2147483647;')
  512. self.write_line('files = (')
  513. self.write_line(');')
  514. self.write_line('inputPaths = (')
  515. self.write_line(');')
  516. self.write_line('outputPaths = (')
  517. self.write_line(');')
  518. self.write_line('runOnlyForDeploymentPostprocessing = 0;')
  519. self.write_line('shellPath = /bin/sh;')
  520. script_root = self.environment.get_script_dir()
  521. test_script = os.path.join(script_root, 'meson_test.py')
  522. cmd = [sys.executable, test_script, test_data, '--wd', self.environment.get_build_dir()]
  523. cmdstr = ' '.join(["'%s'" % i for i in cmd])
  524. self.write_line('shellScript = "%s";' % cmdstr)
  525. self.write_line('showEnvVarsInLog = 0;')
  526. self.indent_level -= 1
  527. self.write_line('};')
  528. self.ofile.write('/* End PBXShellScriptBuildPhase section */\n')
  529. def generate_pbx_sources_build_phase(self):
  530. self.ofile.write('\n/* Begin PBXSourcesBuildPhase section */\n')
  531. for name, phase_id in self.source_phase.items():
  532. t = self.build.targets[name]
  533. self.write_line('%s /* Sources */ = {' % (t.buildphasemap[name]))
  534. self.indent_level += 1
  535. self.write_line('isa = PBXSourcesBuildPhase;')
  536. self.write_line('buildActionMask = 2147483647;')
  537. self.write_line('files = (')
  538. self.indent_level += 1
  539. for s in self.build.targets[name].sources:
  540. s = os.path.join(s.subdir, s.fname)
  541. if not self.environment.is_header(s):
  542. self.write_line('%s /* %s */,' % (self.buildmap[s], os.path.join(self.environment.get_source_dir(), s)))
  543. self.indent_level -= 1
  544. self.write_line(');')
  545. self.write_line('runOnlyForDeploymentPostprocessing = 0;')
  546. self.indent_level -= 1
  547. self.write_line('};')
  548. self.ofile.write('/* End PBXSourcesBuildPhase section */\n')
  549. def generate_pbx_target_dependency(self):
  550. self.ofile.write('\n/* Begin PBXTargetDependency section */\n')
  551. for t in self.build.targets:
  552. idval = self.pbx_dep_map[t] # VERIFY: is this correct?
  553. self.write_line('%s /* PBXTargetDependency */ = {' % idval)
  554. self.indent_level += 1
  555. self.write_line('isa = PBXTargetDependency;')
  556. self.write_line('target = %s /* %s */;' % (self.native_targets[t], t))
  557. self.write_line('targetProxy = %s /* PBXContainerItemProxy */;' % self.containerproxy_map[t])
  558. self.indent_level -= 1
  559. self.write_line('};')
  560. self.ofile.write('/* End PBXTargetDependency section */\n')
  561. def generate_xc_build_configuration(self):
  562. self.ofile.write('\n/* Begin XCBuildConfiguration section */\n')
  563. # First the setup for the toplevel project.
  564. for buildtype in self.buildtypes:
  565. self.write_line('%s /* %s */ = {' % (self.project_configurations[buildtype], buildtype))
  566. self.indent_level += 1
  567. self.write_line('isa = XCBuildConfiguration;')
  568. self.write_line('buildSettings = {')
  569. self.indent_level += 1
  570. self.write_line('ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";')
  571. self.write_line('ONLY_ACTIVE_ARCH = YES;')
  572. self.write_line('SDKROOT = "macosx";')
  573. self.write_line('SYMROOT = "%s/build";' % self.environment.get_build_dir())
  574. self.indent_level -= 1
  575. self.write_line('};')
  576. self.write_line('name = "%s";' % buildtype)
  577. self.indent_level -= 1
  578. self.write_line('};')
  579. # Then the all target.
  580. for buildtype in self.buildtypes:
  581. self.write_line('%s /* %s */ = {' % (self.buildall_configurations[buildtype], buildtype))
  582. self.indent_level += 1
  583. self.write_line('isa = XCBuildConfiguration;')
  584. self.write_line('buildSettings = {')
  585. self.indent_level += 1
  586. self.write_line('COMBINE_HIDPI_IMAGES = YES;')
  587. self.write_line('GCC_GENERATE_DEBUGGING_SYMBOLS = NO;')
  588. self.write_line('GCC_INLINES_ARE_PRIVATE_EXTERN = NO;')
  589. self.write_line('GCC_OPTIMIZATION_LEVEL = 0;')
  590. self.write_line('GCC_PREPROCESSOR_DEFINITIONS = ("");')
  591. self.write_line('GCC_SYMBOLS_PRIVATE_EXTERN = NO;')
  592. self.write_line('INSTALL_PATH = "";')
  593. self.write_line('OTHER_CFLAGS = " ";')
  594. self.write_line('OTHER_LDFLAGS = " ";')
  595. self.write_line('OTHER_REZFLAGS = "";')
  596. self.write_line('PRODUCT_NAME = ALL_BUILD;')
  597. self.write_line('SECTORDER_FLAGS = "";')
  598. self.write_line('SYMROOT = "%s";' % self.environment.get_build_dir())
  599. self.write_line('USE_HEADERMAP = NO;')
  600. self.write_line('WARNING_CFLAGS = ("-Wmost", "-Wno-four-char-constants", "-Wno-unknown-pragmas", );')
  601. self.indent_level -= 1
  602. self.write_line('};')
  603. self.write_line('name = "%s";' % buildtype)
  604. self.indent_level -= 1
  605. self.write_line('};')
  606. # Then the test target.
  607. for buildtype in self.buildtypes:
  608. self.write_line('%s /* %s */ = {' % (self.test_configurations[buildtype], buildtype))
  609. self.indent_level += 1
  610. self.write_line('isa = XCBuildConfiguration;')
  611. self.write_line('buildSettings = {')
  612. self.indent_level += 1
  613. self.write_line('COMBINE_HIDPI_IMAGES = YES;')
  614. self.write_line('GCC_GENERATE_DEBUGGING_SYMBOLS = NO;')
  615. self.write_line('GCC_INLINES_ARE_PRIVATE_EXTERN = NO;')
  616. self.write_line('GCC_OPTIMIZATION_LEVEL = 0;')
  617. self.write_line('GCC_PREPROCESSOR_DEFINITIONS = ("");')
  618. self.write_line('GCC_SYMBOLS_PRIVATE_EXTERN = NO;')
  619. self.write_line('INSTALL_PATH = "";')
  620. self.write_line('OTHER_CFLAGS = " ";')
  621. self.write_line('OTHER_LDFLAGS = " ";')
  622. self.write_line('OTHER_REZFLAGS = "";')
  623. self.write_line('PRODUCT_NAME = RUN_TESTS;')
  624. self.write_line('SECTORDER_FLAGS = "";')
  625. self.write_line('SYMROOT = "%s";' % self.environment.get_build_dir())
  626. self.write_line('USE_HEADERMAP = NO;')
  627. self.write_line('WARNING_CFLAGS = ("-Wmost", "-Wno-four-char-constants", "-Wno-unknown-pragmas", );')
  628. self.indent_level -= 1
  629. self.write_line('};')
  630. self.write_line('name = "%s";' % buildtype)
  631. self.indent_level -= 1
  632. self.write_line('};')
  633. # Now finally targets.
  634. langnamemap = {'c': 'C', 'cpp': 'CPLUSPLUS', 'objc': 'OBJC', 'objcpp': 'OBJCPLUSPLUS'}
  635. for target_name, target in self.build.targets.items():
  636. for buildtype in self.buildtypes:
  637. dep_libs = []
  638. links_dylib = False
  639. headerdirs = []
  640. for d in target.include_dirs:
  641. for sd in d.incdirs:
  642. cd = os.path.join(d.curdir, sd)
  643. headerdirs.append(os.path.join(self.environment.get_source_dir(), cd))
  644. headerdirs.append(os.path.join(self.environment.get_build_dir(), cd))
  645. for l in target.link_targets:
  646. abs_path = os.path.join(self.environment.get_build_dir(),
  647. l.subdir, buildtype, l.get_filename())
  648. dep_libs.append("'%s'" % abs_path)
  649. if isinstance(l, build.SharedLibrary):
  650. links_dylib = True
  651. if links_dylib:
  652. dep_libs = ['-Wl,-search_paths_first', '-Wl,-headerpad_max_install_names'] + dep_libs
  653. dylib_version = None
  654. if isinstance(target, build.SharedLibrary):
  655. ldargs = ['-dynamiclib', '-Wl,-headerpad_max_install_names'] + dep_libs
  656. install_path = os.path.join(self.environment.get_build_dir(), target.subdir, buildtype)
  657. dylib_version = target.version
  658. else:
  659. ldargs = dep_libs
  660. install_path = ''
  661. if dylib_version is not None:
  662. product_name = target.get_basename() + '.' + dylib_version
  663. else:
  664. product_name = target.get_basename()
  665. ldargs += target.link_args
  666. ldstr = ' '.join(ldargs)
  667. valid = self.buildconfmap[target_name][buildtype]
  668. langargs = {}
  669. for lang in self.environment.coredata.compilers:
  670. if lang not in langnamemap:
  671. continue
  672. gargs = self.build.global_args.get(lang, [])
  673. targs = target.get_extra_args(lang)
  674. args = gargs + targs
  675. if len(args) > 0:
  676. langargs[langnamemap[lang]] = args
  677. symroot = os.path.join(self.environment.get_build_dir(), target.subdir)
  678. self.write_line('%s /* %s */ = {' % (valid, buildtype))
  679. self.indent_level += 1
  680. self.write_line('isa = XCBuildConfiguration;')
  681. self.write_line('buildSettings = {')
  682. self.indent_level += 1
  683. self.write_line('COMBINE_HIDPI_IMAGES = YES;')
  684. if dylib_version is not None:
  685. self.write_line('DYLIB_CURRENT_VERSION = "%s";' % dylib_version)
  686. self.write_line('EXECUTABLE_PREFIX = "%s";' % target.prefix)
  687. if target.suffix == '':
  688. suffix = ''
  689. else:
  690. suffix = '.' + target.suffix
  691. self.write_line('EXECUTABLE_SUFFIX = "%s";' % suffix)
  692. self.write_line('GCC_GENERATE_DEBUGGING_SYMBOLS = YES;')
  693. self.write_line('GCC_INLINES_ARE_PRIVATE_EXTERN = NO;')
  694. self.write_line('GCC_OPTIMIZATION_LEVEL = 0;')
  695. self.write_line('GCC_PREPROCESSOR_DEFINITIONS = ("");')
  696. self.write_line('GCC_SYMBOLS_PRIVATE_EXTERN = NO;')
  697. if len(headerdirs) > 0:
  698. quotedh = ','.join(['"\\"%s\\""' % i for i in headerdirs])
  699. self.write_line('HEADER_SEARCH_PATHS=(%s);' % quotedh)
  700. self.write_line('INSTALL_PATH = "%s";' % install_path)
  701. self.write_line('LIBRARY_SEARCH_PATHS = "";')
  702. if isinstance(target, build.SharedLibrary):
  703. self.write_line('LIBRARY_STYLE = DYNAMIC;')
  704. for langname, args in langargs.items():
  705. argstr = ' '.join(args)
  706. self.write_line('OTHER_%sFLAGS = "%s";' % (langname, argstr))
  707. self.write_line('OTHER_LDFLAGS = "%s";' % ldstr)
  708. self.write_line('OTHER_REZFLAGS = "";')
  709. self.write_line('PRODUCT_NAME = %s;' % product_name)
  710. self.write_line('SECTORDER_FLAGS = "";')
  711. self.write_line('SYMROOT = "%s";' % symroot)
  712. self.write_line('USE_HEADERMAP = NO;')
  713. self.write_line('WARNING_CFLAGS = ("-Wmost", "-Wno-four-char-constants", "-Wno-unknown-pragmas", );')
  714. self.indent_level -= 1
  715. self.write_line('};')
  716. self.write_line('name = "%s";' % buildtype)
  717. self.indent_level -= 1
  718. self.write_line('};')
  719. self.ofile.write('/* End XCBuildConfiguration section */\n')
  720. def generate_xc_configurationList(self):
  721. self.ofile.write('\n/* Begin XCConfigurationList section */\n')
  722. self.write_line('%s /* Build configuration list for PBXProject "%s" */ = {' % (self.project_conflist, self.build.project_name))
  723. self.indent_level += 1
  724. self.write_line('isa = XCConfigurationList;')
  725. self.write_line('buildConfigurations = (')
  726. self.indent_level += 1
  727. for buildtype in self.buildtypes:
  728. self.write_line('%s /* %s */,' % (self.project_configurations[buildtype], buildtype))
  729. self.indent_level -= 1
  730. self.write_line(');')
  731. self.write_line('defaultConfigurationIsVisible = 0;')
  732. self.write_line('defaultConfigurationName = debug;')
  733. self.indent_level -= 1
  734. self.write_line('};')
  735. # Now the all target
  736. self.write_line('%s /* Build configuration list for PBXAggregateTarget "ALL_BUILD" */ = {' % self.all_buildconf_id)
  737. self.indent_level += 1
  738. self.write_line('isa = XCConfigurationList;')
  739. self.write_line('buildConfigurations = (')
  740. self.indent_level += 1
  741. for buildtype in self.buildtypes:
  742. self.write_line('%s /* %s */,' % (self.buildall_configurations[buildtype], buildtype))
  743. self.indent_level -= 1
  744. self.write_line(');')
  745. self.write_line('defaultConfigurationIsVisible = 0;')
  746. self.write_line('defaultConfigurationName = debug;')
  747. self.indent_level -= 1
  748. self.write_line('};')
  749. # Test target
  750. self.write_line('%s /* Build configuration list for PBXAggregateTarget "ALL_BUILD" */ = {' % self.test_buildconf_id)
  751. self.indent_level += 1
  752. self.write_line('isa = XCConfigurationList;')
  753. self.write_line('buildConfigurations = (')
  754. self.indent_level += 1
  755. for buildtype in self.buildtypes:
  756. self.write_line('%s /* %s */,' % (self.test_configurations[buildtype], buildtype))
  757. self.indent_level -= 1
  758. self.write_line(');')
  759. self.write_line('defaultConfigurationIsVisible = 0;')
  760. self.write_line('defaultConfigurationName = debug;')
  761. self.indent_level -= 1
  762. self.write_line('};')
  763. for target_name in self.build.targets:
  764. listid = self.buildconflistmap[target_name]
  765. self.write_line('%s /* Build configuration list for PBXNativeTarget "%s" */ = {' % (listid, target_name))
  766. self.indent_level += 1
  767. self.write_line('isa = XCConfigurationList;')
  768. self.write_line('buildConfigurations = (')
  769. self.indent_level += 1
  770. typestr = 'debug'
  771. idval = self.buildconfmap[target_name][typestr]
  772. self.write_line('%s /* %s */,' % (idval, typestr))
  773. self.indent_level -= 1
  774. self.write_line(');')
  775. self.write_line('defaultConfigurationIsVisible = 0;')
  776. self.write_line('defaultConfigurationName = "%s";' % typestr)
  777. self.indent_level -= 1
  778. self.write_line('};')
  779. self.ofile.write('/* End XCConfigurationList section */\n')
  780. def generate_prefix(self):
  781. self.ofile.write('// !$*UTF8*$!\n{\n')
  782. self.indent_level += 1
  783. self.write_line('archiveVersion = 1;\n')
  784. self.write_line('classes = {\n')
  785. self.write_line('};\n')
  786. self.write_line('objectVersion = 46;\n')
  787. self.write_line('objects = {\n')
  788. self.indent_level += 1
  789. def generate_suffix(self):
  790. self.indent_level -= 1
  791. self.write_line('};\n')
  792. self.write_line('rootObject = ' + self.project_uid + ';')
  793. self.indent_level -= 1
  794. self.write_line('}\n')