New directory tree, with preprocessor/ inside interpretor/.
[Faustine.git] / interpretor / preprocessor / faust-0.9.47mr3 / tools / scbuilder / scbuilder
diff --git a/interpretor/preprocessor/faust-0.9.47mr3/tools/scbuilder/scbuilder b/interpretor/preprocessor/faust-0.9.47mr3/tools/scbuilder/scbuilder
new file mode 100755 (executable)
index 0000000..64f9409
--- /dev/null
@@ -0,0 +1,576 @@
+#!/usr/bin/env ruby
+#
+# File:         scbuilder
+# Contents:     Build script for SuperCollider plugins
+# Authors:      Stefan Kersten <sk AT k-hornz DOT de>
+#               nescivi AT gmail DOT com
+#
+# This is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2, or (at your option) any later version.
+# 
+# This software is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+# 
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 675
+# Mass Ave, Cambridge, MA 02139, USA.
+#
+# ======================================================================
+# Usage:
+# 
+# This script compiles `simple' SuperCollider plugins, i.e. plugins that
+# consist of only one source file. Source files may be C++ implementations or
+# a Faust[1] DSP specification.
+#
+# Source file paths are passed either in a file (specified with the
+# PLUGIN_SOURCES option) or via standard input.
+#
+# E.g., when source file paths are in a file called sources.txt:
+#
+# $ sc-build-plugins PLUGIN_SOURCES=sources.txt
+#
+# Alternatively, source file paths can be passed via standard input:
+#
+# $ my-command | sc-build-plugins
+#
+# ======================================================================
+
+# ======================================================================
+# Bootstrap (ruby): Execute scons with content after __END__
+
+require 'tempfile'
+
+Tempfile.open("r") { |f|
+    f << DATA.read
+    f.flush
+    system("scons", "-f", f.path, *ARGV)
+}
+
+__END__
+
+# ======================================================================
+# NOTE: Please use an indentation level of 4 spaces, i.e. no mixing of
+# tabs and spaces.
+# ======================================================================
+
+# ======================================================================
+# setup
+# ======================================================================
+
+EnsureSConsVersion(0,96)
+EnsurePythonVersion(2,3)
+SConsignFile()
+
+# ======================================================================
+# imports
+# ======================================================================
+
+import glob
+import os
+import re
+import sys
+import subprocess
+import types
+import tarfile
+
+# ======================================================================
+# constants
+# ======================================================================
+
+PACKAGE = 'SuperCollider'
+
+def short_cpu_name(cpu):
+    if cpu == 'Power Macintosh':
+        cpu = 'ppc'
+    return cpu.lower()
+
+PLATFORM = os.uname()[0].lower()
+CPU = short_cpu_name(os.uname()[4])
+
+if PLATFORM == 'darwin':
+    PLATFORM_SYMBOL = 'SC_DARWIN'
+    PLUGIN_EXT = '.scx'
+    DEFAULT_PREFIX = '/'
+elif PLATFORM == 'freebsd':
+    PLATFORM_SYMBOL = 'SC_FREEBSD'
+    PLUGIN_EXT = '.so'
+    DEFAULT_PREFIX = '/usr/local'
+elif PLATFORM == 'linux':
+    PLATFORM_SYMBOL = 'SC_LINUX'
+    PLUGIN_EXT = '.so'
+    DEFAULT_PREFIX = '/usr/local'
+elif PLATFORM == 'windows':
+    PLATFORM_SYMBOL = 'SC_WIN32'
+    PLUGIN_EXT = '.scx'
+    DEFAULT_PREFIX = '/'
+else:
+    print 'Unknown platform: %s' % PLATFORM
+    Exit(1)
+
+if CPU == 'ppc':
+    DEFAULT_OPT_ARCH = '7450'
+elif CPU in [ 'i586', 'i686' ]:
+    # FIXME: better detection
+    DEFAULT_OPT_ARCH = CPU
+else:
+    DEFAULT_OPT_ARCH = None
+
+# ======================================================================
+# util
+# ======================================================================
+
+def make_os_env(*keys):
+    env = os.environ
+    res = {}
+    for key in keys:
+        if env.has_key(key):
+            res[key] = env[key]
+    return res
+
+def CheckPKGConfig(context, version):
+    context.Message( 'Checking for pkg-config... ' )
+    ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0]
+    context.Result( ret )
+    return ret
+
+def CheckPKG(context, name):
+    context.Message('Checking for %s... ' % name)
+    ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0]
+    res = None
+    if ret:
+        res = Environment(ENV = make_os_env('PATH', 'PKG_CONFIG_PATH'))
+        res.ParseConfig('pkg-config --cflags --libs \'%s\'' % name)
+        res['PKGCONFIG'] = name
+    context.Result(ret)
+    return (ret, res)
+
+def get_new_pkg_env():
+    return Environment(ENV = make_os_env('PATH', 'PKG_CONFIG_PATH'))
+
+def merge_lib_info(env, *others):
+    for other in others:
+        env.AppendUnique(CCFLAGS = other.get('CCFLAGS', []))
+        env.AppendUnique(CPPDEFINES = other.get('CPPDEFINES', []))
+        env.AppendUnique(CPPPATH = other.get('CPPPATH', []))
+        env.AppendUnique(CXXFLAGS = other.get('CXXFLAGS', []))
+        env.AppendUnique(LIBS = other.get('LIBS', []))
+        env.AppendUnique(LIBPATH = other.get('LIBPATH', []))
+        env['LINKFLAGS'] = env['LINKFLAGS'] + other.get('LINKFLAGS', "")
+
+def flatten_dir(dir):
+    res = []
+    for root, dirs, files in os.walk(dir):
+        if 'CVS' in dirs: dirs.remove('CVS')
+        if '.svn' in dirs: dirs.remove('.svn')
+        for f in files:
+            res.append(os.path.join(root, f))
+    return res
+
+def install_dir(env, src_dir, dst_dir, filter_re, strip_levels=0):
+    nodes = []
+    for root, dirs, files in os.walk(src_dir):
+        src_paths = []
+        dst_paths = []
+        if 'CVS' in dirs: dirs.remove('CVS')
+        if '.svn' in dirs: dirs.remove('.svn')
+        for d in dirs[:]:
+            if filter_re.match(d):
+                src_paths += flatten_dir(os.path.join(root, d))
+                dirs.remove(d)
+        for f in files:
+            if filter_re.match(f):
+                src_paths.append(os.path.join(root, f))
+        dst_paths += map(
+            lambda f:
+            os.path.join(
+            dst_dir,
+            *f.split(os.path.sep)[strip_levels:]),
+            src_paths)
+        nodes += env.InstallAs(dst_paths, src_paths)
+    return nodes
+
+def is_installing():
+    pat = re.compile('^install.*$')
+    for x in COMMAND_LINE_TARGETS:
+        if pat.match(x): return True
+    return False
+
+def bin_dir(prefix):
+    return os.path.join(prefix, 'bin')
+def lib_dir(prefix):
+    return os.path.join(prefix, 'lib')
+
+def pkg_data_dir(prefix, *args):
+    if PLATFORM == 'darwin':
+        base = os.path.join(prefix, 'Library/Application Support')
+    else:
+        base = os.path.join(prefix, 'share')
+    return os.path.join(base, PACKAGE, *args)
+def pkg_doc_dir(prefix, *args):
+    if PLATFORM == 'darwin':
+        base = os.path.join(prefix, 'Library/Documentation')
+    else:
+        base = os.path.join(prefix, 'share', 'doc')   
+    return os.path.join(base, PACKAGE, *args)
+def pkg_include_dir(prefix, *args):
+    return os.path.join(prefix, 'include', PACKAGE, *args)
+def pkg_lib_dir(prefix, *args):
+    return os.path.join(lib_dir(prefix), PACKAGE, *args)
+
+def pkg_classlib_dir(prefix, *args):
+    return pkg_data_dir(prefix, 'SCClassLibrary', *args)
+def pkg_extension_dir(prefix, *args):
+    return pkg_data_dir(prefix, 'Extensions', *args)
+
+def make_opt_flags(env):
+    flags = [
+        "-O3",
+        ## "-fomit-frame-pointer", # can behave strangely for sclang
+        "-ffast-math",
+        "-fstrength-reduce"
+        ]
+    arch = env.get('OPT_ARCH')
+    if arch:
+        if CPU == 'ppc':
+            flags.extend([ "-mcpu=%s" % (arch,) ])
+        else:
+            flags.extend([ "-march=%s" % (arch,) ])
+    if CPU == 'ppc':
+        flags.extend([ "-fsigned-char", "-mhard-float",
+                       ## "-mpowerpc-gpopt", # crashes sqrt
+                       "-mpowerpc-gfxopt"
+                       ])
+    return flags
+
+# ======================================================================
+# Faust builder
+# ======================================================================
+
+def faustInitEnvironment(env):
+    dsp = Builder(
+        action = 'faust -a supercollider.cpp -o $TARGET $SOURCE',
+        suffix = '.cpp',
+        src_suffix = '.dsp')
+    xml = Builder(
+        action = ['faust -o /dev/null -xml $SOURCE', Move('$TARGET', '${SOURCE}.xml')],
+        suffix = '.dsp.xml',
+        src_suffix = '.dsp')
+    sc = Builder(
+        action = '$FAUST2SC --prefix="$FAUST2SC_PREFIX" -o $TARGET $SOURCE',
+        suffix = '.sc',
+        src_suffix = '.dsp.xml')
+    env.Append(BUILDERS = { 'Faust' : dsp,
+                            'FaustXML' : xml,
+                            'FaustSC' : sc })
+    
+# ======================================================================
+# Command line options
+# ======================================================================
+
+opts = Options('scache.conf', ARGUMENTS)
+opts.AddOptions(
+    BoolOption('ALTIVEC',
+               'Build with Altivec support', 1),
+    PathOption('BUILD_DIR',
+               'Directory to build temporary files in', '.',
+               PathOption.PathIsDirCreate),
+    BoolOption('BUILD_SC', 'Build SuperCollider class files', 1),
+    BoolOption('BUILD_XML', 'Build Faust XML files', 1),
+    ('CC', 'C compiler executable'),
+    ('CCFLAGS', 'C compiler flags'),
+    ('CXX', 'C++ compiler executable'),
+    ('CXXFLAGS', 'C++ compiler flags'),
+    BoolOption('CROSSCOMPILE',
+               'Crosscompile for another platform (does not do SSE support check)', 0),
+    BoolOption('DEBUG',
+               'Build with debugging information', 0),
+    PathOption('DESTDIR',
+               'Intermediate installation prefix for packaging', '/'),
+    PathOption('FAUST2SC',
+               'Path to faust2sc script', 'faust2sc',
+               PathOption.PathAccept),
+    (          'FAUST2SC_PREFIX',
+               'Prefix for SC classes generated from Faust definitions', ''),
+    PathOption('PREFIX',
+               'Installation prefix', DEFAULT_PREFIX),
+    PathOption('INSTALLDIR',
+               'Installation directory', '',
+               PathOption.PathAccept),
+    BoolOption('SSE',
+               'Build with SSE support', 1),
+    (          'OPT_ARCH',
+               'Architecture to optimize for', DEFAULT_OPT_ARCH),
+    PathOption('PLUGIN_SOURCES',
+               'File containing plugin sources (C++ or Faust)', None,
+               PathOption.PathAccept),
+    PathOption('SC_SOURCE_DIR',
+               'SuperCollider source directory', '../supercollider',
+               PathOption.PathAccept),
+    )
+
+if PLATFORM == 'darwin':
+    opts.AddOptions(
+        BoolOption('UNIVERSAL',
+                   'Build universal binaries (see UNIVERSAL_ARCHS)', 1),
+        ListOption('UNIVERSAL_ARCHS',
+                   'Architectures to build for',
+                   'all', ['ppc', 'i386'])
+    )
+    
+# ======================================================================
+# basic environment
+# ======================================================================
+
+env = Environment(options = opts,
+                  ENV = make_os_env('PATH', 'PKG_CONFIG_PATH'),
+                  PACKAGE = PACKAGE,
+                  URL = 'http://supercollider.sourceforge.net')
+env.Append(PATH = ['/usr/local/bin', '/usr/bin', '/bin'])
+faustInitEnvironment(env)
+
+# checks for DISTCC and CCACHE as used in modern linux-distros:
+
+if os.path.exists('/usr/lib/distcc/bin'):
+    os.environ['PATH']         = '/usr/lib/distcc/bin:' + os.environ['PATH']
+    env['ENV']['DISTCC_HOSTS'] = os.environ['DISTCC_HOSTS']
+    
+if os.path.exists('/usr/lib/ccache/bin'):
+    os.environ['PATH']         = '/usr/lib/ccache/bin:' + os.environ['PATH']
+    env['ENV']['CCACHE_DIR']   = os.environ['CCACHE_DIR']
+    
+env['ENV']['PATH'] = os.environ['PATH']
+env['ENV']['HOME'] = os.environ['HOME']
+
+# ======================================================================
+# installation directories
+# ======================================================================
+
+FINAL_PREFIX = '$PREFIX'
+INSTALL_PREFIX = os.path.join('$DESTDIR', '$PREFIX')
+
+# ======================================================================
+# configuration
+# ======================================================================
+
+def make_conf(env):
+    return Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig,
+                                           'CheckPKG' : CheckPKG })
+
+def isDefaultBuild():
+    return not env.GetOption('clean') and not 'debian' in COMMAND_LINE_TARGETS
+
+conf = make_conf(env)
+
+# libraries
+libraries = { }
+features = { }
+
+if isDefaultBuild():
+    if not conf.CheckPKGConfig('0'):
+        print 'pkg-config not found.'
+        Exit(1)
+    
+    # SC includes and flags
+    success, libraries['scplugin'] = conf.CheckPKG('libscplugin')
+    if not success:
+        success, libraries['scplugin'] = conf.CheckPKG('libscsynth')
+    if success:
+        libraries['scplugin']['LIBS'] = []
+    else:
+        src_dir = env['SC_SOURCE_DIR']
+        if os.path.isdir(src_dir):
+            libraries['scplugin'] = Environment(
+                                        CPPDEFINES = [PLATFORM_SYMBOL],
+                                        CPPPATH = [os.path.join(src_dir, 'Headers/common'),
+                                                   os.path.join(src_dir, 'Headers/plugin_interface'),
+                                                   os.path.join(src_dir, 'Headers/server')])
+        else:
+            print "Please specify the SC_SOURCE_DIR option."
+            Exit(1)
+else:
+    libraries['scplugin'] = Environment()
+
+# only _one_ Configure context can be alive at a time
+env = conf.Finish()
+
+# altivec
+if env['ALTIVEC']:
+    if PLATFORM == 'darwin':
+        altivec_flags = [ '-faltivec' ]
+    else:
+        altivec_flags = [ '-maltivec', '-mabi=altivec' ]
+    libraries['altivec'] = env.Copy()
+    libraries['altivec'].Append(
+        CCFLAGS = altivec_flags,
+        CPPDEFINES = [('SC_MEMORY_ALIGNMENT', 16)])
+    altiConf = Configure(libraries['altivec'])
+    features['altivec'] = altiConf.CheckCHeader('altivec.h')
+    altiConf.Finish()
+else:
+    features['altivec'] = False
+
+# sse
+if env['SSE']:
+    libraries['sse'] = env.Copy()
+    libraries['sse'].Append(
+        CCFLAGS = ['-msse', '-mfpmath=sse'],
+        CPPDEFINES = [('SC_MEMORY_ALIGNMENT', 16)])
+    sseConf = Configure(libraries['sse'])
+    hasSSEHeader = sseConf.CheckCHeader('xmmintrin.h')
+    if env['CROSSCOMPILE']:
+        build_host_supports_sse = True
+        print 'NOTICE: cross compiling for another platform: assuming SSE support'
+    else:
+        build_host_supports_sse = False
+        if CPU != 'ppc':
+           if PLATFORM == 'freebsd':
+                machine_info = os.popen ("sysctl -a  hw.instruction_sse").read()[:-1]
+                x86_flags = 'no'
+                if "1" in [x for x in machine_info]:
+                        build_host_supports_sse = True
+                        x86_flags = 'sse'
+           elif PLATFORM != 'darwin':
+                flag_line = os.popen ("cat /proc/cpuinfo | grep '^flags'").read()[:-1]
+                x86_flags = flag_line.split (": ")[1:][0].split ()
+           else:
+              machine_info = os.popen ("sysctl -a machdep.cpu").read()[:-1]
+              x86_flags = machine_info.split()
+           if "sse" in [x.lower() for x in x86_flags]:
+              build_host_supports_sse = True
+              print 'NOTICE: CPU has SSE support'
+        else:
+           print 'NOTICE: CPU does not have SSE support'
+    features['sse'] = hasSSEHeader and build_host_supports_sse
+    sseConf.Finish()
+else:
+    features['sse'] = False
+
+opts.Save('scache.conf', env)
+Help(opts.GenerateHelpText(env))
+
+# defines and compiler flags
+env.Append(
+    CPPDEFINES = [ '_REENTRANT' ],
+    CCFLAGS    = [ '-Wno-unknown-pragmas' ],
+    CXXFLAGS   = [ '-Wno-deprecated' ]
+    )
+
+# debugging flags
+if env['DEBUG']:
+    env.Append(CCFLAGS = '-g')
+else:
+    env.Append(
+        CCFLAGS = make_opt_flags(env),
+        CPPDEFINES = ['NDEBUG'])
+
+# platform specific
+if PLATFORM == 'darwin':
+    env.Append(
+        CCFLAGS = '-fvisibility=hidden'
+        )
+
+# vectorization
+if features['altivec']:
+    merge_lib_info(env, libraries['altivec'])
+elif features['sse']:
+    merge_lib_info(env, libraries['sse'])
+else:
+    env.AppendUnique(CPPDEFINES = [('SC_MEMORY_ALIGNMENT', 1)])
+
+# ======================================================================
+# Source/plugins
+# ======================================================================
+
+pluginEnv = env.Copy(
+    SHLIBPREFIX = '',
+    SHLIBSUFFIX = PLUGIN_EXT)
+if PLATFORM == 'darwin':
+    pluginEnv['SHLINKFLAGS'] = '$LINKFLAGS -bundle'
+merge_lib_info(pluginEnv, libraries['scplugin'])
+
+def get_sources(env):
+    if env.has_key('PLUGIN_SOURCES') and env['PLUGIN_SOURCES']:
+        fd = open(env['PLUGIN_SOURCES'], "r")
+        sources = fd.readlines()
+        fd.close()
+    else:
+        print "Reading PLUGIN_SOURCES from <stdin>"
+        sources = sys.stdin.readlines()
+    return map(lambda x: x.strip(), sources)
+
+def make_build_file(env, path, ext=""):
+    newpath = os.path.splitext(os.path.basename(path))[0] + ext
+    return os.path.join(env['BUILD_DIR'], newpath)
+
+def make_plugin_target(env, path):
+    name, ext = os.path.splitext(path)
+    if ext == ".dsp":
+        src = env.Faust(make_build_file(env, path), path)
+    else:
+        src = path
+    return env.SharedLibrary(make_build_file(env, path), src)
+
+def make_xml_target(env, path):
+    name, ext = os.path.splitext(path)
+    if ext == '.dsp':
+        if env['BUILD_SC']:
+            xml = env.FaustXML(make_build_file(env, path), path)
+            sc  = env.FaustSC(make_build_file(env, path), xml)
+            if env['BUILD_XML']:
+                return [sc, xml]
+            else:
+                return sc
+        elif env['BUILD_XML']:
+            return env.FaustXML(make_build_file(env, path), path)
+    return []
+
+sources = get_sources(env)
+plugins = map(lambda x: make_plugin_target(pluginEnv, x), sources)
+xml     = map(lambda x: make_xml_target(pluginEnv, x), sources)
+
+# ======================================================================
+# installation
+# ======================================================================
+
+env.Alias('install', env.Install(
+    os.path.join(pkg_extension_dir(INSTALL_PREFIX), env['INSTALLDIR']),
+    plugins + xml))
+
+# ======================================================================
+# cleanup
+# ======================================================================
+
+env.Clean('scrub',
+          Split('config.log scache.conf .sconf_temp .sconsign.dblite'))
+
+# ======================================================================
+# configuration summary
+# ======================================================================
+
+def yesorno(p):
+    if p: return 'yes'
+    else: return 'no'
+
+print '------------------------------------------------------------------------'
+print ' ALTIVEC:                 %s' % yesorno(features['altivec'])
+print ' BUILD_SC:                %s' % yesorno(env['BUILD_SC'])
+print ' BUILD_XML:               %s' % yesorno(env['BUILD_XML'])
+print ' FAUST2SC:                %s' % env['FAUST2SC']
+if env['INSTALLDIR']:
+    print ' INSTALLDIR:              %s' % env['INSTALLDIR']
+print ' DEBUG:                   %s' % yesorno(env['DEBUG'])
+if env.has_key('PLUGIN_SOURCES'):
+    print ' PLUGIN_SOURCES:          %s' % env['PLUGIN_SOURCES']
+else:
+    print ' PLUGIN_SOURCES:          %s' % 'stdin'
+print ' PREFIX:                  %s' % env['PREFIX']
+print ' SC_SOURCE_DIR            %s' % env['SC_SOURCE_DIR']
+print ' SSE:                     %s' % yesorno(features['sse'])
+print ' CROSSCOMPILE:            %s' % yesorno(env['CROSSCOMPILE'])
+print '------------------------------------------------------------------------'
+
+# ======================================================================
+# EOF