summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Knoth <adi@drcomp.erfurt.thur.de>2017-02-28 11:21:04 +0100
committerGitHub <noreply@github.com>2017-02-28 11:21:04 +0100
commite0281d82c277776c9ea5ae4a272a6a7a950b039c (patch)
tree22362b27c420cd5f40dbd3582868267c2ff68c86
parent4cf826c82c8f865c281833f92f8182d457277b3a (diff)
parentcf48eedf957d6b759eff6c66b74b4c667b11536e (diff)
downloadjack2-e0281d82c277776c9ea5ae4a272a6a7a950b039c.tar.gz
Merge pull request #190 from jackaudio/waf-macosx-fixes
Waf macosx fixes
-rw-r--r--.travis.yml37
-rwxr-xr-x.wafupdaterc2
-rw-r--r--common/wscript51
-rw-r--r--example-clients/wscript20
-rw-r--r--macosx/JackMachSemaphore.mm (renamed from macosx/JackMachSemaphore.cpp)0
-rw-r--r--macosx/JackMachThread.h2
-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.h3
-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/wscript3
-rw-r--r--waflib/extras/xcode.py312
-rw-r--r--waflib/extras/xcode6.py656
-rw-r--r--wscript55
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)
diff --git a/wscript b/wscript
index f0f16ded..6fbe6bf2 100644
--- a/wscript
+++ b/wscript
@@ -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)