Waf macosx fixestags/v1.9.11-RC1
@@ -1,9 +1,34 @@ | |||
sudo: false | |||
os: | |||
- osx | |||
- linux | |||
language: | |||
- cpp | |||
- cpp | |||
compiler: | |||
- gcc | |||
install: | |||
- sudo apt-get install libsamplerate-dev libsndfile-dev libasound2-dev | |||
- gcc | |||
- clang | |||
addons: | |||
apt: | |||
packages: | |||
- libsamplerate-dev | |||
- libsndfile-dev | |||
- libasound2-dev | |||
before_install: | |||
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update; fi | |||
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew outdated pkg-config || brew upgrade pkg-config; fi | |||
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install aften; fi | |||
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install libsamplerate; fi | |||
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install libsndfile; fi | |||
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install opus; fi | |||
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install readline; fi | |||
script: | |||
- ./waf configure --alsa | |||
- ./waf build | |||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then ./waf configure --alsa; fi | |||
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then ./waf configure --opus=no --readline=no; fi | |||
- ./waf build | |||
matrix: | |||
exclude: | |||
- os: osx | |||
compiler: gcc |
@@ -133,6 +133,4 @@ WAFLIB_STRIP_EXTRAS=" | |||
valadoc | |||
why | |||
win32_opts | |||
xcode | |||
xcode6 | |||
" |
@@ -17,12 +17,14 @@ def configure(conf): | |||
conf.check(function_name='timeGetDevCaps', header_name=['windows.h', 'mmsystem.h'], lib='winmm', uselib_store="WINMM", define_name='HAVE_MMSYSTEM_H') | |||
conf.check(function_name='EnumProcesses', header_name=['windows.h', 'psapi.h'], lib='psapi', uselib_store="PSAPI", define_name='HAVE_PSAPI_H') | |||
def create_jack_process_obj(bld, target, sources, uselib = None): | |||
def create_jack_process_obj(bld, target, sources, uselib = None, framework = None): | |||
process = bld(features = ['cxx', 'cxxshlib']) | |||
if not bld.env['IS_WINDOWS']: | |||
process.env['cxxshlib_PATTERN'] = '%s.so' | |||
process.defines = ['HAVE_CONFIG_H','SERVER_SIDE'] | |||
if bld.env['IS_MACOSX']: | |||
if framework: | |||
process.framework = framework | |||
env_includes = ['../macosx', '../posix', '../macosx/coreaudio'] | |||
if bld.env['IS_LINUX']: | |||
env_includes = ['../linux', '../posix', '../linux/alsa'] | |||
@@ -37,8 +39,6 @@ def create_jack_process_obj(bld, target, sources, uselib = None): | |||
if bld.env['IS_LINUX']: | |||
process.env.append_value("CPPFLAGS", "-fvisibility=hidden") | |||
if bld.env['IS_MACOSX']: | |||
process.env.append_value("CPPFLAGS", "-mmacosx-version-min=10.4 -arch i386 -arch ppc -arch x86_64") | |||
#process.env.append_value("LINKFLAGS", "-arch i386 -arch ppc -arch x86_64") | |||
process.env.append_value("CPPFLAGS", "-fvisibility=hidden") | |||
process.install_path = '${ADDON_DIR}/' | |||
process.use = [uselib.name] | |||
@@ -113,8 +113,10 @@ def build(bld): | |||
'timestamps.c', | |||
'../posix/JackPosixProcessSync.cpp', | |||
'../posix/JackPosixThread.cpp', | |||
'../macosx/JackMachThread.cpp', | |||
'../macosx/JackMachSemaphore.cpp', | |||
'../posix/JackPosixMutex.cpp', | |||
'../macosx/JackMachThread.mm', | |||
#'../macosx/JackMachSemaphore.mm', | |||
'../posix/JackPosixSemaphore.cpp', | |||
'../posix/JackSocket.cpp', | |||
'../macosx/JackMachTime.c', | |||
] | |||
@@ -135,6 +137,8 @@ def build(bld): | |||
uselib.append('WINMM') | |||
clientlib = bld(features = ['c', 'cxx', 'cxxshlib', 'cshlib']) | |||
if bld.env['IS_MACOSX']: | |||
clientlib.framework = ['CoreAudio', 'Accelerate'] | |||
clientlib.defines = 'HAVE_CONFIG_H' | |||
clientlib.use = uselib | |||
if bld.env['IS_WINDOWS']: | |||
@@ -185,10 +189,7 @@ def build(bld): | |||
if bld.env['IS_MACOSX']: | |||
clientlib.env.append_value("CPPFLAGS", "-fvisibility=hidden") | |||
clientlib.env.append_value("CPPFLAGS", "-mmacosx-version-min=10.4 -arch i386 -arch ppc -arch x86_64") | |||
#clientlib.env.append_value("LINKFLAGS", "-framework CoreAudio -framework vecLib -single_module -arch i386 -arch ppc -arch x86_64" | |||
clientlib.env.append_value("LINKFLAGS", "-framework CoreAudio -framework vecLib -single_module") | |||
clientlib.env.append_value("LINKFLAGS", "-compatibility_version 1 -current_version 1") | |||
clientlib.env.append_value("LINKFLAGS", "-single_module") | |||
if bld.env['IS_SUN']: | |||
clientlib.env.append_value("LINKFLAGS", "-lnsl -lsocket") | |||
@@ -199,6 +200,8 @@ def build(bld): | |||
return | |||
serverlib = bld(features = ['c', 'cxx', 'cxxshlib', 'cshlib']) | |||
if bld.env['IS_MACOSX']: | |||
serverlib.framework = ['CoreAudio', 'CoreFoundation', 'Accelerate'] | |||
serverlib.defines = ['HAVE_CONFIG_H','SERVER_SIDE'] | |||
serverlib.includes = includes | |||
serverlib.name = 'serverlib' | |||
@@ -285,16 +288,15 @@ def build(bld): | |||
if bld.env['IS_MACOSX']: | |||
serverlib.env.append_value("CPPFLAGS", "-fvisibility=hidden") | |||
serverlib.env.append_value("CPPFLAGS", "-mmacosx-version-min=10.4 -arch i386 -arch ppc -arch x86_64") | |||
#serverlib.env.append_value("LINKFLAGS", "-framework CoreAudio -framework vecLib -single_module -arch i386 -arch ppc -arch x86_64") | |||
serverlib.env.append_value("LINKFLAGS", "-framework CoreAudio -framework CoreFoundation -framework vecLib -single_module") | |||
serverlib.env.append_value("LINKFLAGS", "-compatibility_version 1 -current_version 1") | |||
serverlib.env.append_value("LINKFLAGS", "-single_module") | |||
if bld.env['IS_SUN']: | |||
serverlib.env.append_value("LINKFLAGS", "-lnsl -lsocket") | |||
if bld.env['BUILD_NETLIB']: | |||
netlib = bld(features = ['c', 'cxx', 'cxxshlib', 'cshlib']) | |||
if bld.env['IS_MACOSX']: | |||
netlib.framework = ['CoreAudio'] | |||
netlib.defines = ['HAVE_CONFIG_H','SERVER_SIDE'] | |||
netlib.includes = includes | |||
netlib.name = 'netlib' | |||
@@ -303,6 +305,8 @@ def build(bld): | |||
if bld.env['IS_WINDOWS']: | |||
netlib.install_path = '${BINDIR}' | |||
netlib.use += ['WS2_32', 'WINMM'] | |||
elif bld.env['IS_MACOSX']: | |||
netlib.install_path = '${LIBDIR}' | |||
else: | |||
netlib.use += ['RT'] | |||
netlib.install_path = '${LIBDIR}' | |||
@@ -327,8 +331,8 @@ def build(bld): | |||
if bld.env['IS_MACOSX']: | |||
netlib.source += ['../posix/JackNetUnixSocket.cpp','../posix/JackPosixThread.cpp', '../posix/JackPosixMutex.cpp', '../macosx/JackMachThread.cpp', '../macosx/JackMachTime.c'] | |||
netlib.env.append_value("LINKFLAGS", "-framework CoreAudio -single_module") | |||
netlib.source += ['../posix/JackNetUnixSocket.cpp','../posix/JackPosixThread.cpp', '../posix/JackPosixMutex.cpp', '../macosx/JackMachThread.mm', '../macosx/JackMachTime.c'] | |||
netlib.env.append_value("LINKFLAGS", "-single_module") | |||
if bld.env['IS_WINDOWS']: | |||
netlib.source += ['../windows/JackNetWinSocket.cpp','../windows/JackWinThread.cpp', '../windows/JackMMCSS.cpp', '../windows/JackWinTime.c'] | |||
@@ -360,10 +364,19 @@ def build(bld): | |||
] | |||
if bld.env['BUILD_ADAPTER'] and bld.env['IS_MACOSX']: | |||
audio_adapter_sources += ['../macosx/coreaudio/JackCoreAudioAdapter.cpp'] | |||
process = create_jack_process_obj(bld, 'audioadapter', audio_adapter_sources, serverlib) | |||
process.env.append_value("LINKFLAGS", "-framework CoreAudio -framework AudioUnit -framework AudioToolbox -framework CoreServices") | |||
process.use = 'SAMPLERATE' | |||
audio_adapter_sources += ['../macosx/coreaudio/JackCoreAudioAdapter.mm'] | |||
process = create_jack_process_obj(bld, | |||
'audioadapter', | |||
audio_adapter_sources, | |||
serverlib, | |||
framework = [ | |||
"CoreAudio", | |||
"AudioUnit", | |||
"AudioToolbox", | |||
"CoreServices" | |||
] | |||
) | |||
process.use += ['SAMPLERATE'] | |||
if bld.env['BUILD_ADAPTER'] and bld.env['IS_LINUX'] and bld.env['BUILD_DRIVER_ALSA']: | |||
audio_adapter_sources += ['../linux/alsa/JackAlsaAdapter.cpp'] | |||
@@ -66,14 +66,13 @@ def build(bld): | |||
else: | |||
use = ['clientlib'] | |||
prog = bld(features='c cprogram') | |||
if bld.env['IS_MACOSX']: | |||
prog = bld(features='c cprogram', framework = ["Foundation"]) | |||
else: | |||
prog = bld(features='c cprogram') | |||
prog.includes = os_incdir + ['../common/jack', '../common'] | |||
prog.source = example_program_source | |||
prog.use = use | |||
if bld.env['IS_MACOSX']: | |||
prog.env.append_value("CPPFLAGS", "-mmacosx-version-min=10.4 -arch i386 -arch ppc -arch x86_64") | |||
#prog.env.append_value("LINKFLAGS", "-arch i386 -arch ppc -arch x86_64") | |||
prog.env.append_value("LINKFLAGS", "") | |||
if bld.env['IS_LINUX']: | |||
prog.use += ['RT', 'M'] | |||
if bld.env['IS_SUN']: | |||
@@ -86,10 +85,6 @@ def build(bld): | |||
prog.includes = os_incdir + ['../common/jack', '../common'] | |||
prog.source = 'transport.c' | |||
prog.use = ['clientlib'] | |||
if bld.env['IS_MACOSX']: | |||
prog.env.append_value("CPPFLAGS", "-mmacosx-version-min=10.4 -arch i386 -arch ppc -arch x86_64") | |||
#prog.env.append_value("LINKFLAGS", "-arch i386 -arch ppc -arch x86_64") | |||
prog.env.append_value("LINKFLAGS", "") | |||
if bld.env['IS_LINUX']: | |||
prog.use += ['RT', 'READLINE'] | |||
if bld.env['IS_MACOSX']: | |||
@@ -104,9 +99,6 @@ def build(bld): | |||
prog.source = 'capture_client.c' | |||
prog.use = ['clientlib'] | |||
if bld.env['IS_MACOSX']: | |||
prog.env.append_value("CPPFLAGS", "-mmacosx-version-min=10.4 -arch i386 -arch ppc -arch x86_64") | |||
#prog.env.append_value("LINKFLAGS", "-arch i386 -arch ppc -arch x86_64") | |||
prog.env.append_value("LINKFLAGS", "") | |||
prog.use += ['SNDFILE'] | |||
if bld.env['IS_LINUX']: | |||
prog.use += ['RT', 'SNDFILE'] | |||
@@ -147,10 +139,6 @@ def build(bld): | |||
lib.includes = os_incdir + ['../common/jack', '../common'] | |||
lib.target = example_lib | |||
lib.source = example_lib_source | |||
if bld.env['IS_MACOSX']: | |||
lib.env.append_value("CPPFLAGS", "-mmacosx-version-min=10.4 -arch i386 -arch ppc -arch x86_64") | |||
#lib.env.append_value("LINKFLAGS", "-arch i386 -arch ppc -arch x86_64") | |||
lib.env.append_value("LINKFLAGS", "") | |||
if bld.env['IS_SUN']: | |||
lib.env.append_value("LINKFLAGS", "-lm") | |||
lib.use = 'serverlib' | |||
@@ -70,7 +70,7 @@ typedef unsigned char Boolean; | |||
#include "JackPosixThread.h" | |||
#ifndef MY_TARGET_OS_IPHONE | |||
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacTypes.h> | |||
#include <MacTypes.h> | |||
#endif | |||
#include <mach/thread_policy.h> | |||
@@ -22,8 +22,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
#include <string> | |||
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacTypes.h> | |||
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/Debugging.h> | |||
#include <MacTypes.h> | |||
namespace Jack { | |||
@@ -18,6 +18,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
*/ | |||
#include <sstream> | |||
#include <Foundation/Foundation.h> | |||
#include "JackError.h" | |||
#include "JackCoreMidiUtil.h" | |||
@@ -25,13 +26,15 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
std::string | |||
Jack::GetMacOSErrorString(OSStatus status) | |||
{ | |||
const char *message = GetMacOSStatusErrorString(status); | |||
if (! message) { | |||
std::stringstream stream; | |||
stream << "error (code: '" << status << "')"; | |||
return stream.str(); | |||
NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil]; | |||
NSString *errorString = [error localizedDescription]; | |||
std::string returnString; | |||
if (errorString){ | |||
returnString = std::string([errorString UTF8String]); | |||
} else { | |||
returnString = std::string("No error"); | |||
} | |||
return std::string(message); | |||
return returnString; | |||
} | |||
void |
@@ -25,8 +25,5 @@ def build(bld): | |||
prog.source = test_program_sources | |||
if bld.env['IS_LINUX']: | |||
prog.uselib = 'RT' | |||
if bld.env['IS_MACOSX']: | |||
prog.env.append_value("CPPFLAGS", "-mmacosx-version-min=10.4 -arch i386 -arch ppc -arch x86_64") | |||
#prog.env.append_value("LINKFLAGS", "-arch i386 -arch ppc -arch x86_64") | |||
prog.use = 'clientlib' | |||
prog.target = test_program |
@@ -0,0 +1,312 @@ | |||
#! /usr/bin/env python | |||
# encoding: utf-8 | |||
# XCode 3/XCode 4 generator for Waf | |||
# Nicolas Mercier 2011 | |||
""" | |||
Usage: | |||
def options(opt): | |||
opt.load('xcode') | |||
$ waf configure xcode | |||
""" | |||
# TODO: support iOS projects | |||
from waflib import Context, TaskGen, Build, Utils | |||
import os, sys | |||
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", | |||
} | |||
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() | |||
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): | |||
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, settings): | |||
XCodeNode.__init__(self) | |||
self.buildConfigurations = settings | |||
self.defaultConfigurationIsVisible = 0 | |||
self.defaultConfigurationName = settings and settings[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 | |||
class PBXGroup(XCodeNode): | |||
def __init__(self, name, sourcetree = "<group>"): | |||
XCodeNode.__init__(self) | |||
self.children = [] | |||
self.name = name | |||
self.sourceTree = sourcetree | |||
def add(self, root, sources): | |||
folders = {} | |||
def folder(n): | |||
if not n.is_child_of(root): | |||
return self | |||
try: | |||
return folders[n] | |||
except KeyError: | |||
f = PBXGroup(n.name) | |||
p = folder(n.parent) | |||
folders[n] = f | |||
p.children.append(f) | |||
return f | |||
for s in sources: | |||
f = folder(s.parent) | |||
source = PBXFileReference(s.name, s.abspath()) | |||
f.children.append(source) | |||
# Targets | |||
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, action, target, node, env): | |||
XCodeNode.__init__(self) | |||
conf = XCBuildConfiguration('waf', {'PRODUCT_NAME':target, 'CONFIGURATION_BUILD_DIR':node.parent.abspath()}, env) | |||
self.buildConfigurationList = XCConfigurationList([conf]) | |||
self.buildPhases = [PBXShellScriptBuildPhase(action, target)] | |||
self.buildRules = [] | |||
self.dependencies = [] | |||
self.name = target | |||
self.productName = target | |||
self.productType = "com.apple.product-type.application" | |||
self.productReference = PBXFileReference(target, node.abspath(), 'wrapper.application', 'BUILT_PRODUCTS_DIR') | |||
# Root project object | |||
class PBXProject(XCodeNode): | |||
def __init__(self, name, version): | |||
XCodeNode.__init__(self) | |||
self.buildConfigurationList = XCConfigurationList([XCBuildConfiguration('waf', {})]) | |||
self.compatibilityVersion = version[0] | |||
self.hasScannedForEncodings = 1; | |||
self.mainGroup = PBXGroup(name) | |||
self.projectRoot = "" | |||
self.projectDirPath = "" | |||
self.targets = [] | |||
self._objectVersion = version[1] | |||
self._output = PBXGroup('out') | |||
self.mainGroup.children.append(self._output) | |||
def write(self, file): | |||
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_task_gen(self, tg): | |||
if not getattr(tg, 'mac_app', False): | |||
self.targets.append(PBXLegacyTarget('build', tg.name)) | |||
else: | |||
target = PBXNativeTarget('build', tg.name, tg.link_task.outputs[0].change_ext('.app'), tg.env) | |||
self.targets.append(target) | |||
self._output.children.append(target.productReference) | |||
class xcode(Build.BuildContext): | |||
cmd = 'xcode' | |||
fun = 'build' | |||
def collect_source(self, tg): | |||
source_files = tg.to_nodes(getattr(tg, 'source', [])) | |||
plist_files = tg.to_nodes(getattr(tg, 'mac_plist', [])) | |||
resource_files = [tg.path.find_node(i) for i in Utils.to_list(getattr(tg, 'mac_resources', []))] | |||
include_dirs = Utils.to_list(getattr(tg, 'includes', [])) + Utils.to_list(getattr(tg, 'export_dirs', [])) | |||
include_files = [] | |||
for x in include_dirs: | |||
if not isinstance(x, str): | |||
include_files.append(x) | |||
continue | |||
d = tg.path.find_node(x) | |||
if d: | |||
lst = [y for y in d.ant_glob(HEADERS_GLOB, flat=False)] | |||
include_files.extend(lst) | |||
# remove duplicates | |||
source = list(set(source_files + plist_files + resource_files + include_files)) | |||
source.sort(key=lambda x: x.abspath()) | |||
return source | |||
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)) | |||
for g in self.groups: | |||
for tg in g: | |||
if not isinstance(tg, TaskGen.task_gen): | |||
continue | |||
tg.post() | |||
features = Utils.to_list(getattr(tg, 'features', '')) | |||
group = PBXGroup(tg.name) | |||
group.add(tg.path, self.collect_source(tg)) | |||
p.mainGroup.children.append(group) | |||
if 'cprogram' or 'cxxprogram' in features: | |||
p.add_task_gen(tg) | |||
# targets that don't produce the executable but that you might want to run | |||
p.targets.append(PBXLegacyTarget('configure')) | |||
p.targets.append(PBXLegacyTarget('dist')) | |||
p.targets.append(PBXLegacyTarget('install')) | |||
p.targets.append(PBXLegacyTarget('check')) | |||
node = self.srcnode.make_node('%s.xcodeproj' % appname) | |||
node.mkdir() | |||
node = node.make_node('project.pbxproj') | |||
p.write(open(node.abspath(), 'w')) | |||
@@ -0,0 +1,656 @@ | |||
#! /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_files={ | |||
'Include': bld.path.ant_glob('include/MyLib/*.h'), | |||
'Source': bld.path.ant_glob('src/MyLib/*.cpp') | |||
}, | |||
includes='include', | |||
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 | |||
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, | |||
} | |||
""" | |||
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 | |||
def __hash__(self): | |||
return (self.fileRef).__hash__() | |||
def __eq__(self, other): | |||
return self.fileRef == other.fileRef | |||
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 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() ?") | |||
# 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() | |||
build_files = 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) | |||
""" | |||
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) | |||
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 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] | |||
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) | |||
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, [], []) | |||
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] | |||
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)])) | |||
if lib in tg.env.LIB: | |||
tg.env.LIB = list(filter(lambda x: x != lib, tg.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(tg, 'export_headers', []) | |||
hdrs = self.as_nodes(Utils.to_list(exp_hdrs)) | |||
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])) | |||
# Install path | |||
installpaths = Utils.to_list(getattr(tg, 'install', [])) | |||
prodbuildfile = PBXBuildFile(target.productReference) | |||
for instpath in installpaths: | |||
target.add_build_phase(PBXCopyFilesBuildPhase([prodbuildfile], instpath)) | |||
# Merge frameworks and libs into one list, and prefix the frameworks | |||
ld_flags = ['-framework %s' % lib.split('.framework')[0] 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) |
@@ -387,6 +387,9 @@ def options(opt): | |||
opt.load('compiler_cxx') | |||
opt.load('compiler_c') | |||
opt.load('xcode') | |||
opt.load('xcode6') | |||
# install directories | |||
opt.add_option('--htmldir', type='string', default=None, help="HTML documentation directory [Default: <prefix>/share/jack-audio-connection-kit/reference/html/") | |||
opt.add_option('--libdir', type='string', help="Library directory [Default: <prefix>/lib]") | |||
@@ -478,6 +481,9 @@ def configure(conf): | |||
conf.env.append_unique('CXXFLAGS', '-Wall') | |||
conf.env.append_unique('CFLAGS', '-Wall') | |||
if conf.env['IS_MACOSX']: | |||
conf.check(lib='aften', uselib='AFTEN', define_name='AFTEN') | |||
# configure all auto options | |||
configure_auto_options(conf) | |||
@@ -722,7 +728,8 @@ def build_jackd(bld): | |||
includes = ['.', 'common', 'common/jack'], | |||
target = 'jackd', | |||
source = ['common/Jackdmp.cpp'], | |||
use = ['serverlib']) | |||
use = ['serverlib'] | |||
) | |||
if bld.env['BUILD_JACKDBUS']: | |||
jackd.source += ['dbus/audio_reserve.c', 'dbus/reserve.c'] | |||
@@ -732,8 +739,8 @@ def build_jackd(bld): | |||
jackd.use += ['DL', 'M', 'PTHREAD', 'RT', 'STDC++'] | |||
if bld.env['IS_MACOSX']: | |||
bld.framework = ['CoreFoundation'] | |||
jackd.use += ['DL', 'PTHREAD'] | |||
jackd.framework = ['CoreFoundation'] | |||
if bld.env['IS_SUN']: | |||
jackd.use += ['DL', 'PTHREAD'] | |||
@@ -744,6 +751,15 @@ def build_jackd(bld): | |||
# FIXME: Is SERVER_SIDE needed? | |||
def create_driver_obj(bld, **kw): | |||
if bld.env['IS_MACOSX'] or bld.env['IS_WINDOWS']: | |||
# On MacOSX this is necessary. | |||
# I do not know if this is necessary on Windows. | |||
# Note added on 2015-12-13 by lilrc. | |||
if 'use' in kw: | |||
kw['use'] += ['serverlib'] | |||
else: | |||
kw['use'] = ['serverlib'] | |||
driver = bld( | |||
features = ['c', 'cshlib', 'cxx', 'cxxshlib'], | |||
defines = ['HAVE_CONFIG_H', 'SERVER_SIDE'], | |||
@@ -814,19 +830,20 @@ def build_drivers(bld): | |||
] | |||
coreaudio_src = [ | |||
'macosx/coreaudio/JackCoreAudioDriver.cpp' | |||
'macosx/coreaudio/JackCoreAudioDriver.mm', | |||
'common/JackAC3Encoder.cpp' | |||
] | |||
coremidi_src = [ | |||
'macosx/coremidi/JackCoreMidiInputPort.cpp', | |||
'macosx/coremidi/JackCoreMidiOutputPort.cpp', | |||
'macosx/coremidi/JackCoreMidiPhysicalInputPort.cpp', | |||
'macosx/coremidi/JackCoreMidiPhysicalOutputPort.cpp', | |||
'macosx/coremidi/JackCoreMidiVirtualInputPort.cpp', | |||
'macosx/coremidi/JackCoreMidiVirtualOutputPort.cpp', | |||
'macosx/coremidi/JackCoreMidiPort.cpp', | |||
'macosx/coremidi/JackCoreMidiUtil.cpp', | |||
'macosx/coremidi/JackCoreMidiDriver.cpp' | |||
'macosx/coremidi/JackCoreMidiInputPort.mm', | |||
'macosx/coremidi/JackCoreMidiOutputPort.mm', | |||
'macosx/coremidi/JackCoreMidiPhysicalInputPort.mm', | |||
'macosx/coremidi/JackCoreMidiPhysicalOutputPort.mm', | |||
'macosx/coremidi/JackCoreMidiVirtualInputPort.mm', | |||
'macosx/coremidi/JackCoreMidiVirtualOutputPort.mm', | |||
'macosx/coremidi/JackCoreMidiPort.mm', | |||
'macosx/coremidi/JackCoreMidiUtil.mm', | |||
'macosx/coremidi/JackCoreMidiDriver.mm' | |||
] | |||
ffado_src = [ | |||
@@ -929,21 +946,21 @@ def build_drivers(bld): | |||
bld, | |||
target = 'portaudio', | |||
source = portaudio_src, | |||
use = ['serverlib', 'PORTAUDIO']) # FIXME: Is serverlib needed here? | |||
use = ['PORTAUDIO']) | |||
if bld.env['BUILD_DRIVER_WINMME']: | |||
create_driver_obj( | |||
bld, | |||
target = 'winmme', | |||
source = winmme_src, | |||
use = ['serverlib', 'WINMME']) # FIXME: Is serverlib needed here? | |||
use = ['WINMME']) | |||
if bld.env['IS_MACOSX']: | |||
create_driver_obj( | |||
bld, | |||
target = 'coreaudio', | |||
source = coreaudio_src, | |||
use = ['serverlib'], # FIXME: Is this needed? | |||
use = ['AFTEN'], | |||
framework = ['AudioUnit', 'CoreAudio', 'CoreServices']) | |||
create_driver_obj( | |||
@@ -951,7 +968,7 @@ def build_drivers(bld): | |||
target = 'coremidi', | |||
source = coremidi_src, | |||
use = ['serverlib'], # FIXME: Is this needed? | |||
framework = ['AudioUnit', 'CoreMIDI', 'CoreServices']) | |||
framework = ['AudioUnit', 'CoreMIDI', 'CoreServices', 'Foundation']) | |||
if bld.env['IS_SUN']: | |||
create_driver_obj( | |||
@@ -1071,3 +1088,9 @@ def dist(ctx): | |||
# This code blindly assumes it is working in the toplevel source directory. | |||
if not os.path.exists('svnversion.h'): | |||
os.system('./svnversion_regenerate.sh svnversion.h') | |||
from waflib import TaskGen | |||
@TaskGen.extension('.mm') | |||
def mm_hook(self, node): | |||
"""Alias .mm files to be compiled the same as .cpp files, gcc will do the right thing.""" | |||
return self.create_compiled_task('cxx', node) |