
# vim:syntax=python

print '''
C S O U N D 5 - PLUGIN BUILD FILE

SCons build file for Csound 5 Plugins
By Steven Yi <stevenyi at gmail dot com>

based on Csound5 SConstruct file by Michael Gogins

For custom options, run 'scons -h'.
For default options, run 'scons -H'.
If headers or libraries are not found, edit 'custom.py'.
For Linux, run in the standard shell
    with standard Python and just run 'scons'.
For MinGW, run in the MSys shell
    and use www.python.org WIN32 Python to run scons.
'''

import time
import glob
import os
import os.path
import sys
import string
import zipfile
import shutil
import copy

#############################################################################
#
#   UTILITY FUNCTIONS
#
#############################################################################

zipDependencies = []
pluginLibraries = []
executables = []

libs = []
pythonModules = []

def today():
    return time.strftime("%Y-%m-%d", time.localtime())

def getPlatform():
    if sys.platform[:5] == 'linux':
        return 'linux'
    elif sys.platform[:3] == 'win':
        return 'win32'
    elif sys.platform[:6] == 'darwin':
        return 'darwin'
    else:
        return 'unsupported'

def withMSVC():
    if getPlatform() != 'win32':
           return 0
    checkenv = Environment()
    if 'msvc' in checkenv['TOOLS']: # MSVC
           return 1
    else:
           return 0

#############################################################################
#
#   DEFINE CONFIGURATION
#
#############################################################################

# Detect platform.

print "System platform is '" + getPlatform() + "'."
# Define configuration options.
if withMSVC():
 opts = Options('custom-msvc.py')
else:
 opts = Options('custom.py')
opts.Add('CC')
opts.Add('CXX')
opts.Add('LINK')
opts.Add('LINKFLAGS')
opts.Add('customCPPPATH', 'List of custom CPPPATH variables')
opts.Add('customCCFLAGS')
opts.Add('customCXXFLAGS')
opts.Add('customLIBS')
opts.Add('customLIBPATH')
opts.Add('customSHLINKFLAGS')
opts.Add('customSWIGFLAGS')
opts.Add('useDouble',
    'Set to 1 to use double-precision floating point for audio samples.',
    '0')
opts.Add('buildRelease',
    'Set to 1 to build for release (implies noDebug).',
    '0')
opts.Add('noDebug',
    'Build without debugging information.',
    '0')
opts.Add('gcc3opt',
    'Enable gcc 3.3.x or later optimizations for the specified CPU architecture (e.g. pentium3); implies noDebug.',
    '0')
opts.Add('gcc4opt',
    'Enable gcc 4.0 or later optimizations for the specified CPU architecture (e.g. pentium3); implies noDebug.',
    '0')
opts.Add('useLrint',
    'Use lrint() and lrintf() for converting floating point values to integers.',
    '0')
opts.Add('useGprof',
    'Build with profiling information (-pg).',
    '0')
opts.Add('Word64',
    'Build for 64bit computer',
    '0')
if not withMSVC:
   def_intfc = '1'
else:
   def_intfc = '0'

# Define the common part of the build environment.
# This section also sets up customized options for third-party libraries, which
# should take priority over default options.

commonEnvironment = Environment(options = opts, ENV = {'PATH' : os.environ['PATH']})

customCPPPATH = commonEnvironment['customCPPPATH']
commonEnvironment.Prepend(CPPPATH = customCPPPATH)
customCCFLAGS = commonEnvironment['customCCFLAGS']
commonEnvironment.Prepend(CCFLAGS = customCCFLAGS)
customCXXFLAGS = commonEnvironment['customCXXFLAGS']
commonEnvironment.Prepend(CXXFLAGS = customCXXFLAGS)
customLIBS = commonEnvironment['customLIBS']
commonEnvironment.Prepend(LIBS = customLIBS)
customLIBPATH = commonEnvironment['customLIBPATH']
commonEnvironment.Prepend(LIBPATH = customLIBPATH)
customSHLINKFLAGS = commonEnvironment['customSHLINKFLAGS']
commonEnvironment.Prepend(SHLINKFLAGS = customSHLINKFLAGS)
customSWIGFLAGS = commonEnvironment['customSWIGFLAGS']
commonEnvironment.Prepend(SWIGFLAGS = customSWIGFLAGS)

