X-Git-Url: https://scm.cri.ensmp.fr/git/Faustine.git/blobdiff_plain/c7f552fd8888da2f0d8cfb228fe0f28d3df3a12c..b4b6f2ea75b9f0f3ca918f5b84016610bf7a4d4f:/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 index 0000000..64f9409 --- /dev/null +++ b/interpretor/preprocessor/faust-0.9.47mr3/tools/scbuilder/scbuilder @@ -0,0 +1,576 @@ +#!/usr/bin/env ruby +# +# File: scbuilder +# Contents: Build script for SuperCollider plugins +# Authors: Stefan Kersten +# 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 " + 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