2015-10-29 11:16:05 +01:00
#! /usr/bin/env python
# encoding: utf-8
# XCode 3/XCode 4 generator for Waf
2015-10-29 11:53:19 +01:00
# Based on work by Nicolas Mercier 2011
# Extended by Simon Warg 2015, https://github.com/mimon
2015-10-29 11:16:05 +01:00
# XCode project file format based on http://www.monobjc.net/xcode-project-file-format.html
"""
Usage :
2015-10-29 11:53:19 +01:00
See also demos / xcode6 / folder
2015-10-29 11:16:05 +01:00
def options ( opt ) :
2015-10-29 11:53:19 +01:00
opt . load ( ' xcode6 ' )
def configure ( cnf ) :
# <do your stuff>
# For example
cnf . env . SDKROOT = ' macosx10.9 '
# Use cnf.PROJ_CONFIGURATION to completely set/override
# global project settings
# cnf.env.PROJ_CONFIGURATION = {
# 'Debug': {
# 'SDKROOT': 'macosx10.9'
# }
# 'MyCustomReleaseConfig': {
# 'SDKROOT': 'macosx10.10'
# }
# }
# In the end of configure() do
cnf . load ( ' xcode6 ' )
def build ( bld ) :
# Make a Framework target
bld . framework (
2015-11-08 10:06:03 +01:00
source_files = {
' Include ' : bld . path . ant_glob ( ' include/MyLib/*.h ' ) ,
' Source ' : bld . path . ant_glob ( ' src/MyLib/*.cpp ' )
2015-10-29 11:53:19 +01:00
} ,
2015-11-08 10:06:03 +01:00
includes = ' include ' ,
2015-10-29 11:53:19 +01:00
export_headers = bld . path . ant_glob ( ' include/MyLib/*.h ' ) ,
target = ' MyLib ' ,
)
# You can also make bld.dylib, bld.app, bld.stlib ...
2015-10-29 11:16:05 +01:00
2015-10-29 11:53:19 +01:00
$ waf configure xcode6
2015-10-29 11:16:05 +01:00
"""
# TODO: support iOS projects
from waflib import Context , TaskGen , Build , Utils , ConfigSet , Configure , Errors
from waflib . Build import BuildContext
import os , sys , random , time
HEADERS_GLOB = ' **/(*.h|*.hpp|*.H|*.inl) '
MAP_EXT = {
2015-11-08 10:06:03 +01:00
' ' : " folder " ,
2015-10-29 11:16:05 +01:00
' .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 ,
}
"""
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 :
self . env . PROJ_CONFIGURATION = {
" Debug " : self . env . get_merged_dict ( ) ,
" Release " : self . env . get_merged_dict ( ) ,
}
# 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 . iteritems ( ) :
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 = id + 1
return " %04X %04X %04X %012d " % ( 0 , 10000 , 0 , id )
class XCodeNode :
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 \t isa = %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 . 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
2015-11-08 10:06:03 +01:00
def __hash__ ( self ) :
return ( self . fileRef ) . __hash__ ( )
def __eq__ ( self , other ) :
return self . fileRef == other . fileRef
2015-10-29 11:16:05 +01:00
class PBXGroup ( XCodeNode ) :
def __init__ ( self , name , sourcetree = " <group> " ) :
XCodeNode . __init__ ( self )
self . children = [ ]
self . name = name
self . sourceTree = sourcetree
def add ( self , sources ) :
""" sources param should be a list of PBXFileReference objects """
self . children . extend ( sources )
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)
2015-11-08 10:06:03 +01:00
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
2015-10-29 11:16:05 +01:00
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 ) :
2015-11-08 10:06:03 +01:00
""" Represents a target in XCode, e.g. App, DyLib, Framework etc. """
2015-10-29 11:16:05 +01:00
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() ? " )
# Retreive 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 ]
2016-02-19 23:19:56 +01:00
self . hasScannedForEncodings = 1
2015-10-29 11:16:05 +01:00
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 ( " \t archiveVersion = 1; \n " )
w ( " \t classes = { \n " )
w ( " \t }; \n " )
w ( " \t objectVersion = %d ; \n " % self . _objectVersion )
w ( " \t objects = { \n \n " )
XCodeNode . write ( self , file )
w ( " \t }; \n " )
w ( " \t rootObject = %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
class xcode ( Build . BuildContext ) :
2015-10-29 11:52:58 +01:00
cmd = ' xcode6 '
2015-10-29 11:16:05 +01:00
fun = ' build '
file_refs = dict ( )
2015-11-08 10:06:03 +01:00
build_files = dict ( )
2015-10-29 11:16:05 +01:00
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 )
nodes . append ( d )
return nodes
def create_group ( self , name , files ) :
2015-11-08 10:06:03 +01:00
"""
Returns a new PBXGroup containing the files ( paths ) passed in the files arg
2015-10-29 11:16:05 +01:00
: type files : string
"""
group = PBXGroup ( name )
2015-11-08 10:06:03 +01:00
"""
Do not use unique file reference here , since XCode seem to allow only one file reference
to be referenced by a group .
"""
files = [ ( PBXFileReference ( d . name , d . abspath ( ) ) ) for d in self . as_nodes ( files ) ]
group . add ( files )
2015-10-29 11:16:05 +01:00
return group
def unique_filereference ( self , fileref ) :
2015-10-29 11:16:25 +01:00
"""
Returns a unique fileref , possibly an existing one if the paths are the same .
Use this after you ' ve constructed a PBXFileReference to make sure there is
only one PBXFileReference for the same file in the same project .
"""
2015-10-29 11:16:05 +01:00
if fileref not in self . file_refs :
self . file_refs [ fileref ] = fileref
return self . file_refs [ fileref ]
2015-11-08 10:06:03 +01:00
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 .
"""
if buildfile not in self . build_files :
self . build_files [ buildfile ] = buildfile
return self . build_files [ buildfile ]
2015-10-29 11:16:05 +01:00
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 )
2015-11-08 10:06:03 +01:00
# 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 )
2015-10-29 11:16:05 +01:00
for g in self . groups :
for tg in g :
if not isinstance ( tg , TaskGen . task_gen ) :
continue
tg . post ( )
target_group = PBXGroup ( tg . name )
p . mainGroup . children . append ( target_group )
# Determine what type to build - framework, app bundle etc.
target_type = getattr ( tg , ' 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 ( ) ) , tg . name ) )
else :
target_type = TARGET_TYPES [ target_type ]
file_ext = target_type [ 2 ]
# Create the output node
target_node = tg . path . find_or_declare ( tg . name + file_ext )
target = PBXNativeTarget ( tg . name , target_node , target_type , [ ] , [ ] )
2015-11-08 10:06:03 +01:00
products_group . children . append ( target . productReference )
if hasattr ( tg , ' source_files ' ) :
# Create list of PBXFileReferences
sources = [ ]
if isinstance ( tg . source_files , dict ) :
for grpname , files in tg . source_files . items ( ) :
group = self . create_group ( grpname , files )
target_group . children . append ( group )
sources . extend ( group . children )
elif isinstance ( tg . source_files , list ) :
group = self . create_group ( " Source " , tg . source_files )
target_group . children . append ( group )
sources . extend ( group . children )
else :
self . to_log ( " Argument ' source_files ' passed to target ' %s ' was not a dictionary. Hence, some source files may not be included. Please provide a dictionary of source files, with group name as key and list of source files as value. \n " % tg . name )
supported_extensions = [ ' .c ' , ' .cpp ' , ' .m ' , ' .mm ' ]
sources = filter ( lambda fileref : os . path . splitext ( fileref . path ) [ 1 ] in supported_extensions , sources )
buildfiles = [ self . unique_buildfile ( PBXBuildFile ( fileref ) ) for fileref in sources ]
2015-10-29 11:16:05 +01:00
target . add_build_phase ( PBXSourcesBuildPhase ( buildfiles ) )
# Create build settings which can override the project settings. Defaults to none if user
# did not pass argument. However, this will be filled up further below with target specfic
# search paths, libs to link etc.
settings = getattr ( tg , ' settings ' , { } )
# Check if any framework to link against is some other target we've made
libs = getattr ( tg , ' 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
target . add_dependency ( p . create_target_dependency ( use_target , use_target . name ) )
target . add_build_phase ( PBXFrameworksBuildPhase ( [ PBXBuildFile ( use_target . productReference ) ] ) )
2015-11-08 10:06:03 +01:00
if lib in tg . env . LIB :
tg . env . LIB = list ( filter ( lambda x : x != lib , tg . env . LIB ) )
2015-10-29 11:16:05 +01:00
# 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.
2015-11-08 10:06:03 +01:00
exp_hdrs = getattr ( tg , ' export_headers ' , [ ] )
hdrs = self . as_nodes ( Utils . to_list ( exp_hdrs ) )
2015-10-29 11:16:05 +01:00
files = [ self . unique_filereference ( PBXFileReference ( n . name , n . abspath ( ) ) ) for n in hdrs ]
target . add_build_phase ( PBXHeadersBuildPhase ( [ PBXBuildFile ( f , { ' ATTRIBUTES ' : ( ' Public ' , ) } ) for f in files ] ) )
2015-11-08 10:06:03 +01:00
# Install path
installpaths = Utils . to_list ( getattr ( tg , ' install ' , [ ] ) )
prodbuildfile = PBXBuildFile ( target . productReference )
for instpath in installpaths :
target . add_build_phase ( PBXCopyFilesBuildPhase ( [ prodbuildfile ] , instpath ) )
2015-10-29 11:16:05 +01:00
# Merge frameworks and libs into one list, and prefix the frameworks
2015-11-08 10:06:03 +01:00
ld_flags = [ ' -framework %s ' % lib . split ( ' .framework ' ) [ 0 ] for lib in Utils . to_list ( tg . env . FRAMEWORK ) ]
2015-10-29 11:16:05 +01:00
ld_flags . extend ( Utils . to_list ( tg . env . STLIB ) + Utils . to_list ( tg . env . LIB ) )
# Override target specfic build settings
bldsettings = {
' HEADER_SEARCH_PATHS ' : [ ' $(inherited) ' ] + tg . env [ ' INCPATHS ' ] ,
' LIBRARY_SEARCH_PATHS ' : [ ' $(inherited) ' ] + Utils . to_list ( tg . env . LIBPATH ) + Utils . to_list ( tg . env . STLIBPATH ) ,
' FRAMEWORK_SEARCH_PATHS ' : [ ' $(inherited) ' ] + Utils . to_list ( tg . env . FRAMEWORKPATH ) ,
' OTHER_LDFLAGS ' : r ' \ n ' . join ( ld_flags )
}
# 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 ( ) + self . 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 )
node = self . bldnode . make_node ( ' %s .xcodeproj ' % appname )
node . mkdir ( )
node = node . make_node ( ' project.pbxproj ' )
p . write ( open ( node . abspath ( ) , ' w ' ) )
def build_target ( self , tgtype , * k , * * kw ) :
"""
Provide user - friendly methods to build different target types
E . g . bld . framework ( source = ' .. ' , . . . ) to build a Framework target .
E . g . bld . dylib ( source = ' .. ' , . . . ) to build a Dynamic library target . etc . . .
"""
self . load ( ' ccroot ' )
kw [ ' features ' ] = ' cxx cxxprogram '
kw [ ' target_type ' ] = tgtype
return self ( * k , * * kw )
def app ( self , * k , * * kw ) : return self . build_target ( ' app ' , * k , * * kw )
def framework ( self , * k , * * kw ) : return self . build_target ( ' framework ' , * k , * * kw )
def dylib ( self , * k , * * kw ) : return self . build_target ( ' dylib ' , * k , * * kw )
def stlib ( self , * k , * * kw ) : return self . build_target ( ' stlib ' , * k , * * kw )
def exe ( self , * k , * * kw ) : return self . build_target ( ' exe ' , * k , * * kw )