123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727 |
- #! /usr/bin/env python
- # encoding: utf-8
- # XCode 3/XCode 4/XCode 6/Xcode 7 generator for Waf
- # Based on work by Nicolas Mercier 2011
- # Extended by Simon Warg 2015, https://github.com/mimon
- # XCode project file format based on http://www.monobjc.net/xcode-project-file-format.html
- """
- See playground/xcode6/ for usage examples.
- """
- from waflib import Context, TaskGen, Build, Utils, Errors, Logs
- import os, sys
- # FIXME too few extensions
- XCODE_EXTS = ['.c', '.cpp', '.m', '.mm']
- HEADERS_GLOB = '**/(*.h|*.hpp|*.H|*.inl)'
- MAP_EXT = {
- '': "folder",
- '.h' : "sourcecode.c.h",
- '.hh': "sourcecode.cpp.h",
- '.inl': "sourcecode.cpp.h",
- '.hpp': "sourcecode.cpp.h",
- '.c': "sourcecode.c.c",
- '.m': "sourcecode.c.objc",
- '.mm': "sourcecode.cpp.objcpp",
- '.cc': "sourcecode.cpp.cpp",
- '.cpp': "sourcecode.cpp.cpp",
- '.C': "sourcecode.cpp.cpp",
- '.cxx': "sourcecode.cpp.cpp",
- '.c++': "sourcecode.cpp.cpp",
- '.l': "sourcecode.lex", # luthor
- '.ll': "sourcecode.lex",
- '.y': "sourcecode.yacc",
- '.yy': "sourcecode.yacc",
- '.plist': "text.plist.xml",
- ".nib": "wrapper.nib",
- ".xib": "text.xib",
- }
- # Used in PBXNativeTarget elements
- PRODUCT_TYPE_APPLICATION = 'com.apple.product-type.application'
- PRODUCT_TYPE_FRAMEWORK = 'com.apple.product-type.framework'
- PRODUCT_TYPE_EXECUTABLE = 'com.apple.product-type.tool'
- PRODUCT_TYPE_LIB_STATIC = 'com.apple.product-type.library.static'
- PRODUCT_TYPE_LIB_DYNAMIC = 'com.apple.product-type.library.dynamic'
- PRODUCT_TYPE_EXTENSION = 'com.apple.product-type.kernel-extension'
- PRODUCT_TYPE_IOKIT = 'com.apple.product-type.kernel-extension.iokit'
- # Used in PBXFileReference elements
- FILE_TYPE_APPLICATION = 'wrapper.cfbundle'
- FILE_TYPE_FRAMEWORK = 'wrapper.framework'
- FILE_TYPE_LIB_DYNAMIC = 'compiled.mach-o.dylib'
- FILE_TYPE_LIB_STATIC = 'archive.ar'
- FILE_TYPE_EXECUTABLE = 'compiled.mach-o.executable'
- # Tuple packs of the above
- TARGET_TYPE_FRAMEWORK = (PRODUCT_TYPE_FRAMEWORK, FILE_TYPE_FRAMEWORK, '.framework')
- TARGET_TYPE_APPLICATION = (PRODUCT_TYPE_APPLICATION, FILE_TYPE_APPLICATION, '.app')
- TARGET_TYPE_DYNAMIC_LIB = (PRODUCT_TYPE_LIB_DYNAMIC, FILE_TYPE_LIB_DYNAMIC, '.dylib')
- TARGET_TYPE_STATIC_LIB = (PRODUCT_TYPE_LIB_STATIC, FILE_TYPE_LIB_STATIC, '.a')
- TARGET_TYPE_EXECUTABLE = (PRODUCT_TYPE_EXECUTABLE, FILE_TYPE_EXECUTABLE, '')
- # Maps target type string to its data
- TARGET_TYPES = {
- 'framework': TARGET_TYPE_FRAMEWORK,
- 'app': TARGET_TYPE_APPLICATION,
- 'dylib': TARGET_TYPE_DYNAMIC_LIB,
- 'stlib': TARGET_TYPE_STATIC_LIB,
- 'exe' :TARGET_TYPE_EXECUTABLE,
- }
- def delete_invalid_values(dct):
- """ Deletes entries that are dictionaries or sets """
- for k, v in list(dct.items()):
- if isinstance(v, dict) or isinstance(v, set):
- del dct[k]
- return dct
- """
- Configuration of the global project settings. Sets an environment variable 'PROJ_CONFIGURATION'
- which is a dictionary of configuration name and buildsettings pair.
- E.g.:
- env.PROJ_CONFIGURATION = {
- 'Debug': {
- 'ARCHS': 'x86',
- ...
- }
- 'Release': {
- 'ARCHS' x86_64'
- ...
- }
- }
- The user can define a completely customized dictionary in configure() stage. Otherwise a default Debug/Release will be created
- based on env variable
- """
- def configure(self):
- if not self.env.PROJ_CONFIGURATION:
- 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")
- # Check for any added config files added by the tool 'c_config'.
- if 'cfg_files' in self.env:
- self.env.INCLUDES = Utils.to_list(self.env.INCLUDES) + [os.path.abspath(os.path.dirname(f)) for f in self.env.cfg_files]
- # Create default project configuration?
- if 'PROJ_CONFIGURATION' not in self.env:
- defaults = delete_invalid_values(self.env.get_merged_dict())
- self.env.PROJ_CONFIGURATION = {
- "Debug": defaults,
- "Release": defaults,
- }
- # Some build settings are required to be present by XCode. We will supply default values
- # if user hasn't defined any.
- defaults_required = [('PRODUCT_NAME', '$(TARGET_NAME)')]
- for cfgname,settings in self.env.PROJ_CONFIGURATION.items():
- for default_var, default_val in defaults_required:
- if default_var not in settings:
- settings[default_var] = default_val
- # Error check customization
- if not isinstance(self.env.PROJ_CONFIGURATION, dict):
- 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.")
- part1 = 0
- part2 = 10000
- part3 = 0
- id = 562000999
- def newid():
- global id
- id += 1
- return "%04X%04X%04X%012d" % (0, 10000, 0, id)
- """
- Represents a tree node in the XCode project plist file format.
- When written to a file, all attributes of XCodeNode are stringified together with
- its value. However, attributes starting with an underscore _ are ignored
- during that process and allows you to store arbitray values that are not supposed
- to be written out.
- """
- class XCodeNode(object):
- def __init__(self):
- self._id = newid()
- self._been_written = False
- def tostring(self, value):
- if isinstance(value, dict):
- result = "{\n"
- for k,v in value.items():
- result = result + "\t\t\t%s = %s;\n" % (k, self.tostring(v))
- result = result + "\t\t}"
- return result
- elif isinstance(value, str):
- return "\"%s\"" % value
- elif isinstance(value, list):
- result = "(\n"
- for i in value:
- result = result + "\t\t\t%s,\n" % self.tostring(i)
- result = result + "\t\t)"
- return result
- elif isinstance(value, XCodeNode):
- return value._id
- else:
- return str(value)
- def write_recursive(self, value, file):
- if isinstance(value, dict):
- for k,v in value.items():
- self.write_recursive(v, file)
- elif isinstance(value, list):
- for i in value:
- self.write_recursive(i, file)
- elif isinstance(value, XCodeNode):
- value.write(file)
- def write(self, file):
- if not self._been_written:
- self._been_written = True
- for attribute,value in self.__dict__.items():
- if attribute[0] != '_':
- self.write_recursive(value, file)
- w = file.write
- w("\t%s = {\n" % self._id)
- w("\t\tisa = %s;\n" % self.__class__.__name__)
- for attribute,value in self.__dict__.items():
- if attribute[0] != '_':
- w("\t\t%s = %s;\n" % (attribute, self.tostring(value)))
- w("\t};\n\n")
- # Configurations
- class XCBuildConfiguration(XCodeNode):
- def __init__(self, name, settings = {}, env=None):
- XCodeNode.__init__(self)
- self.baseConfigurationReference = ""
- self.buildSettings = settings
- self.name = name
- if env and env.ARCH:
- settings['ARCHS'] = " ".join(env.ARCH)
- class XCConfigurationList(XCodeNode):
- def __init__(self, configlst):
- """ :param configlst: list of XCConfigurationList """
- XCodeNode.__init__(self)
- self.buildConfigurations = configlst
- self.defaultConfigurationIsVisible = 0
- self.defaultConfigurationName = configlst and configlst[0].name or ""
- # Group/Files
- class PBXFileReference(XCodeNode):
- def __init__(self, name, path, filetype = '', sourcetree = "SOURCE_ROOT"):
- XCodeNode.__init__(self)
- self.fileEncoding = 4
- if not filetype:
- _, ext = os.path.splitext(name)
- filetype = MAP_EXT.get(ext, 'text')
- self.lastKnownFileType = filetype
- self.explicitFileType = filetype
- self.name = name
- self.path = path
- self.sourceTree = sourcetree
- def __hash__(self):
- return (self.path+self.name).__hash__()
- def __eq__(self, other):
- return (self.path, self.name) == (other.path, other.name)
- class PBXBuildFile(XCodeNode):
- """ This element indicate a file reference that is used in a PBXBuildPhase (either as an include or resource). """
- def __init__(self, fileRef, settings={}):
- XCodeNode.__init__(self)
- # fileRef is a reference to a PBXFileReference object
- self.fileRef = fileRef
- # A map of key/value pairs for additionnal settings.
- self.settings = settings
- def __hash__(self):
- return (self.fileRef).__hash__()
- def __eq__(self, other):
- return self.fileRef == other.fileRef
- class PBXGroup(XCodeNode):
- def __init__(self, name, sourcetree = 'SOURCE_TREE'):
- XCodeNode.__init__(self)
- self.children = []
- self.name = name
- self.sourceTree = sourcetree
- # Maintain a lookup table for all PBXFileReferences
- # that are contained in this group.
- self._filerefs = {}
- def add(self, sources):
- """
- Add a list of PBXFileReferences to this group
- :param sources: list of PBXFileReferences objects
- """
- self._filerefs.update(dict(zip(sources, sources)))
- self.children.extend(sources)
- def get_sub_groups(self):
- """
- Returns all child PBXGroup objects contained in this group
- """
- return list(filter(lambda x: isinstance(x, PBXGroup), self.children))
- def find_fileref(self, fileref):
- """
- Recursively search this group for an existing PBXFileReference. Returns None
- if none were found.
- 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.
- If it isn't, the consequence is that certain UI features like 'Reveal in Finder'
- stops working.
- """
- if fileref in self._filerefs:
- return self._filerefs[fileref]
- elif self.children:
- for childgroup in self.get_sub_groups():
- f = childgroup.find_fileref(fileref)
- if f:
- return f
- return None
- class PBXContainerItemProxy(XCodeNode):
- """ This is the element for to decorate a target item. """
- def __init__(self, containerPortal, remoteGlobalIDString, remoteInfo='', proxyType=1):
- XCodeNode.__init__(self)
- self.containerPortal = containerPortal # PBXProject
- self.remoteGlobalIDString = remoteGlobalIDString # PBXNativeTarget
- self.remoteInfo = remoteInfo # Target name
- self.proxyType = proxyType
- class PBXTargetDependency(XCodeNode):
- """ This is the element for referencing other target through content proxies. """
- def __init__(self, native_target, proxy):
- XCodeNode.__init__(self)
- self.target = native_target
- self.targetProxy = proxy
- class PBXFrameworksBuildPhase(XCodeNode):
- """ This is the element for the framework link build phase, i.e. linking to frameworks """
- def __init__(self, pbxbuildfiles):
- XCodeNode.__init__(self)
- self.buildActionMask = 2147483647
- self.runOnlyForDeploymentPostprocessing = 0
- self.files = pbxbuildfiles #List of PBXBuildFile (.o, .framework, .dylib)
- class PBXHeadersBuildPhase(XCodeNode):
- """ This is the element for adding header files to be packaged into the .framework """
- def __init__(self, pbxbuildfiles):
- XCodeNode.__init__(self)
- self.buildActionMask = 2147483647
- self.runOnlyForDeploymentPostprocessing = 0
- self.files = pbxbuildfiles #List of PBXBuildFile (.o, .framework, .dylib)
- class PBXCopyFilesBuildPhase(XCodeNode):
- """
- Represents the PBXCopyFilesBuildPhase section. PBXBuildFile
- can be added to this node to copy files after build is done.
- """
- def __init__(self, pbxbuildfiles, dstpath, dstSubpathSpec=0, *args, **kwargs):
- XCodeNode.__init__(self)
- self.files = pbxbuildfiles
- self.dstPath = dstpath
- self.dstSubfolderSpec = dstSubpathSpec
- class PBXSourcesBuildPhase(XCodeNode):
- """ Represents the 'Compile Sources' build phase in a Xcode target """
- def __init__(self, buildfiles):
- XCodeNode.__init__(self)
- self.files = buildfiles # List of PBXBuildFile objects
- class PBXLegacyTarget(XCodeNode):
- def __init__(self, action, target=''):
- XCodeNode.__init__(self)
- self.buildConfigurationList = XCConfigurationList([XCBuildConfiguration('waf', {})])
- if not target:
- self.buildArgumentsString = "%s %s" % (sys.argv[0], action)
- else:
- self.buildArgumentsString = "%s %s --targets=%s" % (sys.argv[0], action, target)
- self.buildPhases = []
- self.buildToolPath = sys.executable
- self.buildWorkingDirectory = ""
- self.dependencies = []
- self.name = target or action
- self.productName = target or action
- self.passBuildSettingsInEnvironment = 0
- class PBXShellScriptBuildPhase(XCodeNode):
- def __init__(self, action, target):
- XCodeNode.__init__(self)
- self.buildActionMask = 2147483647
- self.files = []
- self.inputPaths = []
- self.outputPaths = []
- self.runOnlyForDeploymentPostProcessing = 0
- self.shellPath = "/bin/sh"
- self.shellScript = "%s %s %s --targets=%s" % (sys.executable, sys.argv[0], action, target)
- class PBXNativeTarget(XCodeNode):
- """ Represents a target in XCode, e.g. App, DyLib, Framework etc. """
- def __init__(self, target, node, target_type=TARGET_TYPE_APPLICATION, configlist=[], buildphases=[]):
- XCodeNode.__init__(self)
- product_type = target_type[0]
- file_type = target_type[1]
- self.buildConfigurationList = XCConfigurationList(configlist)
- self.buildPhases = buildphases
- self.buildRules = []
- self.dependencies = []
- self.name = target
- self.productName = target
- self.productType = product_type # See TARGET_TYPE_ tuples constants
- self.productReference = PBXFileReference(node.name, node.abspath(), file_type, '')
- def add_configuration(self, cf):
- """ :type cf: XCBuildConfiguration """
- self.buildConfigurationList.buildConfigurations.append(cf)
- def add_build_phase(self, phase):
- # Some build phase types may appear only once. If a phase type already exists, then merge them.
- if ( (phase.__class__ == PBXFrameworksBuildPhase)
- or (phase.__class__ == PBXSourcesBuildPhase) ):
- for b in self.buildPhases:
- if b.__class__ == phase.__class__:
- b.files.extend(phase.files)
- return
- self.buildPhases.append(phase)
- def add_dependency(self, depnd):
- self.dependencies.append(depnd)
- # Root project object
- class PBXProject(XCodeNode):
- def __init__(self, name, version, env):
- XCodeNode.__init__(self)
- if not isinstance(env.PROJ_CONFIGURATION, dict):
- 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() ?")
- # Retrieve project configuration
- configurations = []
- for config_name, settings in env.PROJ_CONFIGURATION.items():
- cf = XCBuildConfiguration(config_name, settings)
- configurations.append(cf)
- self.buildConfigurationList = XCConfigurationList(configurations)
- self.compatibilityVersion = version[0]
- self.hasScannedForEncodings = 1
- self.mainGroup = PBXGroup(name)
- self.projectRoot = ""
- self.projectDirPath = ""
- self.targets = []
- self._objectVersion = version[1]
- def create_target_dependency(self, target, name):
- """ : param target : PXBNativeTarget """
- proxy = PBXContainerItemProxy(self, target, name)
- dependecy = PBXTargetDependency(target, proxy)
- return dependecy
- def write(self, file):
- # Make sure this is written only once
- if self._been_written:
- return
- w = file.write
- w("// !$*UTF8*$!\n")
- w("{\n")
- w("\tarchiveVersion = 1;\n")
- w("\tclasses = {\n")
- w("\t};\n")
- w("\tobjectVersion = %d;\n" % self._objectVersion)
- w("\tobjects = {\n\n")
- XCodeNode.write(self, file)
- w("\t};\n")
- w("\trootObject = %s;\n" % self._id)
- w("}\n")
- def add_target(self, target):
- self.targets.append(target)
- def get_target(self, name):
- """ Get a reference to PBXNativeTarget if it exists """
- for t in self.targets:
- if t.name == name:
- return t
- return None
- @TaskGen.feature('c', 'cxx')
- @TaskGen.after('propagate_uselib_vars', 'apply_incpaths')
- def process_xcode(self):
- bld = self.bld
- try:
- p = bld.project
- except AttributeError:
- return
- if not hasattr(self, 'target_type'):
- return
- products_group = bld.products_group
- target_group = PBXGroup(self.name)
- p.mainGroup.children.append(target_group)
- # Determine what type to build - framework, app bundle etc.
- target_type = getattr(self, 'target_type', 'app')
- if target_type not in TARGET_TYPES:
- raise Errors.WafError("Target type '%s' does not exists. Available options are '%s'. In target '%s'" % (target_type, "', '".join(TARGET_TYPES.keys()), self.name))
- else:
- target_type = TARGET_TYPES[target_type]
- file_ext = target_type[2]
- # Create the output node
- target_node = self.path.find_or_declare(self.name+file_ext)
- target = PBXNativeTarget(self.name, target_node, target_type, [], [])
- products_group.children.append(target.productReference)
- # Pull source files from the 'source' attribute and assign them to a UI group.
- # Use a default UI group named 'Source' unless the user
- # provides a 'group_files' dictionary to customize the UI grouping.
- sources = getattr(self, 'source', [])
- if hasattr(self, 'group_files'):
- group_files = getattr(self, 'group_files', [])
- for grpname,files in group_files.items():
- group = bld.create_group(grpname, files)
- target_group.children.append(group)
- else:
- group = bld.create_group('Source', sources)
- target_group.children.append(group)
- # Create a PBXFileReference for each source file.
- # If the source file already exists as a PBXFileReference in any of the UI groups, then
- # reuse that PBXFileReference object (XCode does not like it if we don't reuse)
- for idx, path in enumerate(sources):
- fileref = PBXFileReference(path.name, path.abspath())
- existing_fileref = target_group.find_fileref(fileref)
- if existing_fileref:
- sources[idx] = existing_fileref
- else:
- sources[idx] = fileref
- # If the 'source' attribute contains any file extension that XCode can't work with,
- # then remove it. The allowed file extensions are defined in XCODE_EXTS.
- is_valid_file_extension = lambda file: os.path.splitext(file.path)[1] in XCODE_EXTS
- sources = list(filter(is_valid_file_extension, sources))
- buildfiles = [bld.unique_buildfile(PBXBuildFile(x)) for x in sources]
- target.add_build_phase(PBXSourcesBuildPhase(buildfiles))
- # Check if any framework to link against is some other target we've made
- libs = getattr(self, 'tmp_use_seen', [])
- for lib in libs:
- use_target = p.get_target(lib)
- if use_target:
- # Create an XCode dependency so that XCode knows to build the other target before this target
- dependency = p.create_target_dependency(use_target, use_target.name)
- target.add_dependency(dependency)
- buildphase = PBXFrameworksBuildPhase([PBXBuildFile(use_target.productReference)])
- target.add_build_phase(buildphase)
- if lib in self.env.LIB:
- self.env.LIB = list(filter(lambda x: x != lib, self.env.LIB))
- # If 'export_headers' is present, add files to the Headers build phase in xcode.
- # These are files that'll get packed into the Framework for instance.
- exp_hdrs = getattr(self, 'export_headers', [])
- hdrs = bld.as_nodes(Utils.to_list(exp_hdrs))
- files = [p.mainGroup.find_fileref(PBXFileReference(n.name, n.abspath())) for n in hdrs]
- files = [PBXBuildFile(f, {'ATTRIBUTES': ('Public',)}) for f in files]
- buildphase = PBXHeadersBuildPhase(files)
- target.add_build_phase(buildphase)
- # Merge frameworks and libs into one list, and prefix the frameworks
- frameworks = Utils.to_list(self.env.FRAMEWORK)
- frameworks = ' '.join(['-framework %s' % (f.split('.framework')[0]) for f in frameworks])
- libs = Utils.to_list(self.env.STLIB) + Utils.to_list(self.env.LIB)
- libs = ' '.join(bld.env['STLIB_ST'] % t for t in libs)
- # Override target specific build settings
- bldsettings = {
- 'HEADER_SEARCH_PATHS': ['$(inherited)'] + self.env['INCPATHS'],
- 'LIBRARY_SEARCH_PATHS': ['$(inherited)'] + Utils.to_list(self.env.LIBPATH) + Utils.to_list(self.env.STLIBPATH) + Utils.to_list(self.env.LIBDIR) ,
- 'FRAMEWORK_SEARCH_PATHS': ['$(inherited)'] + Utils.to_list(self.env.FRAMEWORKPATH),
- 'OTHER_LDFLAGS': libs + ' ' + frameworks,
- 'OTHER_LIBTOOLFLAGS': bld.env['LINKFLAGS'],
- 'OTHER_CPLUSPLUSFLAGS': Utils.to_list(self.env['CXXFLAGS']),
- 'OTHER_CFLAGS': Utils.to_list(self.env['CFLAGS']),
- 'INSTALL_PATH': []
- }
- # Install path
- installpaths = Utils.to_list(getattr(self, 'install', []))
- prodbuildfile = PBXBuildFile(target.productReference)
- for instpath in installpaths:
- bldsettings['INSTALL_PATH'].append(instpath)
- target.add_build_phase(PBXCopyFilesBuildPhase([prodbuildfile], instpath))
- if not bldsettings['INSTALL_PATH']:
- del bldsettings['INSTALL_PATH']
- # Create build settings which can override the project settings. Defaults to none if user
- # did not pass argument. This will be filled up with target specific
- # search paths, libs to link etc.
- settings = getattr(self, 'settings', {})
- # The keys represents different build configuration, e.g. Debug, Release and so on..
- # Insert our generated build settings to all configuration names
- keys = set(settings.keys() + bld.env.PROJ_CONFIGURATION.keys())
- for k in keys:
- if k in settings:
- settings[k].update(bldsettings)
- else:
- settings[k] = bldsettings
- for k,v in settings.items():
- target.add_configuration(XCBuildConfiguration(k, v))
- p.add_target(target)
- class xcode(Build.BuildContext):
- cmd = 'xcode6'
- fun = 'build'
- def as_nodes(self, files):
- """ Returns a list of waflib.Nodes from a list of string of file paths """
- nodes = []
- for x in files:
- if not isinstance(x, str):
- d = x
- else:
- d = self.srcnode.find_node(x)
- if not d:
- raise Errors.WafError('File \'%s\' was not found' % x)
- nodes.append(d)
- return nodes
- def create_group(self, name, files):
- """
- Returns a new PBXGroup containing the files (paths) passed in the files arg
- :type files: string
- """
- group = PBXGroup(name)
- """
- Do not use unique file reference here, since XCode seem to allow only one file reference
- to be referenced by a group.
- """
- files_ = []
- for d in self.as_nodes(Utils.to_list(files)):
- fileref = PBXFileReference(d.name, d.abspath())
- files_.append(fileref)
- group.add(files_)
- return group
- def unique_buildfile(self, buildfile):
- """
- Returns a unique buildfile, possibly an existing one.
- Use this after you've constructed a PBXBuildFile to make sure there is
- only one PBXBuildFile for the same file in the same project.
- """
- try:
- build_files = self.build_files
- except AttributeError:
- build_files = self.build_files = {}
- if buildfile not in build_files:
- build_files[buildfile] = buildfile
- return build_files[buildfile]
- def execute(self):
- """
- Entry point
- """
- self.restore()
- if not self.all_envs:
- self.load_envs()
- self.recurse([self.run_dir])
- appname = getattr(Context.g_module, Context.APPNAME, os.path.basename(self.srcnode.abspath()))
- p = PBXProject(appname, ('Xcode 3.2', 46), self.env)
- # If we don't create a Products group, then
- # XCode will create one, which entails that
- # we'll start to see duplicate files in the UI
- # for some reason.
- products_group = PBXGroup('Products')
- p.mainGroup.children.append(products_group)
- self.project = p
- self.products_group = products_group
- # post all task generators
- # the process_xcode method above will be called for each target
- if self.targets and self.targets != '*':
- (self._min_grp, self._exact_tg) = self.get_targets()
- self.current_group = 0
- while self.current_group < len(self.groups):
- self.post_group()
- self.current_group += 1
- node = self.bldnode.make_node('%s.xcodeproj' % appname)
- node.mkdir()
- node = node.make_node('project.pbxproj')
- with open(node.abspath(), 'w') as f:
- p.write(f)
- Logs.pprint('GREEN', 'Wrote %r' % node.abspath())
- def bind_fun(tgtype):
- def fun(self, *k, **kw):
- tgtype = fun.__name__
- if tgtype == 'shlib' or tgtype == 'dylib':
- features = 'cxx cxxshlib'
- tgtype = 'dylib'
- elif tgtype == 'framework':
- features = 'cxx cxxshlib'
- tgtype = 'framework'
- elif tgtype == 'program':
- features = 'cxx cxxprogram'
- tgtype = 'exe'
- elif tgtype == 'app':
- features = 'cxx cxxprogram'
- tgtype = 'app'
- elif tgtype == 'stlib':
- features = 'cxx cxxstlib'
- tgtype = 'stlib'
- lst = kw['features'] = Utils.to_list(kw.get('features', []))
- for x in features.split():
- if not x in kw['features']:
- lst.append(x)
- kw['target_type'] = tgtype
- return self(*k, **kw)
- fun.__name__ = tgtype
- setattr(Build.BuildContext, tgtype, fun)
- return fun
- for xx in 'app framework dylib shlib stlib program'.split():
- bind_fun(xx)
|