diff options
author | Adrian Knoth <adi@drcomp.erfurt.thur.de> | 2017-02-28 11:21:04 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-02-28 11:21:04 +0100 |
commit | e0281d82c277776c9ea5ae4a272a6a7a950b039c (patch) | |
tree | 22362b27c420cd5f40dbd3582868267c2ff68c86 | |
parent | 4cf826c82c8f865c281833f92f8182d457277b3a (diff) | |
parent | cf48eedf957d6b759eff6c66b74b4c667b11536e (diff) | |
download | jack2-e0281d82c277776c9ea5ae4a272a6a7a950b039c.tar.gz |
Merge pull request #190 from jackaudio/waf-macosx-fixes
Waf macosx fixes
-rw-r--r-- | .travis.yml | 37 | ||||
-rwxr-xr-x | .wafupdaterc | 2 | ||||
-rw-r--r-- | common/wscript | 51 | ||||
-rw-r--r-- | example-clients/wscript | 20 | ||||
-rw-r--r-- | macosx/JackMachSemaphore.mm (renamed from macosx/JackMachSemaphore.cpp) | 0 | ||||
-rw-r--r-- | macosx/JackMachThread.h | 2 | ||||
-rw-r--r-- | macosx/JackMachThread.mm (renamed from macosx/JackMachThread.cpp) | 0 | ||||
-rw-r--r-- | macosx/coreaudio/JackCoreAudioAdapter.mm (renamed from macosx/coreaudio/JackCoreAudioAdapter.cpp) | 0 | ||||
-rw-r--r-- | macosx/coreaudio/JackCoreAudioDriver.mm (renamed from macosx/coreaudio/JackCoreAudioDriver.cpp) | 0 | ||||
-rw-r--r-- | macosx/coreaudio/TiPhoneCoreAudioRenderer.mm (renamed from macosx/coreaudio/TiPhoneCoreAudioRenderer.cpp) | 0 | ||||
-rw-r--r-- | macosx/coremidi/JackCoreMidiDriver.mm (renamed from macosx/coremidi/JackCoreMidiDriver.cpp) | 0 | ||||
-rw-r--r-- | macosx/coremidi/JackCoreMidiInputPort.mm (renamed from macosx/coremidi/JackCoreMidiInputPort.cpp) | 0 | ||||
-rw-r--r-- | macosx/coremidi/JackCoreMidiOutputPort.mm (renamed from macosx/coremidi/JackCoreMidiOutputPort.cpp) | 0 | ||||
-rw-r--r-- | macosx/coremidi/JackCoreMidiPhysicalInputPort.mm (renamed from macosx/coremidi/JackCoreMidiPhysicalInputPort.cpp) | 0 | ||||
-rw-r--r-- | macosx/coremidi/JackCoreMidiPhysicalOutputPort.mm (renamed from macosx/coremidi/JackCoreMidiPhysicalOutputPort.cpp) | 0 | ||||
-rw-r--r-- | macosx/coremidi/JackCoreMidiPort.mm (renamed from macosx/coremidi/JackCoreMidiPort.cpp) | 0 | ||||
-rw-r--r-- | macosx/coremidi/JackCoreMidiUtil.h | 3 | ||||
-rw-r--r-- | macosx/coremidi/JackCoreMidiUtil.mm (renamed from macosx/coremidi/JackCoreMidiUtil.cpp) | 15 | ||||
-rw-r--r-- | macosx/coremidi/JackCoreMidiVirtualInputPort.mm (renamed from macosx/coremidi/JackCoreMidiVirtualInputPort.cpp) | 0 | ||||
-rw-r--r-- | macosx/coremidi/JackCoreMidiVirtualOutputPort.mm (renamed from macosx/coremidi/JackCoreMidiVirtualOutputPort.cpp) | 0 | ||||
-rw-r--r-- | tests/wscript | 3 | ||||
-rw-r--r-- | waflib/extras/xcode.py | 312 | ||||
-rw-r--r-- | waflib/extras/xcode6.py | 656 | ||||
-rw-r--r-- | wscript | 55 |
24 files changed, 1085 insertions, 71 deletions
diff --git a/.travis.yml b/.travis.yml index 33235eb3..103729fd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 diff --git a/.wafupdaterc b/.wafupdaterc index 69f4293a..9d98b67f 100755 --- a/.wafupdaterc +++ b/.wafupdaterc @@ -133,6 +133,4 @@ WAFLIB_STRIP_EXTRAS=" valadoc why win32_opts - xcode - xcode6 " diff --git a/common/wscript b/common/wscript index b64d275f..073d70a9 100644 --- a/common/wscript +++ b/common/wscript @@ -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'] diff --git a/example-clients/wscript b/example-clients/wscript index 1b2f6748..b2950f1f 100644 --- a/example-clients/wscript +++ b/example-clients/wscript @@ -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' diff --git a/macosx/JackMachSemaphore.cpp b/macosx/JackMachSemaphore.mm index 1e19329f..1e19329f 100644 --- a/macosx/JackMachSemaphore.cpp +++ b/macosx/JackMachSemaphore.mm diff --git a/macosx/JackMachThread.h b/macosx/JackMachThread.h index 1aad4cc6..1cd08fba 100644 --- a/macosx/JackMachThread.h +++ b/macosx/JackMachThread.h @@ -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> diff --git a/macosx/JackMachThread.cpp b/macosx/JackMachThread.mm index 061c7919..061c7919 100644 --- a/macosx/JackMachThread.cpp +++ b/macosx/JackMachThread.mm diff --git a/macosx/coreaudio/JackCoreAudioAdapter.cpp b/macosx/coreaudio/JackCoreAudioAdapter.mm index b0ff171d..b0ff171d 100644 --- a/macosx/coreaudio/JackCoreAudioAdapter.cpp +++ b/macosx/coreaudio/JackCoreAudioAdapter.mm diff --git a/macosx/coreaudio/JackCoreAudioDriver.cpp b/macosx/coreaudio/JackCoreAudioDriver.mm index d9448030..d9448030 100644 --- a/macosx/coreaudio/JackCoreAudioDriver.cpp +++ b/macosx/coreaudio/JackCoreAudioDriver.mm diff --git a/macosx/coreaudio/TiPhoneCoreAudioRenderer.cpp b/macosx/coreaudio/TiPhoneCoreAudioRenderer.mm index dd2be73f..dd2be73f 100644 --- a/macosx/coreaudio/TiPhoneCoreAudioRenderer.cpp +++ b/macosx/coreaudio/TiPhoneCoreAudioRenderer.mm diff --git a/macosx/coremidi/JackCoreMidiDriver.cpp b/macosx/coremidi/JackCoreMidiDriver.mm index 16912ab6..16912ab6 100644 --- a/macosx/coremidi/JackCoreMidiDriver.cpp +++ b/macosx/coremidi/JackCoreMidiDriver.mm diff --git a/macosx/coremidi/JackCoreMidiInputPort.cpp b/macosx/coremidi/JackCoreMidiInputPort.mm index 7395c75e..7395c75e 100644 --- a/macosx/coremidi/JackCoreMidiInputPort.cpp +++ b/macosx/coremidi/JackCoreMidiInputPort.mm diff --git a/macosx/coremidi/JackCoreMidiOutputPort.cpp b/macosx/coremidi/JackCoreMidiOutputPort.mm index 9fcee2a4..9fcee2a4 100644 --- a/macosx/coremidi/JackCoreMidiOutputPort.cpp +++ b/macosx/coremidi/JackCoreMidiOutputPort.mm diff --git a/macosx/coremidi/JackCoreMidiPhysicalInputPort.cpp b/macosx/coremidi/JackCoreMidiPhysicalInputPort.mm index 748dbc17..748dbc17 100644 --- a/macosx/coremidi/JackCoreMidiPhysicalInputPort.cpp +++ b/macosx/coremidi/JackCoreMidiPhysicalInputPort.mm diff --git a/macosx/coremidi/JackCoreMidiPhysicalOutputPort.cpp b/macosx/coremidi/JackCoreMidiPhysicalOutputPort.mm index d8a4af25..d8a4af25 100644 --- a/macosx/coremidi/JackCoreMidiPhysicalOutputPort.cpp +++ b/macosx/coremidi/JackCoreMidiPhysicalOutputPort.mm diff --git a/macosx/coremidi/JackCoreMidiPort.cpp b/macosx/coremidi/JackCoreMidiPort.mm index 67367923..67367923 100644 --- a/macosx/coremidi/JackCoreMidiPort.cpp +++ b/macosx/coremidi/JackCoreMidiPort.mm diff --git a/macosx/coremidi/JackCoreMidiUtil.h b/macosx/coremidi/JackCoreMidiUtil.h index 4f24fc5b..b8ad84e9 100644 --- a/macosx/coremidi/JackCoreMidiUtil.h +++ b/macosx/coremidi/JackCoreMidiUtil.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 { diff --git a/macosx/coremidi/JackCoreMidiUtil.cpp b/macosx/coremidi/JackCoreMidiUtil.mm index d976e936..8014f572 100644 --- a/macosx/coremidi/JackCoreMidiUtil.cpp +++ b/macosx/coremidi/JackCoreMidiUtil.mm @@ -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 diff --git a/macosx/coremidi/JackCoreMidiVirtualInputPort.cpp b/macosx/coremidi/JackCoreMidiVirtualInputPort.mm index 511a6efb..511a6efb 100644 --- a/macosx/coremidi/JackCoreMidiVirtualInputPort.cpp +++ b/macosx/coremidi/JackCoreMidiVirtualInputPort.mm diff --git a/macosx/coremidi/JackCoreMidiVirtualOutputPort.cpp b/macosx/coremidi/JackCoreMidiVirtualOutputPort.mm index 9bd1ebe9..9bd1ebe9 100644 --- a/macosx/coremidi/JackCoreMidiVirtualOutputPort.cpp +++ b/macosx/coremidi/JackCoreMidiVirtualOutputPort.mm diff --git a/tests/wscript b/tests/wscript index 70d48f0f..24d76e72 100644 --- a/tests/wscript +++ b/tests/wscript @@ -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 diff --git a/waflib/extras/xcode.py b/waflib/extras/xcode.py new file mode 100644 index 00000000..49a16919 --- /dev/null +++ b/waflib/extras/xcode.py @@ -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')) + + diff --git a/waflib/extras/xcode6.py b/waflib/extras/xcode6.py new file mode 100644 index 00000000..ea299ab9 --- /dev/null +++ b/waflib/extras/xcode6.py @@ -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) |