Help(opts.GenerateHelpText(commonEnvironment))

# Define options for different platforms.
if getPlatform() != 'win32':
 print "Build platform is '" + getPlatform() + "'."
else:
 if not withMSVC():
  print "Build platform is 'mingw/msys'"
 else:
  print "Build platform is 'msvc'"

print "SCons tools on this platform: ", commonEnvironment['TOOLS']


commonEnvironment.Prepend(CPPPATH = ['.', './H'])
if commonEnvironment['useLrint'] != '0':
  commonEnvironment.Prepend(CCFLAGS = ['-DUSE_LRINT'])
if commonEnvironment['gcc3opt'] != '0' or commonEnvironment['gcc4opt'] != '0':
  if commonEnvironment['gcc4opt'] != '0':
    commonEnvironment.Prepend(CCFLAGS = ['-ftree-vectorize'])
    cpuType = commonEnvironment['gcc4opt']
  else:
    cpuType = commonEnvironment['gcc3opt']
  commonEnvironment.Prepend(CCFLAGS = ['-fomit-frame-pointer', '-ffast-math'])
  if getPlatform() == 'darwin':
    flags = '-O3 -mcpu=%s -mtune=%s'%(cpuType, cpuType)
  else:
    flags = '-O3 -march=%s'%(cpuType)
  commonEnvironment.Prepend(CCFLAGS = Split(flags))
elif commonEnvironment['buildRelease'] != '0':
  if not withMSVC():
    commonEnvironment.Prepend(CCFLAGS = Split('''
      -O3 -fno-inline-functions -fomit-frame-pointer -ffast-math
    '''))
elif commonEnvironment['noDebug'] == '0':
  if getPlatform() == 'darwin':
    commonEnvironment.Prepend(CCFLAGS = ['-g', '-O2'])
  else:
    if not withMSVC():
      commonEnvironment.Prepend(CCFLAGS = ['-g', '-gstabs', '-O2'])
else:
  commonEnvironment.Prepend(CCFLAGS = ['-O2'])
if commonEnvironment['useGprof'] == '1':
  commonEnvironment.Append(CCFLAGS = ['-pg'])
  commonEnvironment.Append(LINKFLAGS = ['-pg'])
if not withMSVC():
  commonEnvironment.Prepend(CXXFLAGS = ['-fexceptions'])
commonEnvironment.Prepend(LIBPATH = ['.', '#.'])
if commonEnvironment['buildRelease'] == '0':
    commonEnvironment.Prepend(CPPFLAGS = ['-DBETA'])
if commonEnvironment['Word64'] == '1':
    commonEnvironment.Prepend(LIBPATH = ['.', '#.', '/usr/local/lib64'])
    commonEnvironment.Append(CCFLAGS = ['-fPIC'])
else:
    commonEnvironment.Prepend(LIBPATH = ['.', '#.', '/usr/local/lib'])

if commonEnvironment['useDouble'] == '0':
    print 'CONFIGURATION DECISION: Using single-precision floating point for audio samples.'
else:
    print 'CONFIGURATION DECISION: Using double-precision floating point for audio samples.'
    commonEnvironment.Append(CPPFLAGS = ['-DUSE_DOUBLE'])

# Define different build environments for different types of targets.

if not withMSVC():
    commonEnvironment.Prepend(CCFLAGS = "-Wall")

if getPlatform() == 'linux':
    commonEnvironment.Append(CCFLAGS = "-DLINUX")
    commonEnvironment.Append(CPPPATH = '/usr/local/include')
    commonEnvironment.Append(CPPPATH = '/usr/include')
    commonEnvironment.Append(CPPPATH = '/usr/X11R6/include')
    commonEnvironment.Append(CCFLAGS = "-DPIPES")
    commonEnvironment.Append(LINKFLAGS = ['-Wl,-Bdynamic'])
