ctdb-scripts: Support storing statd-callout state in cluster filesystem
[samba4-gss.git] / third_party / waf / waflib / extras / xcode6.py
blobc5b309120c93208b59e233aa87e5e249c9cbe1b0
1 #! /usr/bin/env python
2 # encoding: utf-8
3 # XCode 3/XCode 4/XCode 6/Xcode 7 generator for Waf
4 # Based on work by Nicolas Mercier 2011
5 # Extended by Simon Warg 2015, https://github.com/mimon
6 # XCode project file format based on http://www.monobjc.net/xcode-project-file-format.html
8 """
9 See playground/xcode6/ for usage examples.
11 """
13 from waflib import Context, TaskGen, Build, Utils, Errors, Logs
14 import os, sys
16 # FIXME too few extensions
17 XCODE_EXTS = ['.c', '.cpp', '.m', '.mm']
19 HEADERS_GLOB = '**/(*.h|*.hpp|*.H|*.inl)'
21 MAP_EXT = {
22 '': "folder",
23 '.h' : "sourcecode.c.h",
25 '.hh': "sourcecode.cpp.h",
26 '.inl': "sourcecode.cpp.h",
27 '.hpp': "sourcecode.cpp.h",
29 '.c': "sourcecode.c.c",
31 '.m': "sourcecode.c.objc",
33 '.mm': "sourcecode.cpp.objcpp",
35 '.cc': "sourcecode.cpp.cpp",
37 '.cpp': "sourcecode.cpp.cpp",
38 '.C': "sourcecode.cpp.cpp",
39 '.cxx': "sourcecode.cpp.cpp",
40 '.c++': "sourcecode.cpp.cpp",
42 '.l': "sourcecode.lex", # luthor
43 '.ll': "sourcecode.lex",
45 '.y': "sourcecode.yacc",
46 '.yy': "sourcecode.yacc",
48 '.plist': "text.plist.xml",
49 ".nib": "wrapper.nib",
50 ".xib": "text.xib",
53 # Used in PBXNativeTarget elements
54 PRODUCT_TYPE_APPLICATION = 'com.apple.product-type.application'
55 PRODUCT_TYPE_FRAMEWORK = 'com.apple.product-type.framework'
56 PRODUCT_TYPE_EXECUTABLE = 'com.apple.product-type.tool'
57 PRODUCT_TYPE_LIB_STATIC = 'com.apple.product-type.library.static'
58 PRODUCT_TYPE_LIB_DYNAMIC = 'com.apple.product-type.library.dynamic'
59 PRODUCT_TYPE_EXTENSION = 'com.apple.product-type.kernel-extension'
60 PRODUCT_TYPE_IOKIT = 'com.apple.product-type.kernel-extension.iokit'
62 # Used in PBXFileReference elements
63 FILE_TYPE_APPLICATION = 'wrapper.cfbundle'
64 FILE_TYPE_FRAMEWORK = 'wrapper.framework'
65 FILE_TYPE_LIB_DYNAMIC = 'compiled.mach-o.dylib'
66 FILE_TYPE_LIB_STATIC = 'archive.ar'
67 FILE_TYPE_EXECUTABLE = 'compiled.mach-o.executable'
69 # Tuple packs of the above
70 TARGET_TYPE_FRAMEWORK = (PRODUCT_TYPE_FRAMEWORK, FILE_TYPE_FRAMEWORK, '.framework')
71 TARGET_TYPE_APPLICATION = (PRODUCT_TYPE_APPLICATION, FILE_TYPE_APPLICATION, '.app')
72 TARGET_TYPE_DYNAMIC_LIB = (PRODUCT_TYPE_LIB_DYNAMIC, FILE_TYPE_LIB_DYNAMIC, '.dylib')
73 TARGET_TYPE_STATIC_LIB = (PRODUCT_TYPE_LIB_STATIC, FILE_TYPE_LIB_STATIC, '.a')
74 TARGET_TYPE_EXECUTABLE = (PRODUCT_TYPE_EXECUTABLE, FILE_TYPE_EXECUTABLE, '')
76 # Maps target type string to its data
77 TARGET_TYPES = {
78 'framework': TARGET_TYPE_FRAMEWORK,
79 'app': TARGET_TYPE_APPLICATION,
80 'dylib': TARGET_TYPE_DYNAMIC_LIB,
81 'stlib': TARGET_TYPE_STATIC_LIB,
82 'exe' :TARGET_TYPE_EXECUTABLE,
85 def delete_invalid_values(dct):
86 """ Deletes entries that are dictionaries or sets """
87 for k, v in list(dct.items()):
88 if isinstance(v, dict) or isinstance(v, set):
89 del dct[k]
90 return dct
92 """
93 Configuration of the global project settings. Sets an environment variable 'PROJ_CONFIGURATION'
94 which is a dictionary of configuration name and buildsettings pair.
95 E.g.:
96 env.PROJ_CONFIGURATION = {
97 'Debug': {
98 'ARCHS': 'x86',
99 ...
101 'Release': {
102 'ARCHS': x86_64'
106 The user can define a completely customized dictionary in configure() stage. Otherwise a default Debug/Release will be created
107 based on env variable
109 def configure(self):
110 if not self.env.PROJ_CONFIGURATION:
111 self.to_log("A default project configuration was created since no custom one was given in the configure(conf) stage. Define your custom project settings by adding PROJ_CONFIGURATION to env. The env.PROJ_CONFIGURATION must be a dictionary with at least one key, where each key is the configuration name, and the value is a dictionary of key/value settings.\n")
113 # Check for any added config files added by the tool 'c_config'.
114 if 'cfg_files' in self.env:
115 self.env.INCLUDES = Utils.to_list(self.env.INCLUDES) + [os.path.abspath(os.path.dirname(f)) for f in self.env.cfg_files]
117 # Create default project configuration?
118 if 'PROJ_CONFIGURATION' not in self.env:
119 defaults = delete_invalid_values(self.env.get_merged_dict())
120 self.env.PROJ_CONFIGURATION = {
121 "Debug": defaults,
122 "Release": defaults,
125 # Some build settings are required to be present by XCode. We will supply default values
126 # if user hasn't defined any.
127 defaults_required = [('PRODUCT_NAME', '$(TARGET_NAME)')]
128 for cfgname,settings in self.env.PROJ_CONFIGURATION.items():
129 for default_var, default_val in defaults_required:
130 if default_var not in settings:
131 settings[default_var] = default_val
133 # Error check customization
134 if not isinstance(self.env.PROJ_CONFIGURATION, dict):
135 raise Errors.ConfigurationError("The env.PROJ_CONFIGURATION must be a dictionary with at least one key, where each key is the configuration name, and the value is a dictionary of key/value settings.")
137 part1 = 0
138 part2 = 10000
139 part3 = 0
140 id = 562000999
141 def newid():
142 global id
143 id += 1
144 return "%04X%04X%04X%012d" % (0, 10000, 0, id)
147 Represents a tree node in the XCode project plist file format.
148 When written to a file, all attributes of XCodeNode are stringified together with
149 its value. However, attributes starting with an underscore _ are ignored
150 during that process and allows you to store arbitrary values that are not supposed
151 to be written out.
153 class XCodeNode(object):
154 def __init__(self):
155 self._id = newid()
156 self._been_written = False
158 def tostring(self, value):
159 if isinstance(value, dict):
160 result = "{\n"
161 for k,v in value.items():
162 result = result + "\t\t\t%s = %s;\n" % (k, self.tostring(v))
163 result = result + "\t\t}"
164 return result
165 elif isinstance(value, str):
166 return '"%s"' % value.replace('"', '\\\\\\"')
167 elif isinstance(value, list):
168 result = "(\n"
169 for i in value:
170 result = result + "\t\t\t\t%s,\n" % self.tostring(i)
171 result = result + "\t\t\t)"
172 return result
173 elif isinstance(value, XCodeNode):
174 return value._id
175 else:
176 return str(value)
178 def write_recursive(self, value, file):
179 if isinstance(value, dict):
180 for k,v in value.items():
181 self.write_recursive(v, file)
182 elif isinstance(value, list):
183 for i in value:
184 self.write_recursive(i, file)
185 elif isinstance(value, XCodeNode):
186 value.write(file)
188 def write(self, file):
189 if not self._been_written:
190 self._been_written = True
191 for attribute,value in self.__dict__.items():
192 if attribute[0] != '_':
193 self.write_recursive(value, file)
194 w = file.write
195 w("\t%s = {\n" % self._id)
196 w("\t\tisa = %s;\n" % self.__class__.__name__)
197 for attribute,value in self.__dict__.items():
198 if attribute[0] != '_':
199 w("\t\t%s = %s;\n" % (attribute, self.tostring(value)))
200 w("\t};\n\n")
202 # Configurations
203 class XCBuildConfiguration(XCodeNode):
204 def __init__(self, name, settings = {}, env=None):
205 XCodeNode.__init__(self)
206 self.baseConfigurationReference = ""
207 self.buildSettings = settings
208 self.name = name
209 if env and env.ARCH:
210 settings['ARCHS'] = " ".join(env.ARCH)
213 class XCConfigurationList(XCodeNode):
214 def __init__(self, configlst):
215 """ :param configlst: list of XCConfigurationList """
216 XCodeNode.__init__(self)
217 self.buildConfigurations = configlst
218 self.defaultConfigurationIsVisible = 0
219 self.defaultConfigurationName = configlst and configlst[0].name or ""
221 # Group/Files
222 class PBXFileReference(XCodeNode):
223 def __init__(self, name, path, filetype = '', sourcetree = "SOURCE_ROOT"):
225 XCodeNode.__init__(self)
226 self.fileEncoding = 4
227 if not filetype:
228 _, ext = os.path.splitext(name)
229 filetype = MAP_EXT.get(ext, 'text')
230 self.lastKnownFileType = filetype
231 self.explicitFileType = filetype
232 self.name = name
233 self.path = path
234 self.sourceTree = sourcetree
236 def __hash__(self):
237 return (self.path+self.name).__hash__()
239 def __eq__(self, other):
240 return (self.path, self.name) == (other.path, other.name)
242 class PBXBuildFile(XCodeNode):
243 """ This element indicate a file reference that is used in a PBXBuildPhase (either as an include or resource). """
244 def __init__(self, fileRef, settings={}):
245 XCodeNode.__init__(self)
247 # fileRef is a reference to a PBXFileReference object
248 self.fileRef = fileRef
250 # A map of key/value pairs for additional settings.
251 self.settings = settings
253 def __hash__(self):
254 return (self.fileRef).__hash__()
256 def __eq__(self, other):
257 return self.fileRef == other.fileRef
259 class PBXGroup(XCodeNode):
260 def __init__(self, name, sourcetree = 'SOURCE_TREE'):
261 XCodeNode.__init__(self)
262 self.children = []
263 self.name = name
264 self.sourceTree = sourcetree
266 # Maintain a lookup table for all PBXFileReferences
267 # that are contained in this group.
268 self._filerefs = {}
270 def add(self, sources):
272 Add a list of PBXFileReferences to this group
274 :param sources: list of PBXFileReferences objects
276 self._filerefs.update(dict(zip(sources, sources)))
277 self.children.extend(sources)
279 def get_sub_groups(self):
281 Returns all child PBXGroup objects contained in this group
283 return list(filter(lambda x: isinstance(x, PBXGroup), self.children))
285 def find_fileref(self, fileref):
287 Recursively search this group for an existing PBXFileReference. Returns None
288 if none were found.
290 The reason you'd want to reuse existing PBXFileReferences from a PBXGroup is that XCode doesn't like PBXFileReferences that aren't part of a PBXGroup hierarchy.
291 If it isn't, the consequence is that certain UI features like 'Reveal in Finder'
292 stops working.
294 if fileref in self._filerefs:
295 return self._filerefs[fileref]
296 elif self.children:
297 for childgroup in self.get_sub_groups():
298 f = childgroup.find_fileref(fileref)
299 if f:
300 return f
301 return None
303 class PBXContainerItemProxy(XCodeNode):
304 """ This is the element for to decorate a target item. """
305 def __init__(self, containerPortal, remoteGlobalIDString, remoteInfo='', proxyType=1):
306 XCodeNode.__init__(self)
307 self.containerPortal = containerPortal # PBXProject
308 self.remoteGlobalIDString = remoteGlobalIDString # PBXNativeTarget
309 self.remoteInfo = remoteInfo # Target name
310 self.proxyType = proxyType
312 class PBXTargetDependency(XCodeNode):
313 """ This is the element for referencing other target through content proxies. """
314 def __init__(self, native_target, proxy):
315 XCodeNode.__init__(self)
316 self.target = native_target
317 self.targetProxy = proxy
319 class PBXFrameworksBuildPhase(XCodeNode):
320 """ This is the element for the framework link build phase, i.e. linking to frameworks """
321 def __init__(self, pbxbuildfiles):
322 XCodeNode.__init__(self)
323 self.buildActionMask = 2147483647
324 self.runOnlyForDeploymentPostprocessing = 0
325 self.files = pbxbuildfiles #List of PBXBuildFile (.o, .framework, .dylib)
327 class PBXHeadersBuildPhase(XCodeNode):
328 """ This is the element for adding header files to be packaged into the .framework """
329 def __init__(self, pbxbuildfiles):
330 XCodeNode.__init__(self)
331 self.buildActionMask = 2147483647
332 self.runOnlyForDeploymentPostprocessing = 0
333 self.files = pbxbuildfiles #List of PBXBuildFile (.o, .framework, .dylib)
335 class PBXCopyFilesBuildPhase(XCodeNode):
337 Represents the PBXCopyFilesBuildPhase section. PBXBuildFile
338 can be added to this node to copy files after build is done.
340 def __init__(self, pbxbuildfiles, dstpath, dstSubpathSpec=0, *args, **kwargs):
341 XCodeNode.__init__(self)
342 self.files = pbxbuildfiles
343 self.dstPath = dstpath
344 self.dstSubfolderSpec = dstSubpathSpec
346 class PBXSourcesBuildPhase(XCodeNode):
347 """ Represents the 'Compile Sources' build phase in a Xcode target """
348 def __init__(self, buildfiles):
349 XCodeNode.__init__(self)
350 self.files = buildfiles # List of PBXBuildFile objects
352 class PBXLegacyTarget(XCodeNode):
353 def __init__(self, action, target=''):
354 XCodeNode.__init__(self)
355 self.buildConfigurationList = XCConfigurationList([XCBuildConfiguration('waf', {})])
356 if not target:
357 self.buildArgumentsString = "%s %s" % (sys.argv[0], action)
358 else:
359 self.buildArgumentsString = "%s %s --targets=%s" % (sys.argv[0], action, target)
360 self.buildPhases = []
361 self.buildToolPath = sys.executable
362 self.buildWorkingDirectory = ""
363 self.dependencies = []
364 self.name = target or action
365 self.productName = target or action
366 self.passBuildSettingsInEnvironment = 0
368 class PBXShellScriptBuildPhase(XCodeNode):
369 def __init__(self, action, target):
370 XCodeNode.__init__(self)
371 self.buildActionMask = 2147483647
372 self.files = []
373 self.inputPaths = []
374 self.outputPaths = []
375 self.runOnlyForDeploymentPostProcessing = 0
376 self.shellPath = "/bin/sh"
377 self.shellScript = "%s %s %s --targets=%s" % (sys.executable, sys.argv[0], action, target)
379 class PBXNativeTarget(XCodeNode):
380 """ Represents a target in XCode, e.g. App, DyLib, Framework etc. """
381 def __init__(self, target, node, target_type=TARGET_TYPE_APPLICATION, configlist=[], buildphases=[]):
382 XCodeNode.__init__(self)
383 product_type = target_type[0]
384 file_type = target_type[1]
386 self.buildConfigurationList = XCConfigurationList(configlist)
387 self.buildPhases = buildphases
388 self.buildRules = []
389 self.dependencies = []
390 self.name = target
391 self.productName = target
392 self.productType = product_type # See TARGET_TYPE_ tuples constants
393 self.productReference = PBXFileReference(node.name, node.abspath(), file_type, '')
395 def add_configuration(self, cf):
396 """ :type cf: XCBuildConfiguration """
397 self.buildConfigurationList.buildConfigurations.append(cf)
399 def add_build_phase(self, phase):
400 # Some build phase types may appear only once. If a phase type already exists, then merge them.
401 if ( (phase.__class__ == PBXFrameworksBuildPhase)
402 or (phase.__class__ == PBXSourcesBuildPhase) ):
403 for b in self.buildPhases:
404 if b.__class__ == phase.__class__:
405 b.files.extend(phase.files)
406 return
407 self.buildPhases.append(phase)
409 def add_dependency(self, depnd):
410 self.dependencies.append(depnd)
412 # Root project object
413 class PBXProject(XCodeNode):
414 def __init__(self, name, version, env):
415 XCodeNode.__init__(self)
417 if not isinstance(env.PROJ_CONFIGURATION, dict):
418 raise Errors.WafError("Error: env.PROJ_CONFIGURATION must be a dictionary. This is done for you if you do not define one yourself. However, did you load the xcode module at the end of your wscript configure() ?")
420 # Retrieve project configuration
421 configurations = []
422 for config_name, settings in env.PROJ_CONFIGURATION.items():
423 cf = XCBuildConfiguration(config_name, settings)
424 configurations.append(cf)
426 self.buildConfigurationList = XCConfigurationList(configurations)
427 self.compatibilityVersion = version[0]
428 self.hasScannedForEncodings = 1
429 self.mainGroup = PBXGroup(name)
430 self.projectRoot = ""
431 self.projectDirPath = ""
432 self.targets = []
433 self._objectVersion = version[1]
435 def create_target_dependency(self, target, name):
436 """ : param target : PXBNativeTarget """
437 proxy = PBXContainerItemProxy(self, target, name)
438 dependency = PBXTargetDependency(target, proxy)
439 return dependency
441 def write(self, file):
443 # Make sure this is written only once
444 if self._been_written:
445 return
447 w = file.write
448 w("// !$*UTF8*$!\n")
449 w("{\n")
450 w("\tarchiveVersion = 1;\n")
451 w("\tclasses = {\n")
452 w("\t};\n")
453 w("\tobjectVersion = %d;\n" % self._objectVersion)
454 w("\tobjects = {\n\n")
456 XCodeNode.write(self, file)
458 w("\t};\n")
459 w("\trootObject = %s;\n" % self._id)
460 w("}\n")
462 def add_target(self, target):
463 self.targets.append(target)
465 def get_target(self, name):
466 """ Get a reference to PBXNativeTarget if it exists """
467 for t in self.targets:
468 if t.name == name:
469 return t
470 return None
472 @TaskGen.feature('c', 'cxx')
473 @TaskGen.after('propagate_uselib_vars', 'apply_incpaths')
474 def process_xcode(self):
475 bld = self.bld
476 try:
477 p = bld.project
478 except AttributeError:
479 return
481 if not hasattr(self, 'target_type'):
482 return
484 products_group = bld.products_group
486 target_group = PBXGroup(self.name)
487 p.mainGroup.children.append(target_group)
489 # Determine what type to build - framework, app bundle etc.
490 target_type = getattr(self, 'target_type', 'app')
491 if target_type not in TARGET_TYPES:
492 raise Errors.WafError("Target type '%s' does not exists. Available options are '%s'. In target '%s'" % (target_type, "', '".join(TARGET_TYPES.keys()), self.name))
493 else:
494 target_type = TARGET_TYPES[target_type]
495 file_ext = target_type[2]
497 # Create the output node
498 target_node = self.path.find_or_declare(self.name+file_ext)
499 target = PBXNativeTarget(self.name, target_node, target_type, [], [])
501 products_group.children.append(target.productReference)
503 # Pull source files from the 'source' attribute and assign them to a UI group.
504 # Use a default UI group named 'Source' unless the user
505 # provides a 'group_files' dictionary to customize the UI grouping.
506 sources = getattr(self, 'source', [])
507 if hasattr(self, 'group_files'):
508 group_files = getattr(self, 'group_files', [])
509 for grpname,files in group_files.items():
510 group = bld.create_group(grpname, files)
511 target_group.children.append(group)
512 else:
513 group = bld.create_group('Source', sources)
514 target_group.children.append(group)
516 # Create a PBXFileReference for each source file.
517 # If the source file already exists as a PBXFileReference in any of the UI groups, then
518 # reuse that PBXFileReference object (XCode does not like it if we don't reuse)
519 for idx, path in enumerate(sources):
520 fileref = PBXFileReference(path.name, path.abspath())
521 existing_fileref = target_group.find_fileref(fileref)
522 if existing_fileref:
523 sources[idx] = existing_fileref
524 else:
525 sources[idx] = fileref
527 # If the 'source' attribute contains any file extension that XCode can't work with,
528 # then remove it. The allowed file extensions are defined in XCODE_EXTS.
529 is_valid_file_extension = lambda file: os.path.splitext(file.path)[1] in XCODE_EXTS
530 sources = list(filter(is_valid_file_extension, sources))
532 buildfiles = [bld.unique_buildfile(PBXBuildFile(x)) for x in sources]
533 target.add_build_phase(PBXSourcesBuildPhase(buildfiles))
535 # Check if any framework to link against is some other target we've made
536 libs = getattr(self, 'tmp_use_seen', [])
537 for lib in libs:
538 use_target = p.get_target(lib)
539 if use_target:
540 # Create an XCode dependency so that XCode knows to build the other target before this target
541 dependency = p.create_target_dependency(use_target, use_target.name)
542 target.add_dependency(dependency)
544 buildphase = PBXFrameworksBuildPhase([PBXBuildFile(use_target.productReference)])
545 target.add_build_phase(buildphase)
546 if lib in self.env.LIB:
547 self.env.LIB = list(filter(lambda x: x != lib, self.env.LIB))
549 # If 'export_headers' is present, add files to the Headers build phase in xcode.
550 # These are files that'll get packed into the Framework for instance.
551 exp_hdrs = getattr(self, 'export_headers', [])
552 hdrs = bld.as_nodes(Utils.to_list(exp_hdrs))
553 files = [p.mainGroup.find_fileref(PBXFileReference(n.name, n.abspath())) for n in hdrs]
554 files = [PBXBuildFile(f, {'ATTRIBUTES': ('Public',)}) for f in files]
555 buildphase = PBXHeadersBuildPhase(files)
556 target.add_build_phase(buildphase)
558 # Merge frameworks and libs into one list, and prefix the frameworks
559 frameworks = Utils.to_list(self.env.FRAMEWORK)
560 frameworks = ' '.join(['-framework %s' % (f.split('.framework')[0]) for f in frameworks])
562 libs = Utils.to_list(self.env.STLIB) + Utils.to_list(self.env.LIB)
563 libs = ' '.join(bld.env['STLIB_ST'] % t for t in libs)
565 # Override target specific build settings
566 bldsettings = {
567 'HEADER_SEARCH_PATHS': ['$(inherited)'] + self.env['INCPATHS'],
568 'LIBRARY_SEARCH_PATHS': ['$(inherited)'] + Utils.to_list(self.env.LIBPATH) + Utils.to_list(self.env.STLIBPATH) + Utils.to_list(self.env.LIBDIR),
569 'FRAMEWORK_SEARCH_PATHS': ['$(inherited)'] + Utils.to_list(self.env.FRAMEWORKPATH),
570 'OTHER_LDFLAGS': libs + ' ' + frameworks + ' ' + ' '.join(bld.env['LINKFLAGS']),
571 'OTHER_CPLUSPLUSFLAGS': Utils.to_list(self.env['CXXFLAGS']),
572 'OTHER_CFLAGS': Utils.to_list(self.env['CFLAGS']),
573 'INSTALL_PATH': [],
574 'GCC_PREPROCESSOR_DEFINITIONS': self.env['DEFINES']
577 # Install path
578 installpaths = Utils.to_list(getattr(self, 'install', []))
579 prodbuildfile = PBXBuildFile(target.productReference)
580 for instpath in installpaths:
581 bldsettings['INSTALL_PATH'].append(instpath)
582 target.add_build_phase(PBXCopyFilesBuildPhase([prodbuildfile], instpath))
584 if not bldsettings['INSTALL_PATH']:
585 del bldsettings['INSTALL_PATH']
587 # Create build settings which can override the project settings. Defaults to none if user
588 # did not pass argument. This will be filled up with target specific
589 # search paths, libs to link etc.
590 settings = getattr(self, 'settings', {})
592 # The keys represents different build configuration, e.g. Debug, Release and so on..
593 # Insert our generated build settings to all configuration names
594 keys = set(settings.keys()) | set(bld.env.PROJ_CONFIGURATION.keys())
595 for k in keys:
596 if k in settings:
597 settings[k].update(bldsettings)
598 else:
599 settings[k] = bldsettings
601 for k,v in settings.items():
602 target.add_configuration(XCBuildConfiguration(k, v))
604 p.add_target(target)
607 class xcode(Build.BuildContext):
608 cmd = 'xcode6'
609 fun = 'build'
611 def as_nodes(self, files):
612 """ Returns a list of waflib.Nodes from a list of string of file paths """
613 nodes = []
614 for x in files:
615 if not isinstance(x, str):
616 d = x
617 else:
618 d = self.srcnode.find_node(x)
619 if not d:
620 raise Errors.WafError('File \'%s\' was not found' % x)
621 nodes.append(d)
622 return nodes
624 def create_group(self, name, files):
626 Returns a new PBXGroup containing the files (paths) passed in the files arg
627 :type files: string
629 group = PBXGroup(name)
631 Do not use unique file reference here, since XCode seem to allow only one file reference
632 to be referenced by a group.
634 files_ = []
635 for d in self.as_nodes(Utils.to_list(files)):
636 fileref = PBXFileReference(d.name, d.abspath())
637 files_.append(fileref)
638 group.add(files_)
639 return group
641 def unique_buildfile(self, buildfile):
643 Returns a unique buildfile, possibly an existing one.
644 Use this after you've constructed a PBXBuildFile to make sure there is
645 only one PBXBuildFile for the same file in the same project.
647 try:
648 build_files = self.build_files
649 except AttributeError:
650 build_files = self.build_files = {}
652 if buildfile not in build_files:
653 build_files[buildfile] = buildfile
654 return build_files[buildfile]
656 def execute(self):
658 Entry point
660 self.restore()
661 if not self.all_envs:
662 self.load_envs()
663 self.recurse([self.run_dir])
665 appname = getattr(Context.g_module, Context.APPNAME, os.path.basename(self.srcnode.abspath()))
667 p = PBXProject(appname, ('Xcode 3.2', 46), self.env)
669 # If we don't create a Products group, then
670 # XCode will create one, which entails that
671 # we'll start to see duplicate files in the UI
672 # for some reason.
673 products_group = PBXGroup('Products')
674 p.mainGroup.children.append(products_group)
676 self.project = p
677 self.products_group = products_group
679 # post all task generators
680 # the process_xcode method above will be called for each target
681 if self.targets and self.targets != '*':
682 (self._min_grp, self._exact_tg) = self.get_targets()
684 self.current_group = 0
685 while self.current_group < len(self.groups):
686 self.post_group()
687 self.current_group += 1
689 node = self.bldnode.make_node('%s.xcodeproj' % appname)
690 node.mkdir()
691 node = node.make_node('project.pbxproj')
692 with open(node.abspath(), 'w') as f:
693 p.write(f)
694 Logs.pprint('GREEN', 'Wrote %r' % node.abspath())
696 def bind_fun(tgtype):
697 def fun(self, *k, **kw):
698 tgtype = fun.__name__
699 if tgtype == 'shlib' or tgtype == 'dylib':
700 features = 'cxx cxxshlib'
701 tgtype = 'dylib'
702 elif tgtype == 'framework':
703 features = 'cxx cxxshlib'
704 tgtype = 'framework'
705 elif tgtype == 'program':
706 features = 'cxx cxxprogram'
707 tgtype = 'exe'
708 elif tgtype == 'app':
709 features = 'cxx cxxprogram'
710 tgtype = 'app'
711 elif tgtype == 'stlib':
712 features = 'cxx cxxstlib'
713 tgtype = 'stlib'
714 lst = kw['features'] = Utils.to_list(kw.get('features', []))
715 for x in features.split():
716 if not x in kw['features']:
717 lst.append(x)
719 kw['target_type'] = tgtype
720 return self(*k, **kw)
721 fun.__name__ = tgtype
722 setattr(Build.BuildContext, tgtype, fun)
723 return fun
725 for xx in 'app framework dylib shlib stlib program'.split():
726 bind_fun(xx)