+++ /dev/null
-#!/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