elif getPlatform() == 'darwin':
    commonEnvironment.Append(CCFLAGS = "-DMACOSX")
    commonEnvironment.Append(CPPPATH = '/usr/local/include')
    commonEnvironment.Append(CCFLAGS = "-DPIPES")
    if commonEnvironment['useAltivec'] == '1':
        print 'CONFIGURATION DECISION using Altivec optmisation'
        commonEnvironment.Append(CCFLAGS = "-faltivec")
elif getPlatform() == 'win32':
    commonEnvironment.Append(CCFLAGS = "-D_WIN32")
    commonEnvironment.Append(CCFLAGS = "-DWIN32")
    commonEnvironment.Append(CCFLAGS = "-DPIPES")
    commonEnvironment.Append(CCFLAGS = "-DOS_IS_WIN32")
    if not withMSVC():
        commonEnvironment.Append(CPPPATH = '/usr/local/include')
        commonEnvironment.Append(CPPPATH = '/usr/include')
        commonEnvironment.Append(CCFLAGS = "-mthreads")
    else:
        commonEnvironment.Append(CCFLAGS = "-DMSVC")

# Check for prerequisites.
# We check only for headers; checking for libs may fail
# even if they are present, due to secondary dependencies.

configure = commonEnvironment.Configure()

if not configure.CheckHeader("stdio.h", language = "C"):
    print " *** Failed to compile a simple test program. The compiler is"
    print " *** possibly not set up correctly, or is used with invalid flags."
    print " *** Check config.log to find out more about the error."
    Exit(-1)

if getPlatform() == 'win32':
    commonEnvironment['ENV']['PATH'] = os.environ['PATH']
    commonEnvironment['SYSTEMROOT'] = os.environ['SYSTEMROOT']

# Define macros that configure and config.h used to define.

headerMacroCheck = [
    ['io.h',        '-DHAVE_IO_H'       ],
    ['fcntl.h',     '-DHAVE_FCNTL_H'    ],
    ['unistd.h',    '-DHAVE_UNISTD_H'   ],
    ['stdint.h',    '-DHAVE_STDINT_H'   ],
    ['sys/time.h',  '-DHAVE_SYS_TIME_H' ],
    ['sys/types.h', '-DHAVE_SYS_TYPES_H'],
    ['termios.h',   '-DHAVE_TERMIOS_H'  ]]

for h in headerMacroCheck:
    if configure.CheckHeader(h[0], language = "C"):
        commonEnvironment.Append(CPPFLAGS = [h[1]])

if getPlatform() == 'darwin':
    commonEnvironment.Append(CPPFLAGS = '-DHAVE_DIRENT_H')
elif configure.CheckHeader("dirent.h", language = "C"):
    commonEnvironment.Append(CPPFLAGS = '-DHAVE_DIRENT_H')


def makePlugin(env, pluginName, srcs):
    pluginLib = env.SharedLibrary(pluginName, srcs)
    pluginLibraries.append(pluginLib)
    
    return pluginLib

pluginEnvironment = commonEnvironment.Copy()
#pluginEnvironment.Append(LIBS = ['sndfile'])

if getPlatform() == 'darwin':
    pluginEnvironment.Append(LINKFLAGS = Split('''
        -framework CoreMIDI -framework CoreFoundation -framework CoreAudio
    '''))
    # pluginEnvironment.Append(LINKFLAGS = ['-dynamiclib'])
    pluginEnvironment['SHLIBSUFFIX'] = '.dylib'
    pluginEnvironment.Prepend(CXXFLAGS = "-fno-rtti")

#############################################################################
#
#   DEFINE TARGETS AND SOURCES
#
#############################################################################

# Plugin opcodes.

makePlugin(pluginEnvironment, 'examplePlugin', Split('''
    examplePlugin.c
'''))

