mirror of
https://gitlab.com/ita1024/waf.git
synced 2024-11-22 09:57:15 +01:00
commit
975fdde91b
25
.gitignore
vendored
25
.gitignore
vendored
@ -9,3 +9,28 @@ demos/*/build*
|
||||
playground/*/build*
|
||||
.waf-*
|
||||
*.log
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
|
7
demos/xcode6/include/MyLib/TestClass.h
Normal file
7
demos/xcode6/include/MyLib/TestClass.h
Normal file
@ -0,0 +1,7 @@
|
||||
#include <string>
|
||||
|
||||
class TestClass
|
||||
{
|
||||
public:
|
||||
std::string message();
|
||||
};
|
5
demos/xcode6/src/MyLib/TestClass.cpp
Normal file
5
demos/xcode6/src/MyLib/TestClass.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include "MyLib/TestClass.h"
|
||||
|
||||
std::string TestClass::message() {
|
||||
return "Hello from TestClass";
|
||||
}
|
9
demos/xcode6/src/test.cpp
Normal file
9
demos/xcode6/src/test.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
#include <iostream>
|
||||
#include "MyLib/TestClass.h"
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
TestClass a;
|
||||
std::cout << a.message();
|
||||
return 0;
|
||||
}
|
63
demos/xcode6/wscript
Normal file
63
demos/xcode6/wscript
Normal file
@ -0,0 +1,63 @@
|
||||
from waflib import Task, TaskGen
|
||||
top = '.'
|
||||
out = 'build'
|
||||
APPNAME = 'TestProject'
|
||||
VERSION = '1.0'
|
||||
|
||||
def options(opt):
|
||||
opt.load('xcode6')
|
||||
|
||||
def configure(conf):
|
||||
|
||||
conf.env.FRAMEWORK_VERSION = '1.0'
|
||||
conf.env.ARCHS = 'x86_64'
|
||||
conf.env.MACOSX_DEPLOYMENT_TARGET = '10.9'
|
||||
conf.env.SDKROOT = 'macosx10.9'
|
||||
|
||||
conf.load('xcode6')
|
||||
|
||||
def build(bld):
|
||||
|
||||
tg = bld.framework(
|
||||
source=bld.path.ant_glob('src/MyLib/*.cpp'),
|
||||
includes='include',
|
||||
group_files={
|
||||
'Include': bld.path.ant_glob('include/MyLib/*.h')
|
||||
},
|
||||
|
||||
# export_headers will put the files in the Header
|
||||
# buildphase in Xcode - i.e ship them with your .framework
|
||||
export_headers=bld.path.ant_glob('include/MyLib/*.h'),
|
||||
target='MyLib',
|
||||
)
|
||||
|
||||
bld.env.LIB_SDL2 = '/Library/Frameworks/SDL2.framework/SDL2'
|
||||
tg2 = bld.app(
|
||||
source=bld.path.ant_glob('src/*.cpp|'),
|
||||
includes=tg.includes,
|
||||
target='MyApp',
|
||||
use='MyLib',
|
||||
uselib='SDL2',
|
||||
cxxflags='-O3',
|
||||
framework='Cocoa',
|
||||
settings={"Debug": {"CONFIG_NAME": 'Debug'}}
|
||||
)
|
||||
|
||||
bld.dylib(
|
||||
source=tg.source,
|
||||
includes=tg.includes,
|
||||
target='MyDynLib',
|
||||
)
|
||||
|
||||
bld.exe(
|
||||
source=tg.source,
|
||||
includes=tg.includes,
|
||||
target='MyExe',
|
||||
)
|
||||
|
||||
bld.stlib(
|
||||
source=tg.source,
|
||||
includes=tg.includes,
|
||||
target='MyStaticLib',
|
||||
)
|
||||
|
603
waflib/extras/xcode6.py
Normal file
603
waflib/extras/xcode6.py
Normal file
@ -0,0 +1,603 @@
|
||||
#! /usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# XCode 3/XCode 4 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
|
||||
|
||||
"""
|
||||
Usage:
|
||||
|
||||
See also demos/xcode6/ folder
|
||||
|
||||
def options(opt):
|
||||
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(
|
||||
source=bld.path.ant_glob('src/MyLib/*.cpp'),
|
||||
includes='include',
|
||||
group_files={
|
||||
'Include': bld.path.ant_glob('include/MyLib/*.h')
|
||||
},
|
||||
export_headers=bld.path.ant_glob('include/MyLib/*.h'),
|
||||
target='MyLib',
|
||||
)
|
||||
|
||||
# You can also make bld.dylib, bld.app, bld.stlib ...
|
||||
|
||||
$ waf configure xcode6
|
||||
"""
|
||||
|
||||
# TODO: support iOS projects
|
||||
|
||||
from waflib import Context, TaskGen, Build, Utils, ConfigSet, Configure, Errors
|
||||
from waflib.Build import BuildContext
|
||||
import os, sys, random, time
|
||||
|
||||
def options(opt):
|
||||
opt.load('cxx')
|
||||
|
||||
HEADERS_GLOB = '**/(*.h|*.hpp|*.H|*.inl)'
|
||||
|
||||
MAP_EXT = {
|
||||
'.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\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.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
|
||||
|
||||
|
||||
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)
|
||||
|
||||
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):
|
||||
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]
|
||||
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
|
||||
|
||||
class xcode(Build.BuildContext):
|
||||
cmd = 'xcode6'
|
||||
fun = 'build'
|
||||
|
||||
file_refs = dict()
|
||||
|
||||
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):
|
||||
""" Returns a new PBXGroup containing the files (paths) passed in the files arg
|
||||
:type files: string
|
||||
"""
|
||||
group = PBXGroup(name)
|
||||
files = [self.unique_filereference(PBXFileReference(d.name, d.abspath())) for d in self.as_nodes(files)]
|
||||
group.children.extend(files)
|
||||
return group
|
||||
|
||||
def unique_filereference(self, fileref):
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
if fileref not in self.file_refs:
|
||||
self.file_refs[fileref] = fileref
|
||||
return self.file_refs[fileref]
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
if hasattr(tg, 'group_files'):
|
||||
if isinstance(tg.group_files, dict):
|
||||
for grpname,files in tg.group_files.items():
|
||||
group_files = self.create_group(grpname, files)
|
||||
target_group.children.append(group_files)
|
||||
else:
|
||||
self.to_log("Argument 'group_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)
|
||||
|
||||
# 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, [], [])
|
||||
|
||||
# Collect source and put them in a group with name set to 'Source', which can be overriden
|
||||
if len(tg.source) > 0:
|
||||
g = self.create_group(getattr(tg, 'source_grpname', 'Source'), tg.source)
|
||||
buildfiles = [PBXBuildFile(fileref) for fileref in g.children]
|
||||
target.add_build_phase(PBXSourcesBuildPhase(buildfiles))
|
||||
target_group.children.append(g)
|
||||
|
||||
# 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)]))
|
||||
|
||||
# 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.
|
||||
hdrs = self.as_nodes(Utils.to_list(getattr(tg, 'export_headers', [])))
|
||||
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]))
|
||||
|
||||
|
||||
# Merge frameworks and libs into one list, and prefix the frameworks
|
||||
ld_flags = ['-framework %s' % lib for lib in Utils.to_list(tg.env.FRAMEWORK)]
|
||||
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)
|
Loading…
Reference in New Issue
Block a user