# Emacs edit mode for this file is -*- python -*-




# Backward compatibility
if not 'Variables' in globals():
    Variables = Options
    BoolVariable = BoolOption

# Some hard-coded settings
pboriname = 'PolyBoRi'
try:
    versionnumber = open('versionnumber', 'r').read().rstrip() + "-0"
    (pboriversion, pborirevision) = versionnumber.split('-')[:2]
    pborifullrevision = (pborirevision.split('.') + ['0', '0', '0'])[:3]
    pborirelease = pborifullrevision[0]
except:
    pboriversion = "0.0"
    pborirevision = "0"
    pborifullrevision = ['0', '0', '0']
    pborirelease = "0"



debname = "polybori-" + pboriversion + '.' + pborirelease

import tarfile

import sys
from os import sep, path
from glob import glob

m4ri=Split("""grayflex.c permutation.c packedmatrix.c strassen.c
misc.c brilliantrussian.c trsm.c mmc.c echelonform.c pls.c pls_mmpf.c""")
m4ri=[path.join("M4RI/m4ri", m) for m in m4ri]

m4ri_inc = 'M4RI'

def ensure_dir(target, env):
    target = env.subst(target)
    if not path.exists(target):
        try:
            os.makedirs(target)
        except:
            # Maybe just a race condition occured, because two processes trixy
            # to generate the directory at the same time. (This I could ignore.)
            if not path.exists(target):
                raise RuntimeError, "Could not mkdir " + target


def pathsplit(p, rest=[]):
    (h,t) = os.path.split(p)
    if len(h) < 1: return [t]+rest
    if len(t) < 1: return [h]+rest
    return pathsplit(h,[t]+rest)

def commonpath(l1, l2, common=[]):
    if len(l1) < 1: return (common, l1, l2)
    if len(l2) < 1: return (common, l1, l2)
    if l1[0] != l2[0]: return (common, l1, l2)
    return commonpath(l1[1:], l2[1:], common+[l1[0]])

def relpath(p1, p2):
    (common,l1,l2) = commonpath(pathsplit(p1), pathsplit(p2))
    p = []
    if len(l1) > 0:
        p = [ ('..' + sep) * len(l1) ]
    p = p + l2

    if len(p) == 0:
        return ''
    return os.path.join( *p )

def env_relpath(env, path, versus):
    return relpath(env.subst(path), env.subst(versus))

Environment.relpath = env_relpath

def preprocessed_substitute(target, source, env):
    def preprocess_at(page):
        import re
        p = re.compile('@([^@\n]*) @', re.VERBOSE)
        return p.sub(r'$\1', page)
        
    substitute_install(target, source, env, preprocess=preprocess_at)
    

# Fix some paths and names
class PathJoiner(object):
    """Generates a valid path from lists of strings, with custom prefix (set at
    initialization). It also changes '/' to correct path separator.""" 
    def __init__(self, *parent):
        self.parent = path.join(*self.validpath(*parent))
    def __call__(self, *args):
        return path.join(self.parent, *self.validpath(*args))
    def validpath(self, *args):
        return [str(elt).replace('/', sep) for elt in args]

[TestsPath, PyPBPath, CuddPath, GBPath, PBPath, DocPath, BuildPath] = \
    [ PathJoiner(fdir)
      for fdir in Split("""testsuite PyPolyBoRi Cudd groebner libpolybori doc
 build""") ]

M4RIPath = PathJoiner('M4RI')
M4RIInc = PathJoiner(M4RIPath('m4ri'))

DataPath = PathJoiner(TestsPath('py/data'))

DebPath = PathJoiner('pkgs/debian')
DebInstPath = PathJoiner('debian')

RPMPath = PathJoiner('pkgs/rpm')
SpecsPath = PathJoiner(RPMPath('SPECS'))

   
# Split lists separated by colons and whitespaces
def SplitColonSep(arg):
    result = []
    for element in Split(arg):
        result += element.split(':')
    return result

def shell_output(*args):
    from subprocess import Popen, PIPE, STDOUT
    process = Popen(args, stdin=None, stdout=PIPE, stderr=STDOUT, env=os.environ)
    return process.communicate()[0].rstrip()


pyroot="pyroot/"
ipbroot = 'ipbori'
guiroot = 'gui'
cudd_name = 'pboriCudd'

[PyRootPath, IPBPath, GUIPath] = [PathJoiner(fdir) for fdir in [pyroot, ipbroot,
                                                                guiroot] ]
try:
	import SCons.Tool.applelink as applelink
except:
	pass
import os

def FinalizePermissions(targets, perm=None):
    def isdll(path):
        return 'dll' in os.path.basename(path).split(os.path.extsep)[1:]
    
    for src in targets:
        path = str(src)
        if not os.path.islink(path):
            if perm is None:
                if os.path.isdir(path):
                    perm = 040755
                else:
                    if os.access(path, os.X_OK) or isdll(path):
                        perm = 0755
                    else:
                        perm = 0644
            env.AddPostAction(src, Chmod(path, perm))
    return targets

def FinalizeExecs(targets):
    return FinalizePermissions(targets, 0755)

def FinalizeNonExecs(targets):
    return FinalizePermissions(targets, 0644)


distribute = 'distribute' in COMMAND_LINE_TARGETS

prepare_deb = 'prepare-debian' in COMMAND_LINE_TARGETS
generate_deb = 'deb' in COMMAND_LINE_TARGETS
deb_generation = prepare_deb or generate_deb
generate_rpm = 'rpm' in COMMAND_LINE_TARGETS
generate_srpm = 'srpm' in COMMAND_LINE_TARGETS
prepare_rpm = 'prepare-rpm' in COMMAND_LINE_TARGETS
rpm_generation = generate_rpm or generate_srpm or prepare_rpm


# Undocumented switches (for debugging foreign platforms)
defaultopts = Variables() # Works only from command line
defaultopts.Add('PLATFORM', "Manually set another platform (unusual)")
defaultopts.Add('TOOLS', "Manually set toolchain (unusual)", converter = Split)   

defaultenv = Environment(ENV = os.environ, options=defaultopts)

# See also: http://trac.sagemath.org/sage_trac/ticket/9872 and #6437
def detect_linker(env):
    import re
    args = env.subst('$CC').split() + ['-Wl,-v']
    if re.search("Binutils|GNU",  shell_output(*args)):
        return "gnu"

    # Non-gnu linker or linux (could be Sun or Intel linker) will return 'posix'.
    return env['PLATFORM']

def detect_compiler(env):
    import re
    args = env.subst('$CC').split() + ['-v']
    if re.search("gcc version",  shell_output(*args)):
        return "gnu"

    # Non-gnu linker or linux (could be Sun or Intel linker) will return 'posix'.
    return env['PLATFORM']

# for gentoo-prefix on OS X
def _fix_dynlib_flags(env):

    if env['PLATFORM']=="darwin":
        return "-Wl,-flat_namespace"
    return ''


def _sonameprefix(env):
    linker = detect_linker(env)
    #print linker, "linker detected!"
    if env['PLATFORM']=="darwin":
        return "-install_name @loader_path/"

    elif (env['PLATFORM'] == "sunos") and (linker == 'sunos'):
        return '-Wl,-h'

    else:
        return '-Wl,-soname,'

# dynamic module flags
def _dynmodule_flags(env):
    """Creates special flags for dynamic libraries, in particular on darwin."""
    if env['PLATFORM'] == "darwin":
        return "-Wl,-undefined -Wl,dynamic_lookup"
    else:
        return ""

def _moduleflags(env):
    if env['PLATFORM']=="darwin":
        python_absolute = shell_output("which", env.subst("$PYTHON"))
        return ["-fvisibility=hidden", "-bundle_loader", python_absolute]

    return []

def _relative_rpath(target, env):
    if not target or env['PLATFORM'] in ["darwin", "cygwin"]:
        return ''

    targetdir = os.path.dirname(env.subst(str(target)))
    libdir = BuildPath(env['DEVEL_LIB_PREFIX'].lstrip(sep))
    relative_path = '\\$$ORIGIN/' + env.relpath(targetdir, libdir)
    return [env['RPATHPREFIX'] + relative_path + env['RPATHSUFFIX'],
            '-z', 'origin']

def scons_version():
    import SCons
    return SCons.__version__.split('.')

def oldstyle_flags():
    return scons_version() < ['0','97','0']


class ExtendedVariables:
    def __init__(self, vars, defaults):
        from weakref import proxy
        vars.AddWithDefaults = self
        self.vars = proxy(vars)
        self.defaults = defaults
    def __call__(self, varname, *args, **kwds):   
        self.vars.Add(varname, *args, **kwds)
        self.vars.Add('DEFAULT_' + varname, 
                      "defaults appended to " + repr(varname),
                      self.defaults[varname])

pbori_cache_macros=["PBORI_UNIQUE_SLOTS","PBORI_CACHE_SLOTS","PBORI_MAX_MEMORY"]

def setup_env(defaultenv):

    opts = Variables('custom.py')

    ExtendedVariables(opts, defaultenv)
    
    # Define option handle, may be changed from command line or custom.py
    opts.Add('CXX', 'C++ Compiler (inherited from SCons)',
             defaultenv['CXX'])
    opts.Add('CC', 'C Compiler (inherited from SCons)',
             defaultenv['CC'])

    opts.Add('SHCXX', 
             'C++ Compiler (preparing shared libraries; inherited from SCons)',
             defaultenv['SHCXX'])
    opts.Add('SHCC', 
             'C Compiler (preparing shared libraries; inherited from SCons)',
             defaultenv['SHCC'])

    opts.Add('PYTHON', 'Python executable', "python$PROGSUFFIX")

    opts.Add('LIBPATH', 'list of library paths (colon or whitespace separated)',
             defaultenv.get('LIBPATH', []), converter = SplitColonSep)
    opts.Add('CPPPATH', 'list of include paths (colon or whitespace separated)',
             defaultenv.get('CPPPATH', []), converter = SplitColonSep)

    opts.Add('TEST_CPPPATH', 'list of include paths for tests (colon or whitespace separated)',
             '', converter = SplitColonSep)

    opts.Add('CPPDEFINES', 'list of preprocessor defines (whitespace separated)',
             defaultenv.get('CPPDEFINES',[]) + ['PBORI_NDEBUG'], converter = Split)


    if oldstyle_flags() :
        defaultenv.Append(CCFLAGS=["-std=c99", "$M4RI_CFLAGS"])
        defaultenv.Append(CXXFLAGS=["-std=c++98", "$M4RI_CFLAGS", 
                                    "-ftemplate-depth-100"])
        for (var, help, default) in [('CCFLAGS', "C compiler flags", ["-O3"]),
                                     ('CXXFLAGS', "C++ compiler flags", ["-O3"])]:
            opts.AddWithDefaults(var, help, default, converter=Split)

    else:
        defaultenv.Append(CCFLAGS=["$M4RI_CFLAGS"])
        defaultenv.Append(CFLAGS=["-std=c99"])
        defaultenv.Append(CXXFLAGS=["-std=c++98", "-ftemplate-depth-100"])

        for (var, help, default) in [('CCFLAGS', "C/C++ compiler flags", ["-O3"]),
                                     ('CFLAGS', "C compiler flags", []),
                                     ('CXXFLAGS', "C++ compiler flags", [])]:
            opts.AddWithDefaults(var, help, default, converter=Split)


    opts.Add('M4RI_CFLAGS', "C compiler flags for M4RI", converter = Split) 


    defaultenv.Append(LINKFLAGS=['${_fix_dynlib_flags(__env__)}', 
                                 '${_relative_rpath(TARGET, __env__)}'])
    defaultenv.Append(SHLINKFLAGS=['$SONAMEFLAGS'])
    defaultenv.Append(LDMODULEFLAGS=['${_moduleflags(__env__)}'])
    defaultenv.Append(LIBS=[])

    opts.AddWithDefaults('LINKFLAGS', 
                         "Custom linker flags (e.g. '-s' for stripping)", [],
                         converter=Split)

    opts.AddWithDefaults('SHLINKFLAGS', 'Shared libraries link flags.', [],
                         converter=Split)

    opts.AddWithDefaults('LDMODULEFLAGS',
                         'Dynamic module compile flags', [], converter=Split)

    for flag in Split("""SHCCFLAGS SHCFLAGS SHCXXFLAGS FRAMEWORKS"""):
        if defaultenv.has_key(flag):
            opts.AddWithDefaults(flag, "flags inherited from SCons",
                                 [], converter=Split)
        else:
            print "Flags", flag, "not in default environment!"


    opts.AddWithDefaults('LIBS', 'custom libraries needed for build', [],
                         converter = Split)
    opts.Add('GD_LIBS', 'Library gb and its dependencies (if needed)', 
             ["gd"], converter = Split)

    opts.Add('PREFIX', 'installation prefix directory', '$DESTDIR/usr/local')
    opts.Add('EPREFIX','executables installation prefix directory', '$PREFIX/bin')

    opts.Add('INSTALLDIR', 'end user installation directory',
             '$PREFIX/share/polybori')
    opts.Add('DOCDIR', 'documentation installation directory',
             '$INSTALLDIR/doc')
    opts.Add('MANDIR', 'Man-pages installation directory',
             '$PREFIX/man')
    opts.Add('ICONDIR', 'Icon installation directory', '$PREFIX/share/pixmaps')
    opts.Add('PYINSTALLPREFIX',
             'python modules directory (default is built-in site)', '$DESTDIR$PYTHONSITE')

    opts.Add('DEVEL_PREFIX',
             'development version installation directory','$PREFIX' )
    opts.Add('DEVEL_INCLUDE_PREFIX',
             'development version header installation directory',
             '$DEVEL_PREFIX/include' )
    opts.Add('DEVEL_LIB_PREFIX',
             'development version library installation directory',
             '$DEVEL_PREFIX/lib' )

    opts.Add(BoolVariable('M4RI_RPM',
                          'Assume rpm knows about M4RI', False))   

    opts.Add(BoolVariable('HAVE_DOXYGEN',
                        'Generate doxygen-based documentation, if available', '$DOCS'))
    opts.Add(BoolVariable('HAVE_PYTHON_EXTENSION',
                        'Build python extension, if possible', True))

    opts.Add('BOOST_PYTHON',
             'Name of Boost-python library to link with', 'boost_python')

    opts.Add('BOOST_TEST',
             'Name of Boost unit test framework library to link with',
             'boost_unit_test_framework')


    opts.Add(BoolVariable('RELATIVE_SYMLINK',
                          'Use relative symbolic links on install', True))

    opts.Add(BoolVariable('HAVE_L2H', 'Switch latex2html on/off (deprecated)', 
                          False))
    opts.Add(BoolVariable('HAVE_HEVEA', 'Switch hevea on/off (deprecated)', False))
    opts.Add(BoolVariable('HAVE_TEX4HT', 'Switch tex4ht on/off', '$DOCS'))


    opts.Add(BoolVariable('HAVE_PYDOC', 'Switch python doc generation on/off',
                          True))
    opts.Add(BoolVariable('EXTERNAL_PYTHON_EXTENSION', 'External python interface',
                          False))

    opts.Add(BoolVariable('USE_TIMESTAMP', 'Use timestamp on distribution', True))
    opts.Add(BoolVariable('SHLIBVERSIONING',
                          'Use libtool-style versionated shared library', True))

    opts.Add('SONAMEPREFIX', 'Prefix for compiler soname command.', 
             '${_sonameprefix(__env__)}')
    opts.Add('SONAMESUFFIX','Suffix for compiler soname command.', '')

    opts.Add('SONAMEFLAGS',
             'Shared libraries link flags.',
             ['${_sonamecmd(SONAMEPREFIX, TARGET, SONAMESUFFIX, __env__)}'])


    opts.Add('INSTALL_NAME_DIR',
             'Path to be used for dylib install_name (darwin only)',
             '@loader_path')

    opts.Add('SHLIBVERSIONSUFFIX',
             'Shared libraries suffix for library versioning.',
             '-' + pboriversion +
             defaultenv['SHLIBSUFFIX'] + '.$LIBRARY_VERSION')



    opts.Add(BoolVariable('FORCE_HASH_MAP', "Force the use of gcc's deprecated " +
    "hash_map extension, even if unordered_map is available (avoiding of buggy " +
    "unordered_map)", False))

    opts.Add('RPATH', "rpath setting", '', converter = SplitColonSep)


    for m in pbori_cache_macros:
        opts.Add(m, 'PolyBoRi Cache macro value: '+m, '')


    for var in Split("""CCCOM CXXCOM SHCCCOM SHCXXCOM SHLINKCOM LINKCOM LINK SHLINK
    SHLIBPREFIX LIBPREFIX SHLIBSUFFIX LIBSUFFIX"""):
        if defaultenv.has_key(var):
            opts.Add(var, 
                     "inherited from SCons", defaultenv[var])
    else:
            if var != "LIBSUFFIX":
                print "Variable", var, "not in default environment!"

    opts.Add('LIBRARY_VERSION', "libtool-style library version", 
             '.'.join(pborifullrevision))

    opts.Add('CONFFILE', "Dump settings to file, if given", '')
    opts.Add('PKGCONFIGPATH', 
             "Write settings to pkg-config file in path, if given", '')

    opts.Add('DESKTOPPATH', 
             "Generate .desktop file in given path, if given", '')

    opts.Add('DESTDIR', "Temporary installation directory, if given", '')

    opts.Add('M4RIURL', 
             """Source destinations for missing m4ri download: 
space-separated list of local files or pairs <URL>#<MD5>, '' skips""",
             """m4ri-20121224.tar.gz
             http://m4ri.sagemath.org/downloads/m4ri-20121224.tar.gz#1a2a59b547fed9e825ff9135a21ba53b""",
             converter=Split)

    opts.Add(BoolVariable('DOCS',
                          "Build/install platform-independent documantation",
                          True))
    
    opts.Add('PLATFORM', "Manually set another platform (unusual)",
             defaultenv['PLATFORM'])

    tools =  defaultenv['TOOLS'] + ["disttar", "doxygen"]


    # Get paths and related things from current environment os.environ
    # note: We cannot avoid those due to non-standard system setups,
    #       also we do not know which variables are used in general

    return (Environment(ENV = os.environ, options = opts, tools = tools, 
                        toolpath = '.'), opts, tools)


(env, opts, tools) = setup_env(defaultenv)

if defaultenv['PLATFORM'] == "sunos":  # forcing gcc, keeping linker
    def is_gnu():
        compilerenv = Environment(ENV = os.environ, options = opts)
        return (detect_compiler(compilerenv)  == 'gnu',
                detect_linker(compilerenv)  == 'gnu')

    (is_gcc, is_gnulink) = is_gnu()

    tools = [tool for tool in defaultenv['TOOLS']]

    if is_gcc:
        for arg in ['default', 'suncc', 'sunc++', 'sunar']:
            if arg in tools:
                tools.remove(arg)
        tools +=  [ 'gcc', 'g++', 'ar']

    if is_gnulink:
        if 'sunlink' in tools:
            tools.remove('sunlink')
        tools +=  ['gnulink']
    else:
        if 'gnulink' in tools:
            tools.remove('gnulink')
        tools +=  ['sunlink']
    if tools != defaultenv['TOOLS']:    

        platform_opts = Variables(args={'PLATFORM': defaultenv['PLATFORM']})
        defaultenv = Environment(ENV=os.environ, tools=tools,
                                 options=platform_opts)

        (env, opts, tools) = setup_env(defaultenv)


# Monkey patching Install/InstallAs to fix permissions on install
_env_install = env.Install
_env_installas = env.InstallAs

def _env_install_final(env, *args):
    return FinalizePermissions(_env_install(env, *args))

def _env_installas_final(env, *args):
    return FinalizePermissions(_env_installas(env, *args))

_env_install_final.__doc__ = env.Install.__doc__
_env_installas_final.__doc__ = env.InstallAs.__doc__

env.Install = _env_install_final
env.InstallAs = _env_installas_final


# Another monkey patch: Ensure that necessary flags are appended 
# (explicitely set DEFAULT_<flags>="" if defaults should be removed)
for key in env.Dictionary().keys():
    if key.startswith('DEFAULT_'):
        env.AppendUnique(**{key.replace('DEFAULT_',''): ['$' + key]})

# Extract some option values
HAVE_DOXYGEN = env['HAVE_DOXYGEN'] and ("doxygen" in tools)
HAVE_PYTHON_EXTENSION = env['HAVE_PYTHON_EXTENSION']

USERLIBS = list(env.get('LIBS', []))

# Skipping doxygen-based docu, if no doxygen is found.
if HAVE_DOXYGEN:
    HAVE_DOXYGEN = env.Detect('doxygen')
    if not HAVE_DOXYGEN:
        print "Doxygen not found, skipping C++-documentation generation!"

# soname related stuff
def _sonamecmd(prefix, target, suffix, env = env):
    """Creates soname."""

    target = str(env.subst(target))
    import re
    soPattern = re.compile('(.*)\.[0-9]*\.[^.]*$', re.I|re.S)
    soname = soPattern.findall(path.basename(target))

    if len(soname) > 0:
        return prefix + soname[0] + suffix   
    else:
        if env['PLATFORM']=="darwin":
            return prefix + path.basename(target) + suffix

        return ''
    


env['_sonameprefix'] = _sonameprefix
env['_sonamecmd'] = _sonamecmd
env['_fix_dynlib_flags'] = _fix_dynlib_flags
env['_moduleflags'] = _moduleflags
env['_relative_rpath'] = _relative_rpath  
env['_dynmodule_flags'] = _dynmodule_flags


# config.h generator
def config_h_build(target, source, env):
    """ config_h building..."""
    def define_line(name, value):
        return """#ifndef %(name)s
#define %(name)s %(value)s
#endif
""" % dict(name=name, value=value)
    
    from string import join
    macros = [elt.split('=') + [''] for elt in env['CPPDEFINES'] ]
    for macro in pbori_cache_macros:
        if env.get(macro, None): macros += [ (macro,  env[macro]) ]
    
    config_defs =  join([define_line(elt[0], elt[1]) for elt in macros], '')
    config_h_in = """/* File: %(target)s
 * Automatically generated by PolyBoRi %(version)s */
#ifndef polybori_config_h_
#define polybori_config_h_

%(defs)s
#endif /* polybori_config_h_ */
"""
    config_ver = pboriversion + '.' + pborirevision

    for a_target, a_source in zip(target, source):
        config_h = file(str(a_target), "w")
        conf_repl = dict(target=a_target, version=config_ver, defs=config_defs)
        config_h.write(config_h_in % conf_repl)
        config_h.close()

def config_h_message(*args):
    return "writing config.h..."

config_h = env.Command(PBPath('include/polybori/config.h'),
                       'SConstruct',
                       action = env.Action(config_h_build, 
                                           config_h_message))
env.AlwaysBuild(config_h)

class PythonConfig(object):
    def __init__(self, python_executable):
        def querycmd(arg):
            from subprocess import Popen, PIPE, STDOUT
            process = Popen([self.python], stdin=PIPE, stdout=PIPE, stderr=STDOUT,
                           env=os.environ)
            return process.communicate("from distutils.sysconfig import *\n" +
                                       "print " + arg + "\n")[0].strip()


        self.python = python_executable
        self.version = querycmd("get_python_version()")
        self.major = self.version.split('.')[0]
        self.sitedir = querycmd("get_python_lib()")
        self.libdir = querycmd("get_config_vars()['LIBDIR']")
        self.incdir = querycmd("get_python_inc()")
        self.staticlibdir = querycmd("get_config_vars()['LIBPL']")
        self.libs = querycmd("get_config_vars()['LIBS']")
        self.module_suffix = querycmd("get_config_vars()['SO']")

        self.libs = self.libs.split()
        if env['PLATFORM']=="darwin":
            #workaround for -framework, CoreFoundation entries...
            self.libs=[l for l in self.libs if l.startswith('-l')]
        
        self.libs=[l.replace('-l','') for l in self.libs]
        self.libname = 'python' + str(self.version)

pyconf = PythonConfig(env.subst("$PYTHON"))

env.AppendUnique(PYTHONSITE = pyconf.sitedir)

have_l2h = have_t4h = False
external_m4ri = False
GD_LIBS = []
BOOST_TEST = env['BOOST_TEST']
dylibs = []
stlibs = []

def check_variants(conf, libname, header, generators, priority):
    if not libname:
        return None
    if header:
        def checklib(name):
            return conf.CheckLibWithHeader(name, header, 'c++', autoadd=0)
    else:
        def checklib(name):
            return conf.CheckLib(name, autoadd=0)

    names=[[]]

    for idx in priority:
        gen = generators[idx]
        names += [name + [(idx, elt)] for name in names for elt in gen]

    for elt in names:
        namelist = map(lambda x:x[1], sorted(elt, key=lambda x:x[0]))
        name = '-'.join([libname] + namelist);
        if checklib(name):
            return name
            
    return None

def check_boost_variants(conf, libname, header=None):
    return check_variants(conf, libname, header,
                          [[pyconf.version], ['gcc'], ['mt', 'mt-p'], 
                           ['_'.join(map(str,  env['BOOST_VERSION'][0:nlen]))
                            for nlen in [2,3] ] ], [3,0,2,1])

######################################################################
# Paths
######################################################################

InstPyPath = PathJoiner(env['PYINSTALLPREFIX'])

DevelInstPath = PathJoiner(env['DEVEL_PREFIX'])
PBInclPath = PathJoiner(PBPath('include/polybori'))
DevelInstInclPath = PathJoiner(env['DEVEL_INCLUDE_PREFIX'], 'polybori')
DevelInstLibPath = PathJoiner(env['DEVEL_LIB_PREFIX'])

BuildLibPath = PathJoiner(BuildPath(DevelInstLibPath().lstrip(sep)))
BuildInclPath = PathJoiner(BuildPath(DevelInstInclPath().lstrip(sep)))
BuildInclTopPath = PathJoiner(BuildPath(env.subst('$DEVEL_INCLUDE_PREFIX').lstrip(sep)))
BuildPyPBPath = PathJoiner(BuildPath(InstPyPath('polybori/dynamic').lstrip(sep)))

#######################################################################

m4ri_png = False
retrieve_m4ri = False
libm4ri = []

if not env.GetOption('clean'):
    def BoostVersion(context):
        # Boost versions are in format major.minor.subminor
        context.Message('Detecting Boost version... ')
        (result, values) = context.TryRun("""
        #include <boost/version.hpp>
        #include <iostream>
        int main() {
            std::cout << BOOST_VERSION;
            return 0;
        }
        """, '.cpp')
        result = (result == 1)
        if result:
            values = (int(values[0:-5]), int(values[-5:-2]), int(values[-2:-1]))
            context.Display('.'.join(map(str, values)) + '... ')
        else:
            values = [0]*3

        env.Append(BOOST_VERSION=values)
        context.Result(result)
        return result

    def CheckSizeOfTypes(context):
        context.Message('Detecting type sizes... ')
        test_src_sizeof =  """
        #include <stdio.h>
        int main(int argc, char **argv) {
          printf("SIZEOF_VOID_P=%u SIZEOF_INT=%u SIZEOF_LONG=%u",
            (unsigned)sizeof(void*), (unsigned)sizeof(int), (unsigned)sizeof(long));
          return 0;
        }
        """
        (result, values) = context.TryRun(test_src_sizeof, '.c')
        result = (result == 1)
        if result:
            context.Display('got ' + values + '...')
            env.Append(CPPDEFINES=Split(values))
        context.Result(result)
        return result

    def CheckLongLong(context):
        context.Message('Checking whether C++ knows about long long... ')
        test_src_longlong =  """
        int main(int argc, char **argv) {
          long long val = 0LL;
          return (int)val;
        }
        """
        (result, values) = context.TryRun(test_src_longlong, '.cc')
        result = (result == 1)
        context.Result(result)
        return result



    def M4RIConfig(context, url, hash, tmpdir):

                def userAction(target,source,env):
                    import urllib
                    (tmpfile, headers) = urllib.urlretrieve(url, target[0].abspath)
                    if hash or not path.exists(env.File(url).abspath):
                        import hashlib
                        m = hashlib.md5()
                        for elt in open(tmpfile,"rb").readlines(): m.update(elt)
                        if m.hexdigest() != hash: return "hash mismatch"

                    import tarfile
                    tar = tarfile.open(tmpfile)
                    if not path.exists(tmpdir): ensure_dir(tmpdir, env)
                    tar.extractall(tmpdir)
                    tar.close()
                    env.Execute(Move(path.join(tmpdir, path.basename(url)), tmpfile))
                    return None

                context.Message("  Downloading m4ri sources from " + repr(url) \
                                + " to " + repr(tmpdir) + " ... ")
                ret = context.TryAction(action=Action(userAction))[0]
                context.Result(ret)
                if ret == 1:
                    context.Message("  Configuring m4ri...")
                    ret = context.TryAction(" ".join(["cd", 
                                            path.join(tmpdir, path.basename(url).split('.')[0]),
                                            "; ./configure",
                                            "--prefix=" + env.Dir(BuildPath()).abspath,
                                            "--libdir=" + env.Dir(BuildLibPath()).abspath,
                                            "--includedir=" + \
                                            env.Dir(BuildInclTopPath()).abspath]))[0]
                    context.Result( ret )

                return ret

    def GuessM4RIFlags(context, external):
        context.Message('Guessing m4ri compile flags... ')
        if not external:
            if not os.path.exists(M4RIInc('config.h')):
                context.Message("Abusing m4ri's configure to get headers... ")
                Execute("cd M4RI; ./configure --prefix=$PREFIX; cd -")
        
        test_src =  """
        #include <m4ri/%s>
        #include <stdio.h>
        int main(int argc, char **argv) {
        #ifdef __M4RI_SIMD_CFLAGS
          /* get relevant compile flags of M4RI */
          printf(__M4RI_SIMD_CFLAGS);
          printf(" ");
        #elif defined(__M4RI_CFLAGS)
          /* fall back: get compile flags of M4RI */
          printf(__M4RI_CFLAGS);
          printf(" ");
        #else
          /* fall back: test for possible current and future configurations */
          %s
        #endif
          return 0;
        }
        """  %  \
        ("%s", ''.join(["""
        #if (defined(__M4RI_HAVE_%(macro)s) && (__M4RI_HAVE_%(macro)s)) || \
          defined(HAVE_%(macro)s)
          printf("-m%(option)s ");
        #endif""" % \
        dict(macro=opt.replace('.','_').upper(), option=opt) for opt in \
            Split("sse sse2 sse3 sse4 sse4.1 sse4.2 sse4a ssse3 mmx 3dnow") ]) )
        (result, values) = context.TryRun(test_src % "m4ri_config.h", '.c')
	if result != 1:
            (result, values) = context.TryRun(test_src % "config.h", '.c')

        result = (result == 1)
        if result:
            context.Display(values)
            env.Append(M4RI_CFLAGS=Split(values))

        context.Result(result)
        return result

    conf = Configure(env, 
                     custom_tests = {'CheckSizeOfTypes': CheckSizeOfTypes,
                                     'CheckLongLong': CheckLongLong,
                                     'GuessM4RIFlags': GuessM4RIFlags,
                                     'BoostVersion': BoostVersion,
                                     'M4RIConfig': M4RIConfig })

    if not conf.CheckSizeOfTypes():
        print "Could not detect type sizes (maybe compile/link flags " + \
            "trouble)! Exiting."
        Exit(1)

    if conf.CheckLongLong():
        env.Append(CPPDefines='PBORI_HAVE_LONG_LONG')

    if env['FORCE_HASH_MAP']:
        if conf.CheckCXXHeader('ext/hash_map'):
            env.Append(CPPDEFINES=["PBORI_HAVE_HASH_MAP"])  
    else:
        if conf.CheckCXXHeader('unordered_map'):
            env.Append(CPPDEFINES=["PBORI_HAVE_UNORDERED_MAP"])
        elif conf.CheckCXXHeader('tr1/unordered_map'):
            env.Append(CPPDEFINES=["PBORI_HAVE_TR1_UNORDERED_MAP"])
        elif conf.CheckCXXHeader('ext/hash_map'):
            env.Append(CPPDEFINES=["PBORI_HAVE_HASH_MAP"])  

    extern_python_ext = env['EXTERNAL_PYTHON_EXTENSION']
    if HAVE_PYTHON_EXTENSION or extern_python_ext:
        env.Append(CPPPATH=[pyconf.incdir])
        env.Append(LIBPATH=[pyconf.libdir, pyconf.staticlibdir])

    env.Prepend(CPPPATH=[PBPath('include'), GBPath('include')])
    env.Append(CPPDEFINES=["PBORI_HAVE_M4RI"])


    if HAVE_PYTHON_EXTENSION:
        if not (conf.CheckLib(pyconf.libname, autoadd=0)):
            print "Python library not available (needed for python extension)!"
            HAVE_PYTHON_EXTENSION = False

    if HAVE_PYTHON_EXTENSION:
        if not (conf.CheckCXXHeader(path.join('boost', 'python.hpp'))):
            print "Developer's version of boost/python not available ",
            print "(needed for python extension)!"
            HAVE_PYTHON_EXTENSION = False


    conf.BoostVersion() 
    if HAVE_PYTHON_EXTENSION:
        store_libs =[elt for elt in env["LIBS"]]
        env.Append(LIBS=pyconf.libname)
                
        BOOST_PYTHON = check_boost_variants(conf, env['BOOST_PYTHON'],
                                            path.join('boost', 'python.hpp'))
        if BOOST_PYTHON is None:
            
            print "Warning Boost/Python library BOOST_PYTHON =",
            print repr(env['BOOST_PYTHON']), "(or variants)  not available " +\
                  "(needed for python extension)!"
            HAVE_PYTHON_EXTENSION = False
        env['BOOST_PYTHON'] = BOOST_PYTHON         

        env["LIBS"] = store_libs

    BOOST_TEST = check_boost_variants(conf, env['BOOST_TEST'])
    if BOOST_TEST is None:
         print "Warning Boost/unit test framework library BOOST_TEST =",
         print repr(env['BOOST_TEST']), " not available. Skipping tests."
    env['BOOST_TEST'] = BOOST_TEST

    have_l2h = env['HAVE_L2H'] and env.Detect('latex2html')

    tex_to_ht = 'hevea'

    if not have_l2h:
        have_t4h = env['HAVE_HEVEA'] and env.Detect('hevea')
        t4h_opts = ''
        if not have_t4h:
            have_t4h = env['HAVE_TEX4HT'] and env.Detect('htlatex')
            tex_to_ht = 'htlatex'

            if not have_t4h:
                print "Warning: No LaTeX to html converter found,",
                print "Tutorial will not be installed"

    external_m4ri = conf.CheckLib('m4ri', autoadd=0)
    if external_m4ri:
        libm4ri = ['m4ri']
        if conf.CheckFunc('testing_m4ri_PNGs', """
        #include <m4ri/io.h>
        #if defined(__M4RI_HAVE_LIBPNG) && __M4RI_HAVE_LIBPNG
        #define testing_m4ri_PNGs() 
        #else
        #define testing_m4ri_PNGs() fail fail fail
        #endif """):
            m4ri_png = True
           
    else:
            tmpdir = BuildPath('tmp')
            urls = [(elt + '#').split('#')[:2] for elt in Split(env.subst('$M4RIURL'))]
            for (url, hash) in urls:
                m4ri_name = path.basename(url).split('.')[0]
                m4ri_dir = path.join(tmpdir, m4ri_name)

                if conf.M4RIConfig(url, hash, tmpdir):
                    env.Prepend(CPPPATH=m4ri_dir)
                    libm4ri = ['m4ri']
                    external_m4ri = retrieve_m4ri = m4ri_png = True
                    env['PB_M4RI_SRC'] = m4ri_name + '.tar.gz'
                    env['M4RIVERSION'] = m4ri_name[-8:]
                    break
            if not external_m4ri:
                print "  Cannot build without m4ri!"
                Exit(1)

    if m4ri_png:
        env.Append(CPPDEFINES=["PBORI_HAVE_M4RI_PNG"])
        for suffix in ['', '12', '13', '10', '11']:
            if conf.CheckLib('png' + suffix, autoadd=0):
                GD_LIBS = ['png' + suffix]
            break  

    conf.GuessM4RIFlags(external_m4ri)

    if not m4ri_png:
        gdlibs = env["GD_LIBS"]
        if gdlibs and conf.CheckCHeader("gd.h"):
            store_libs = [elt for elt in env["LIBS"]]
            env.Append(LIBS=gdlibs[1:])

            if conf.CheckLib(gdlibs[0], autoadd=0):
                env["LIBS"] = store_libs
                env.Append(LIBS=gdlibs)
                if conf.CheckFunc("testing_PNGs",
                                  "#include<gd.h>\n#define testing_PNGs() gdImagePng(NULL,NULL) "):
                    env.Append(CPPDEFINES=["PBORI_HAVE_GD"])
                    GD_LIBS = gdlibs
                else:
                    print "libgd is available, but could not generate png file -",\
                      "dependencies in GD_LIBS missing? -", \
                      "Skipping gd-based optional features."
            env["LIBS"] = store_libs


    env = conf.Finish()

else: # when cleaning
    # Work around bug in older SCons (didn't remove symlinks to files)
    if scons_version() < ['1','3','0']:
        for elt in glob('*' + env['SHLIBSUFFIX'] + "*") + \
                [PyRootPath('polybori/dynamic')]:
            if os.path.islink(elt):
                os.remove(elt)

    # things not handled by builders
    for elt in [PyRootPath('polybori/dynamic')]:
        if os.path.exists(elt) and os.path.islink(elt):
            os.remove(elt)

# end of not cleaning

env.Clean('.',  ['build'] + glob("config.log") + glob(".sconf*") + \
          glob(PBPath('*' + env['LIBSUFFIX'])) + \
          glob(GBPath('*' + env['LIBSUFFIX'])) + \
          glob('*' + env['SHLIBSUFFIX'] + "*") + glob('*.pyc')  )

for root, dirs, files in os.walk('build'):

    for elt in [path.join(root, dname) for dname in dirs + files]:
        # Work around bug in older SCons (didn't remove symlinks to files)
        if scons_version() < ['1','3','0'] and os.path.islink(elt) \
                and env.GetOption('clean'):
            os.remove(elt)
        else:
            env.Clean(root, elt)

env.Alias('build', env.Dir('build'));

have_pydoc = env['HAVE_PYDOC']
# Platoform-independent stuff

env['PBVERSION'] = pboriversion
env['PBRELEASE'] = pborirevision

if env['M4RI_RPM']:
    env['PB_M4RI_RPM'] = "1"
else:
    env['PB_M4RI_RPM'] = "0"
    

# Resoruces for including anything into the PyPolyBoRi shared library
shared_resources = []

# Builder for symlinks
def build_symlink(target, source, env):

    target = target[0]
    targetdir = target.dir.abspath
    targetpath = target.abspath
    target = target.path
    source = source[0].abspath

    if env['RELATIVE_SYMLINK'] :
        source = env.relpath(targetdir, source)
    if not source:
        source = '.'

    print "Symlinking from", source, "to", target
   
    if path.exists(targetpath):
        os.remove(targetpath)
    os.symlink(source, targetpath)

    return None

symlinkbld = Builder(action = build_symlink)

env.Append(BUILDERS={'SymLink' : symlinkbld})

def shared_object(o, **kwds):
    return env.SharedObject(o, **kwds)



######################################################################
# Stuff for building Cudd library
######################################################################

#env.Append(CPPDEFINES=["PBORI_HAVE_IEEE_754"])


cudd_headers = [ CuddPath('cudd/' + fname + '.h') for fname in Split("""
cuddInt cudd util""") ] + [PBInclPath('cudd/prefix' + fname + '.h')
                      for fname in ['', '_internal'] ]
    
cudd_resources = [CuddPath('cudd/cudd' + elt) for elt in Split("""
API.c Cache.c Init.c LCache.c Ref.c Table.c ZddFuncs.c ZddSetop.c""") ]

cudd_shared = shared_object(cudd_resources, CPPPATH = env['CPPPATH'] + [CuddPath()])

#libCudd = env.StaticLibrary(CuddPath(cudd_name), cudd_resources)

shared_resources += cudd_shared

###################
# End of Cudd stuff
###################


def SymlinkReadableLibname(files):
    """ Generate symbolik link with more readable library name."""
    
    suffix = env.subst('$SHLIBVERSIONSUFFIX')
    simplesuffix = env.subst('$SHLIBSUFFIX')
    result = []
    import re
    soPattern = re.compile('(.*)\.[0-9]*\.[0-9]*$', re.I|re.S)
    sonameversion = soPattern.findall(path.basename(env.subst('$LIBRARY_VERSION')))[0]
    
    for fname in files:
        fname = str(fname)
        soname = soPattern.sub(r'\1', fname)
        versionname = fname.replace('.' + env.subst('$LIBRARY_VERSION'), '')
        simple = fname.replace(suffix, simplesuffix)

        for (dest, src) in [(soname, fname), (versionname, soname),
        (simple, versionname)]:
            if (dest != src):
                result += env.SymLink(dest, src)
    return result

def VersionatedSharedLibrary(*args, **kwds):

    kwds['SHLIBSUFFIX'] = env.subst('$SHLIBVERSIONSUFFIX')

    sharedlib = env.SharedLibrary
    return sharedlib(*args, **kwds)

slib = env.SharedLibrary
if env['SHLIBVERSIONING']:
    slib = VersionatedSharedLibrary


######################################################################
# Stuff for building PolyBoRi's C++ part
######################################################################

pb_src=Split("""BoolePolyRing.cc BooleEnv.cc BoolePolynomial.cc BooleVariable.cc
    CCheckedIdx.cc CErrorInfo.cc PBoRiError.cc CCuddFirstIter.cc
    BooleMonomial.cc BooleSet.cc LexOrder.cc CCuddLastIter.cc 
    BooleExponent.cc DegLexOrder.cc DegRevLexAscOrder.cc
    pbori_routines.cc BlockDegLexOrder.cc BlockDegRevLexAscOrder.cc""")

pb_src=[PBPath('src', source) for source in pb_src]

libpb_name = 'polybori'
libpb_name_static = libpb_name

libpb=env.StaticLibrary(PBPath(libpb_name_static), pb_src + cudd_resources, 
                        CCFLAGS=['-g'] + env['CCFLAGS'])


if isinstance(libpb,list):
    libpb=libpb[0]


pb_shared = shared_object(pb_src)
shared_resources += pb_shared

libpbShared = slib(BuildLibPath(libpb_name), list(shared_resources))
pb_symlinks = SymlinkReadableLibname(libpbShared)

env.Clean([libpb] + pb_shared, config_h)

######################################################################
# Stuff for building Groebner library
######################################################################

gb_src=Split("""groebner.cc LiteralFactorization.cc
LiteralFactorizationIterator.cc randomset.cc pairs.cc
groebner_alg.cc FGLMStrategy.cc polynomial_properties.cc LexBucket.cc
dlex4data.cc dp_asc4data.cc lp4data.cc nf.cc interpolate.cc GroebnerStrategy.cc
PairManager.cc PolyEntry.cc ReductionStrategy.cc MatrixMonomialOrderTables.cc""")
gb_src = [GBPath('src', source) for source in gb_src]

if not(external_m4ri):
   gb_src += m4ri
   env.Clean(M4RIPath(), [M4RIPath(elt) for elt in Split(""".deps Makefile
   config.status libtool m4ri.pc m4ri/config.h m4ri/m4ri_config.h m4ri/stamp-h1
   testsuite/Makefile""")])
   
libgb_name = libpb_name + '_groebner'
libgb_name_static = libgb_name

gb=env.StaticLibrary(GBPath(libgb_name_static), gb_src, 
                     CCFLAGS=['-g'] + env['CCFLAGS'])

#print "gb:", gb, dir(gb)
#sometimes l seems to be boxed by a list
if isinstance(gb,list):
    gb=gb[0]

gb_shared = shared_object(gb_src)#env.SharedObject(gb_src)
shared_resources += gb_shared

libgbShared = slib(BuildLibPath(libgb_name), list(gb_shared),
                   LIBS = libpbShared + env['LIBS'] + libm4ri + GD_LIBS)


gb_symlinks = SymlinkReadableLibname(libgbShared)

CPPPATH=env['CPPPATH']+[GBPath('include')]
#print env['CCFLAGS']
#print env['CXXFLAGS']


######################################################################
# Doxygen-based docu
######################################################################
docutarget = [DocPath('c++', elt) for elt in Split("html")]

if HAVE_DOXYGEN:
    cxxdocu = env.Doxygen(source=[DocPath('doxygen.conf')],
                          target=docutarget)

env.Clean(DocPath('c++'), glob(DocPath('c++/*')))
env.Clean(DocPath(), DocPath('c++'))

######################################################################
# Boost-test based tests
######################################################################

testclasses = Split("""GroebnerStrategy spoly term_accumulate CStringLiteral BooleEnv BooleSet BooleConstant BoolePolyRing BooleExponent BooleVariable BooleMonomial BoolePolynomial PBoRiError CCuddDDFacade DegRevLexAscOrder DegLexOrder
BlockDegRevLexAscOrder BlockDegLexOrder  LexOrder 
CFactoryBase MonomialFactory PolynomialFactory VariableFactory SetFactory
weak_pointers FGLMStrategy PseudoLongProduct""")

# Note: use custom TEST_CPPPATH settings for testing header installation, if any
try:
    testCPPPATH = env['TEST_CPPPATH']
except:
    testCPPPATH = None
if not testCPPPATH:
    testCPPPATH = CPPPATH


if BOOST_TEST:
    testfiles = env.Object([TestsPath('src', src + "Test.cc") for src in
                           testclasses], CPPPATH=testCPPPATH)
    testmain = env.Object([TestsPath('src', "unittests.cc")],
                          CPPPATH=testCPPPATH,
                          CPPDEFINES = ["BOOST_TEST_DYN_LINK"])

    
    def test_building(target, sources, env):
        env.Program(target, sources + testmain, 
                    CPPPATH=testCPPPATH,
                    LIBS = env['LIBS'] + \
                        [BOOST_TEST] + libpbShared + libgbShared  + libm4ri + GD_LIBS,
                    CPPDEFINES = ["BOOST_TEST_DYN_LINK"] )

    test_building(TestsPath("unittests"), testfiles, env)

    for testfile in testfiles:
        test_building(path.splitext(testfile.path)[0] + '.bin', [testfile], env)

    if env['BOOST_PYTHON']:
        env.Program(TestsPath("embedTest"), [TestsPath('src', "embedTest.cc")] + testmain, 
                    CPPPATH=testCPPPATH,
                    LIBS = env['LIBS'] + \
                    [BOOST_TEST] + libpbShared + libgbShared  + libm4ri + GD_LIBS + \
                    [env['BOOST_PYTHON'], pyconf.libname] + libm4ri,
                    CPPDEFINES = ["BOOST_TEST_DYN_LINK"] )
        


######################################################################
# python extension
######################################################################
LIBS = env['LIBS']+[env['BOOST_PYTHON']]+USERLIBS


documentable_python_modules = glob(PyRootPath('polybori/*.py')) + \
    [PyRootPath('polybori/dynamic/__init__.py')]


# Currently all python modules are at place
installable_python_modules = []

pydocu = []
dynamic_modules = []
pypb_symlinks = []


if HAVE_PYTHON_EXTENSION:
    wrapper_files=[ PyPBPath(f) for f in Split("""pypb_module.cc
    main_wrapper.cc test_util.cc fglm_wrapper.cc
    Poly_wrapper.cc navigator_wrap.cc variable_block.cc
    monomial_wrapper.cc misc_wrapper.cc strategy_wrapper.cc set_wrapper.cc
    slimgb_wrapper.cc""") ] 
    

    pypb=env.LoadableModule(BuildPyPBPath('PyPolyBoRi'),
                            wrapper_files,
                            LIBS=pyconf.libs + LIBS + \
                            libpbShared + libgbShared + libm4ri + GD_LIBS,
                            LDMODULESUFFIX=pyconf.module_suffix,
                            LDMODULEPREFIX="",
                            )

    env.Depends(pypb, pb_symlinks + gb_symlinks)
    
    if env['PLATFORM']=="darwin":
            def fix_install_name(target, source, env):
                names = [str(elt) for elt in dylibs]
                names = Split(shell_output('otool', '-D', *names))[1::2]
                for name in names:
                    newname = "@loader_path/" + \
                        env.relpath(InstPyPath("polybori/dynamic"),
                                    DevelInstLibPath(os.path.basename(name)))
                    env.Execute("install_name_tool -change %s %s %s"%(name, newname, target[0]))

            env.AddPostAction(pypb, fix_install_name)

# __init__.py generator
    def init_build(target, source, env):
        """__init__.py building..."""

        init_py_in = """# File: %(target)s
# Automatically generated by PolyBoRi
# This file is just for developing, it should not be installed.
def _location():
    import os
    import sys
    from distutils.sysconfig import get_python_version
    fname = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                         "initpy" + get_python_version().replace('.', ''))
    return file(fname, "r").read()

import imp
imp.load_dynamic("polybori.dynamic.PyPolyBoRi", _location())
"""
        init_py = file(target[0].path, "w")
        init_py.write(init_py_in  % dict(target = target[0].path, 
                                   source = source[0].abspath))
        init_py.close()
        init_py = file(target[1].path, "w")
        init_py_in = """%(source)s"""
        init_py.write(init_py_in % dict(target = target[1].path, 
                                        source = source[0].abspath))
        init_py.close()
    def init_message(target, *args):
        return target[0].path + " building..."
        
    dynamic_init_py = env.Command([PyRootPath('polybori/dynamic', elt) for elt\
                                       in ['__init__.py', 'initpy' + \
                                               pyconf.version.replace('.','')]],
                                  pypb, 
                                  action = env.Action(init_build, init_message))

    env.Alias(BuildPath(), dynamic_init_py) # Developers also need this
    env.Clean(PyRootPath("polybori"), PyRootPath("polybori/dynamic"))
    pypb_init_py = env.Command(BuildPyPBPath('__init__.py'), pypb, 
                               [Touch("$TARGET")])
    env.Depends(pypb_init_py, dynamic_init_py)
    # Define the dynamic python modules in pyroot
    documentable_python_modules += dynamic_modules
   
    
    polybori_modules = PyRootPath("polybori")
    #DefaultBuild(env.Install(polybori_modules, pypb))
    for (f,n) in installable_python_modules:
        env.Install(polybori_modules, f)

    
    to_append_for_profile = [libpb, gb]
    #to_append_for_profile=File('/lib/libutil.a')
    env.Program(PyPBPath('profiled'), wrapper_files+to_append_for_profile,
                LIBS = LIBS + ["python" + str(pyconf.version)] + USERLIBS + \
                pyconf.libs + libm4ri + GD_LIBS,
            CPPDEFINES=env["CPPDEFINES"]+["PB_STATIC_PROFILING_VERSION"])

elif env['EXTERNAL_PYTHON_EXTENSION']:
    dynamic_init_py = env.Command(PyRootPath('polybori/dynamic/__init__.py'), 
                                  [], [Touch("$TARGET")])

    env.Alias(BuildPath(), dynamic_init_py) 

else:
    print "no python extension"

docpybase = path.basename(env.subst('$PYTHON'))
DocPyPath = PathJoiner(DocPath(docpybase))
if HAVE_PYTHON_EXTENSION or extern_python_ext:
    # Generating python documentation
    def pypb_emitter(target,source,env):

        TargetPath = PathJoiner(target[0].dir)
        for filename in source:
            (fname, fext) = path.splitext(str(filename).replace(pyroot,''))

            if not fname.split(sep)[-1] == "__init__" :
                if fext in ['.so', '.py'] :
                    fname = TargetPath(fname.replace(sep,'.') + '.html')
                    target.append(env.File(fname))

        return (target, source)

    bld = Builder(action = "$PYTHON doc/genpythondoc.py " + pyroot +
                  " $TARGET.dir",
                  emitter = pypb_emitter)

    # Add the new Builder to the list of builders
    env['BUILDERS']['PYTHONDOC'] = bld

    # Generate foo.vds from foo.txt using mk_vds
    #for f in Split("ll.py nf.py gbrefs.py blocks.py PyPolyBoRi.so specialsets.py"):
    if have_pydoc:
        pydocu = env.PYTHONDOC(target=[DocPyPath('polybori.html'),
                                       DocPyPath('polybori.dynamic.html')],
                               source = documentable_python_modules)

        env.Clean(pydocu,
                  glob(DocPath('python*')) + 
                  glob(DocPath('python*/polybori*.html')) )

        env.Depends(pydocu, PyRootPath('polybori/dynamic/__init__.py'))
        env.Alias('doc/python', pydocu)

env.Clean(PyRootPath('polybori'), glob(PyRootPath('polybori/*.pyc')) +
          glob(PyRootPath('polybori/dynamic/*.pyc')))

# Source distribution archive generation
env.Append(DISTTAR_EXCLUDEEXTS = Split(""".o .os .so .a .dll .cache .pyc
           .cvsignore .dblite .log .sconsign .depend .out .graphViz_temp .exe
           .kprof.html .rpm .spec .so.0 .so.0.0.0 .0 .gcda .orig .rej .bin"""),
           DISTTAR_EXCLUDEDIRS = Split("""CVS .svn .sconf_temp SOURCES BUILD
           auxiliary .deps"""),
           DISTTAR_EXCLUDEPATTERN = Split(""".#* #*# *~ profiled cacheopts.h
           *config.h coding.py unittests Makefile config.status libtool
           m4ri.pc stamp-h1"""))

   
if distribute or rpm_generation or deb_generation:
    allsrcs = Split("""SConstruct README LICENSE ChangeLog versionnumber
disttar.py doxygen.py""")
    for dirname in Split("""groebner ipbori libpolybori 
    PyPolyBoRi pyroot pkgs gui testsuite"""):
        allsrcs.append(env.Dir(dirname))

    # Cudd is not distributed completely (unused and unfree things removed)
    allsrcs += [CuddPath(src) for src in Split("""LICENSE README
    RELEASE.NOTES""") ]
    allsrcs += [env.Dir(CuddPath(src)) for src in Split("""cudd""") ]

    # doc is not distributed completely
    allsrcs += [ DocPath(dsrc) for dsrc in Split("""doxygen.conf index.html.in
    tutorial/tutorial.tex tutorial/tutorial_content.tex tutorial/PolyGui.png
    tutorial/PolyGui-Options.png tutorial/versionnumber.in genpythondoc.py
    man/ipbori.1 man/PolyGUI.1 """) ]
    allsrcs.append(env.Dir(DocPath('images')))
    

if distribute:
    presrcdistri = env.DistTar(debname, allsrcs)
    (srcdistrname, srcdistrext1) = path.splitext(str(presrcdistri[0]))
    (srcdistrname, srcdistrext) = path.splitext(srcdistrname)
    srcdistrext += srcdistrext1
    pborisuffix = ''

    #if str(pborirelease) != "0" :
    #    pborisuffix += "-" + str(pborirelease)

    if env['USE_TIMESTAMP']:
        from datetime import date
        pborisuffix += "-" + str(date.today())

    if pborisuffix :
        srcdistri = env.Command(srcdistrname + pborisuffix + srcdistrext,
                                presrcdistri,                            
                                Move("$TARGET", "$SOURCE"))
    else :
        srcdistri = presrcdistri
                
    env.AlwaysBuild(srcdistri)
    env.Alias('distribute', srcdistri)
    
dylibs += libpbShared + libgbShared 
stlibs += [libpb, gb]

readabledevellibs = pb_symlinks + gb_symlinks + pypb_symlinks

dylibs_inst  = env.Install(DevelInstLibPath(), dylibs)
stlibs_inst  = env.Install(DevelInstLibPath(), stlibs)
env.Alias('install-static', stlibs_inst)

dylibs_readable_inst = SymlinkReadableLibname(dylibs_inst)

devellibs_inst = dylibs_readable_inst + dylibs_inst + stlibs_inst

env.Alias('install', dylibs_inst + dylibs_readable_inst)

# Installation for development purposes
if 'devel-install' in COMMAND_LINE_TARGETS or \
        'install-devel' in COMMAND_LINE_TARGETS or \
        'install-headers' in COMMAND_LINE_TARGETS:
    
    for elt in ['..', '.'] + [path.basename(elt)
                              for elt in glob(PBInclPath('*'))
                              if path.isdir(elt) and \
                                  path.basename(elt) != 'cudd' ]:
        env.Alias('install-headers', 
                  env.Install(DevelInstInclPath(elt), 
                              glob(PBInclPath(elt, '*.h'))))

    env.Alias('install-headers', 
              env.Install(DevelInstInclPath('groebner'),
                          glob(GBPath('include/polybori/groebner/*.h'))))

    # To ensure correct (patched) version of cudd we install our own
    # copy of the cudd headers (to our inclusion "namespace" to avoid clashes)
    env.Alias('install-headers', 
              env.Install(DevelInstInclPath('cudd'), cudd_headers))

    if not(external_m4ri):
        env.Alias('install-headers', 
                  env.Install(DevelInstInclPath('m4ri'), 
                              glob('M4RI/m4ri/*.h')))

    env.Alias('install-headers', DevelInstInclPath())
  
env.Append(COPYALL_PATTERNS = ['*'])

# Copy glob('*') from one directory to the other
def cp_all(target, source, env):
    source = source[0].path
    target = target[0].path

    ensure_dir(target, env)

    for patt in env['COPYALL_PATTERNS']:
        for filename in glob(path.join(source, patt)):
            print filename
            if not path.isdir(filename):
                result = str(path.join(target, path.basename(filename)))
                try:
                    env.Execute([Delete(result), Copy(result, filename),
                                 Chmod(result, 0644)])
                except:
                    raise RuntimeError, "error with ", result

    return None

# Copy python docu from one directory to the other and correct paths to modules
def cp_pydoc(target, source, env):

    source = source[0].path
    target = target[0].path
    import re
    patt = re.compile('(file:|)/[^\" ]*' + pyroot, re.VERBOSE)

    ensure_dir(target, env)

    showpath = env.relpath(env.Dir(target).abspath,
                           env.Dir(env['PYINSTALLPREFIX']).abspath)

    if showpath != '' and showpath[-1] != '/':
         showpath += '/'
    for filename in glob(path.join(source, '*.html')):
        if not path.isdir(filename):
            fcontent = open(filename).read()
            fcontent = patt.sub(r''+showpath, fcontent)

            result = str(path.join(target, path.basename(filename)))
            open(result, "w").write(fcontent)

    return None


cp_recbld = Builder(action = cp_all)
cp_pydocbld = Builder(action = cp_pydoc)


# Note: target[0] needs to be the path resulting from latex2html
# todo: More generic by moving actual result to given path?
def l2h_emitter(target, source, env):
    target = [env.File(path.join(str(target[0]), 'index.html'))]
    env.Clean(target, target[0].dir)
    return (target, source)

l2h = Builder(action = 'cd `dirname $SOURCE`; latex2html -html_version 4.0,unicode,utf-8 $SOURCE',
              emitter = l2h_emitter)

def t4h_emitter(target, source, env):
    target = [env.File(path.join(str(target[0]), 
                      path.splitext(path.basename(source[0].name))[0] + '.html'))]
    env.Clean(target, target[0].dir)
    return (target, source)


if have_t4h :
    t4h_str =  tex_to_ht + ' ' + path.join(env.Dir('').abspath, "$SOURCE") + t4h_opts
    os.environ['TEXINPUTS'] = env.Dir('doc/tutorial').abspath

    def t4h_action(source, target, env, for_signature):
        subdir = path.splitext(target[0].name)[0]
        if tex_to_ht == 'htlatex':
            t4h_opts = ' "html,2,charset=utf-8" " -cunihtf -utf8" "-d%s/"' % subdir
   
        return ('cd %s;' + tex_to_ht + ' %s ' +  t4h_opts) % (source[0].dir, source[0].name)

    tex_to_ht_bld = Builder(generator = t4h_action, emitter = t4h_emitter)
    env.Append(BUILDERS={'TeXToHt' : tex_to_ht_bld})


# substition function 
def substitute_install(target, source, env,
                       preprocess = None, postprocess = None):
        from string import Template
        page = open(str(source[0]), 'r').read()

        if preprocess:
            page = preprocess(page) 
        page = Template(page).safe_substitute(env)
        if postprocess:
            page = postprocess(page)     
        open(str(target[0]), 'w').write(page)
        return None

substinstbld  = Builder(action = substitute_install)


def docu_master(target, source, env):
    import os, re

    basefiles = ['index.html', 'polybori.html', 'tutorial.html']
    basesfound = []
    for item in source:
        if os.path.isdir(str(item)):
            for root, dirs, files in os.walk(str(item)):
                for filename in files:
                    if filename in basefiles:
                        basesfound.append(os.path.join(root, filename))

    if str(target[0]) in basesfound:
        basesfound.remove(str(target[0]))

    linkPattern = re.compile('<title.*?>(.*?)</title>', re.I|re.S) 
    links = ''
    for src in basesfound:
        fhandle = open(src, 'r')
        fcontent = fhandle.read()
        fhandle.close()
        ftitle = linkPattern.search(fcontent).group(1)
        relsrc = relpath(str(target[0].dir), src)
        links +=  '<P><A href="' + relsrc + '">' + ftitle +'</A>\n'


    env['PBDOCLINKS'] = links
    substitute_install(target, source, env)

    return None

def docu_emitter(target, source, env):
    if source[0].dir != target[0].dir :
        import re
        linkPattern = re.compile('<img src *?= *?"([^>]*?)".*?>', re.I|re.S) 
        fhandle = open(str(source[0]), 'r')
        relsrcs = linkPattern.findall(fhandle.read())
        SrcPath = PathJoiner(source[0].dir)
        TargetPath = PathJoiner(target[0].dir)

        for src in relsrcs:
            env.Depends(target,
                        FinalizeNonExecs(env.InstallAs(env.File(TargetPath(src)),
                                                       SrcPath(src))))
        fhandle.close()
        
        
    return (target, source)

    
masterdocubld  = Builder(action = docu_master, emitter = docu_emitter)

env.Append(BUILDERS={'CopyAll': cp_recbld, 'L2H': l2h,
                     'SubstInstallAs': substinstbld,
                     'CopyPyDoc':cp_pydocbld})
env.Append(BUILDERS={'DocuMaster': masterdocubld})



def spec_builder(target, source, env):

    substitute_install(target, source, env)
    return None

specbld = Builder(action = spec_builder)

def rpmemitter(target, source, env):
    rpm_arch =  shell_output("rpm", "-E", "%_arch")
    target = [RPMPath('RPMS', rpm_arch, target[0].name + '.' + rpm_arch + '.rpm')]
    return (target, source)

def srpmemitter(target, source, env):
    target = [RPMPath('SRPMS', target[0].name + '.src.rpm')]
    return (target, source)   
    
def generate_rpmbuilder(rpmopts, emitt = rpmemitter):
    return Builder(action = "rpmbuild " + rpmopts + " --define='_topdir " +
                   Dir(RPMPath()).abspath +  "' $SOURCE", emitter = emitt)

srpmbld  = generate_rpmbuilder('-bs', srpmemitter)
rpmbld  = generate_rpmbuilder('--define="jobs ' + str(GetOption('num_jobs')) +
                              '" -bb', rpmemitter)

# debbuilder is very experimental, we ignore dependencies currently (-d)
debbld = Builder(action = "dpkg-buildpackage -d -rfakeroot")
    
env.Append(BUILDERS={'SpecBuilder': specbld,
                     'RPMBuilder': rpmbld, 'SRPMBuilder': srpmbld,
                     'DebBuilder': debbld})

if have_l2h or have_t4h or HAVE_DOXYGEN:
    version4tex = env.Command([DocPath('tutorial/versionnumber')],
                              DocPath('tutorial/versionnumber.in'),
                              preprocessed_substitute)

    tutorial_srcs = [DocPath('tutorial/tutorial.tex')] + version4tex + glob(DocPath('tutorial/*.tex'))

    if have_l2h:
        tutorial = env.L2H(env.Dir(DocPath('tutorial/tutorial')), tutorial_srcs)
    else:
        if have_t4h :
            tutorial = env.TeXToHt(env.Dir(DocPath('tutorial/tutorial')),
                                   tutorial_srcs)    

    documastersubdirs = []
    if have_l2h or have_t4h:
        documastersubdirs += ["tutorial/tutorial"]
    if HAVE_DOXYGEN:
        documastersubdirs += ["c++"]

    if have_pydoc and HAVE_PYTHON_EXTENSION:
        documastersubdirs += [path.basename(elt) for elt in glob(DocPath("python*"))]
        if docpybase not in documastersubdirs:
            documastersubdirs += [docpybase]

    docmstr = env.DocuMaster(DocPath('index.html'),
                             [DocPath('index.html.in')] + [
            env.Dir(DocPath(srcs)) for srcs in documastersubdirs ])
    
    # build-independent doc targets
    if have_l2h or have_t4h:
        env.Alias('prepare-docs', DocPath('tutorial'))
    if HAVE_DOXYGEN:
        env.Alias('prepare-docs', DocPath('c++'))

    env.Alias('prepare-docs', docmstr)
    env.Alias('docs', 'prepare-docs')

# Clean, even, if L2H/TexToHt are not available anymore
env.Clean(DocPath('tutorial'), DocPath('tutorial/tutorial'))
env.Clean(DocPath('tutorial'),
          [glob(DocPath('tutorial/tutorial' + sfx)) for sfx 
           in Split("*.html .4* .aux .css .dvi .idv .l*g .tmp .xref")])

pbrpmname = pboriname + '-' + pboriversion + "." + pborirevision 

if rpm_generation:
    # Some file servers use invalid group-ids, so change to current gid
    def correctgid(target, source, env):
        os.chown(target[0].path, -1, os.getgid())

    rpmsrcs = FinalizeNonExecs(env.DistTar(RPMPath('SOURCES',
                                                   pbrpmname),
                                           allsrcs, DISTTAR_FORMAT = 'bz2'))
    env.AddPostAction(rpmsrcs, correctgid)

    pbspec = FinalizeNonExecs(env.SpecBuilder(SpecsPath(pboriname +'.spec'),
                                              RPMPath('PolyBoRi.spec.in')))
       
    env.AddPostAction(pbspec, correctgid)

    if retrieve_m4ri:
        m4ri_srcs = Install(RPMPath('SOURCES'),
                            BuildPath('tmp', m4ri_name + '.tar.gz'))
        env.AddPostAction(m4ri_srcs, correctgid)
        env.Depends(pbspec, m4ri_srcs)

    env.AlwaysBuild(pbspec)
    env.Alias('prepare-rpm', pbspec)
    env.Alias('prepare-rpm', rpmsrcs)
    
    pbsrpm = env.SRPMBuilder(RPMPath('SRPMS', pbrpmname),
                             pbspec + rpmsrcs)
    env.AlwaysBuild(pbsrpm)
    pbrpm = env.RPMBuilder(RPMPath('RPMS', pbrpmname ),
                           pbspec + rpmsrcs)

    def provide_builddir(target, source, env):
        ensure_dir(RPMPath('BUILD'), env)
    
    env.AddPreAction(pbrpm, provide_builddir)
    env.AlwaysBuild(pbrpm)
    env.Alias('srpm', pbsrpm)
    env.Alias('rpm', pbrpm)

    env.Clean(RPMPath, [RPMPath(elt) for elt in Split("""RPMS SRPMS BUILD
        SPEC SOURCES""")])

if prepare_deb or generate_deb:
    debsrc = env.SubstInstallAs(DebInstPath('changelog'),
                                DebPath('changelog.in'))


    debsrc += FinalizeNonExecs(env.SubstInstallAs(DebInstPath('control.in'),
                                                  DebPath('control.in')))
    env['cdbs'] = 'cdbs (>= 0.4.23-1.1), debhelper (>= 5), quilt, patchutils (>= 0.2.25), cdbs (>= 0.4.27-1)'


    debsrc += FinalizeNonExecs(env.Command([DebInstPath('control')],
                                           DebPath('control.in'),
                                           preprocessed_substitute))
        
    for src in ['rules', 'compat', 'copyright', 
                'libpolybori-dev.install',  'python-polybori.install'] :
        debsrc += env.Install(DebInstPath(), DebPath(src))
        
    debsrc += env.InstallAs(DebInstPath('libpolybori-' + pboriversion +
                                        '.' + pborirevision   +'-0.install'),
                            DebPath('libpolybori0.install'))
        
    env.Alias('prepare-debian', DebInstPath())
    env.Clean(DebInstPath(), DebInstPath())
    deb_arch =  shell_output("dpkg-architecture", "-qDEB_HOST_GNU_CPU")
    pbdeb = env.DebBuilder(path.join('..', debname + '-' + pborirelease +
                                     '.' + deb_arch + '.deb'), debsrc)
    
    env.AlwaysBuild(env.Alias('deb', pbdeb))    
    

def GeneratePyc(sources):
    results = []
    for src in sources:
        (fbase, fext) = path.splitext(src.name)
        if (fext == '.py') :
            cmdline = """$PYTHON -c "import py_compile; """
            cmdline +=  """py_compile.compile('""" + str(src) + """')" """ 
            results += env.Command(str(src) +'c', file, cmdline)

        env.Depends(results, sources)
    return results


       
# Installation precedure for end users
if 'install' in COMMAND_LINE_TARGETS or 'install-docs' in COMMAND_LINE_TARGETS:

    # Setting umask for newly generated directories
    try:
        umask = os.umask(022)
        print 'setting umask to 022 (was 0%o)' % umask
    except OSError:     # ignore on systems that don't support umask
        pass
    
    InstPath = PathJoiner(env['INSTALLDIR'])
    InstExecPath = PathJoiner(env['EPREFIX'])
    InstDocPath = PathJoiner(env['DOCDIR'])
    InstManPath = PathJoiner(env['MANDIR'])

   
    for inst_path in [InstPath(), InstExecPath(), InstDocPath(), InstPyPath(),
                      InstManPath()]:
        env.Alias('install', inst_path)
       
    # The distribution usually take core of gzipping and symlink correction         
    env.Install(InstManPath('man1'), DocPath('man/ipbori.1'))
    env.Install(InstManPath('man1'), DocPath('man/PolyGUI.1'))

    env.SymLink(InstManPath('man1/ipbori' + pyconf.major + '.1'),
                InstManPath('man1/ipbori.1'))
    env.SymLink(InstManPath('man1/ipbori' + pyconf.version + '.1'),
                InstManPath('man1/ipbori.1')) 
    env.SymLink(InstManPath('man1/PolyGUI' + pyconf.major + '.1'),
                InstManPath('man1/PolyGUI.1'))
    env.SymLink(InstManPath('man1/PolyGUI' + pyconf.version + ".1"),
                InstManPath('man1/PolyGUI.1')) 

    # Executables and shared libraries to be installed
    so_pyfiles = []

    if env['PLATFORM']=="darwin":

        if env['INSTALL_NAME_DIR'] is not None:
            name = os.path.join(env['INSTALL_NAME_DIR'], 
                                "${TARGET.name}")
            for elt in dylibs_inst:
                env.AddPostAction(elt, 
                                  "install_name_tool -id " + name + " $TARGET")

    if HAVE_PYTHON_EXTENSION:
        pypb_inst = env.Install(InstPyPath("polybori/dynamic"), pypb)
        env.Depends(pypb_inst, dylibs_inst + dylibs_readable_inst)
        so_pyfiles += pypb_inst

    pyfiles = []
    env['GUIPYPREFIX'] = env.relpath(InstPath(GUIPath()),
                                     '$PYINSTALLPREFIX')
    
    for instfile in [ IPBPath('ipbori')]:
        FinalizeExecs(env.SubstInstallAs(InstPath(instfile + pyconf.version), instfile))

    for instfile in [ GUIPath('PolyGUI') ]:
        FinalizeExecs(env.SubstInstallAs(InstPath(instfile + pyconf.version), instfile))

    for instfile in [GUIPath('cnf2ideal.py')]:
        pyfiles += env.InstallAs(InstPath(instfile), instfile)
        
    for instfile in [ GUIPath('polybori.png') ]:
        env.InstallAs(InstPath(instfile), instfile)

    # Copy c++ documentation
    if HAVE_DOXYGEN:
        cxxdocinst = env.CopyAll(env.Dir(InstDocPath('c++')),
                                 env.Dir(DocPath('c++/html')))
        env.Depends(cxxdocinst, cxxdocu)

    htmlpatterns = Split("*.html *.css *.png *gif *.jpg")

    # Copy python documentation
    if have_pydoc and HAVE_PYTHON_EXTENSION:
        pydocuinst = env.CopyPyDoc(env.Dir(InstDocPath(docpybase)),
                                   env.Dir(DocPyPath()))

        env.Depends(pydocuinst, pydocu)
        env.Clean(pydocuinst, pydocuinst)

    # Copy Cudd documentation
    #CopyAll(InstDocPath('cudd'), 'Cudd/cudd/doc', env) 
    #CopyAll(InstDocPath('cudd/icons'), 'Cudd/cudd/doc/icons', env)

    # Copy Tutorial
    if have_l2h or have_t4h:
        tutorialinst = env.CopyAll(env.Dir(InstDocPath('tutorial')),
                                   env.Dir(DocPath('tutorial/tutorial')),
                                   COPYALL_PATTERNS = htmlpatterns)
        env.Depends(tutorialinst, tutorial)
    else:
        tutorialinst = []

         
        
    # Generate html master
    instdocumastersubdirs = ["tutorial", "c++"]
    if have_pydoc and HAVE_PYTHON_EXTENSION:
        instdocumastersubdirs +=  [path.basename(elt) for elt in glob("doc/python*")]

    if ('install' in COMMAND_LINE_TARGETS) and \
           (docpybase not in instdocumastersubdirs):
        instdocumastersubdirs += [docpybase]
        
    instdocu = FinalizeNonExecs(env.DocuMaster(InstDocPath('index.html'),
                                               [DocPath('index.html.in')] + [ 
        env.Dir(InstDocPath(srcs)) for srcs in instdocumastersubdirs]))

    env.Depends(instdocu, tutorialinst)
     
    if HAVE_DOXYGEN:
        env.Depends(instdocu, cxxdocinst)
        env.Depends(cxxdocinst, tutorialinst)

    ensure_dir(InstDocPath(), env)
    
    # Non-executables to be installed
    pyfile_srcs = glob(PyRootPath('polybori/*.py'))

    if (float(pyconf.version) < 2.5): # removing advanced functionality
        pyfile_srcs.remove(PyRootPath('polybori/context.py'))
                       
    for instfile in pyfile_srcs :
        targetfile = InstPyPath(env.relpath(PyRootPath(), instfile))
        pyfiles += env.InstallAs(targetfile, instfile)

    if HAVE_PYTHON_EXTENSION:
        pyfiles +=  env.Install(InstPyPath("polybori/dynamic"), pypb_init_py)

    if HAVE_PYTHON_EXTENSION or extern_python_ext:
        cmdline = """$PYTHON -c "import compileall; compileall.compile_dir('"""
        cmdline += InstPyPath('polybori') + """', ddir = ''); """ 
        cmdline += """compileall.compile_dir('"""+ InstPath(GUIPath())
        cmdline += """', ddir='')" """
        FinalizeNonExecs(env.Command([file1.path + 'c' for file1 in pyfiles],
                                     pyfiles, cmdline))

    env['PYINSTALLPREFIX'] = env.subst('$PYINSTALLPREFIX')
    env['RELATIVEPYPREFIX'] = env.relpath(InstPath(IPBPath()),
                                          '$PYINSTALLPREFIX')       

    # Symlink from executable into bin directory
    ipboribin = env.SymLink(InstExecPath('ipbori' + pyconf.version),
                            InstPath(IPBPath('ipbori' + pyconf.version))) + \
    env.SymLink(InstExecPath('ipbori' + pyconf.major),
                InstExecPath('ipbori' + pyconf.version)) + \
    env.SymLink(InstExecPath('ipbori'),
                InstExecPath('ipbori' + pyconf.version))


    guibin = env.SymLink(InstExecPath('PolyGUI' + pyconf.version),
                         InstPath(GUIPath('PolyGUI' + pyconf.version))) + \
    env.SymLink(InstExecPath('PolyGUI' + pyconf.major),
                InstExecPath('PolyGUI' + pyconf.version)) + \
    env.SymLink(InstExecPath('PolyGUI'),
                InstExecPath('PolyGUI' + pyconf.version))
    
    env.AlwaysBuild(ipboribin)   
    env.Alias('install', ipboribin)
    env.AlwaysBuild(guibin)   
    env.Alias('install', guibin)

    # we dump the flags for reuse by other developers
    conffilename = env['CONFFILE']
    if conffilename:
        def build_conffile(target, source, env):
            opts.Save(target[0].path, env)
            return None

        conffile = env.Command(conffilename, 'SConstruct', build_conffile)
        env.AlwaysBuild(conffile)
        env.Alias('install', conffile)

    pkgconfigdirname = env['PKGCONFIGPATH']
    if pkgconfigdirname:
        def build_pcfile(target, source, env):
            localenv = source[0].get_env()
            libflags = localenv.subst("$LINKFLAGS $_LIBDIRFLAGS $_LIBFLAGS ${_stripixes(LIBLINKPREFIX, GD_LIBS, LIBLINKSUFFIX, LIBPREFIXES, LIBSUFFIXES, __env__)}");
            libs = ' '.join(set([l.replace('-l','') for l in libflags.split() 
                    if l.startswith('-l')]))
            page = """
prefix=$PREFIX
exec_prefix=$${prefix}
includedir=$DEVEL_INCLUDE_PREFIX
libdir=$DEVEL_LIB_PREFIX

Name: %s
Description: The PolyBoRi library
URL: http://polybori.sourceforge.net
Version: %s
Requires: %s
Cflags: $CXXFLAGS $CCFLAGS $_CCCOMCOM
Libs: %s
            """ % (env.File(target[0]).name.replace('.pc',''),
                   pboriversion + '.' + pborirevision,
                   libs, libflags)
            page = localenv.subst_target_source(page).replace(env.subst("$DESTDIR"),'') + '\n'
            open(str(target[0]), 'w').writelines(page)

            return None

        pcfiles = [env.Command(path.join(pkgconfigdirname,
                                         "polybori-groebner-" + pboriversion +
                                         ".pc"),
                               libgbShared, build_pcfile),
                   env.Command(path.join(pkgconfigdirname,
                                         "polybori-" + pboriversion + ".pc"),
                               libpbShared, build_pcfile)
                   ]

        env.AlwaysBuild(pcfiles)
        env.Alias('install', pcfiles)

    desktoppath = env['DESKTOPPATH']
    if desktoppath:
        def build_desktop(target, source, env):
            page = """[Desktop Entry]
Categories=Education;Science;Math
Comment=PolyBoRi GUI
Exec=%s
GenericName=Boolean Groebner Basis System
Icon=PolyGUI
MimeType=
Name=PolyGUI
Path=
StartupNotify=false
Terminal=false
Type=Application
""" % path.basename(str(source[0]))
            open(str(target[0]), 'w').writelines(page)
            return None

        desktopfiles = [env.Command(path.join(desktoppath,
                                              path.basename(str(elt)) + \
                                                  '.desktop'),
                                    elt, build_desktop)
                        for elt in guibin ] + \
                        [env.Install(env['ICONDIR'], GUIPath('PolyGUI.xpm'))]

        env.AlwaysBuild(desktopfiles)
        env.Alias('install', desktopfiles)

    if have_l2h or have_t4h or  HAVE_DOXYGEN:   
        env.Alias('install-docs', instdocu)
        env.Depends('install-docs', 'prepare-docs')
        env.Alias('install', 'install-docs')

env.Alias('prepare-static',  stlibs)
env.Alias('prepare-install', dylibs + readabledevellibs)


if HAVE_PYTHON_EXTENSION:
    env.Alias('prepare-install', [BuildPyPBPath(), pyroot])

env.Alias('prepare-devel',  ['prepare-static', 'prepare-install'])


for sfx in [pyconf.major, pyconf.version]:
    Default(env.SymLink(IPBPath('ipbori' + sfx),
                        IPBPath('ipbori')))
    Default(env.SymLink(GUIPath('PolyGUI' + sfx),
                        GUIPath('PolyGUI')))

Default(BuildPath())

# Generate usage for scons -h here
# (PYTHONSITE is already evaluated, but not python-specific paths)
Help(opts.GenerateHelpText(env))

if 'dump_default' in COMMAND_LINE_TARGETS:
  print defaultenv.Dump()

if 'dump' in COMMAND_LINE_TARGETS:
  print env.Dump()

env.Alias('dump', 'SConstruct')
env.Alias('dump_default', 'SConstruct')


if retrieve_m4ri:
    m4ribld = env.Command([BuildLibPath("libm4ri.so"),
                           BuildLibPath("libm4ri-0.0." + env['M4RIVERSION'] + ".so"),
                           BuildLibPath("libm4ri.a")],
                          [BuildPath('tmp', m4ri_name, 'configure'),
                           BuildPath('tmp', m4ri_name, 'm4ri/config.h')],
                          "cd ${SOURCE.dir.abspath}; make && make install")
    
    env.Alias("install",
              env.Install(DevelInstLibPath(),
                          [BuildLibPath("libm4ri-0.0." + env['M4RIVERSION'] + \
                                            ".so"),
                           BuildLibPath("libm4ri.a")]) +
              env.SymLink(DevelInstLibPath("libm4ri.so"),
                          DevelInstLibPath("libm4ri-0.0." + env['M4RIVERSION'] + \
                                           ".so")))
    
    if env['PKGCONFIGPATH']:
        env.Install(env.subst('$PKGCONFIGPATH'),
                    BuildLibPath('pkginfo/m4ri.pc'))

    env.Alias("install-headers",
              env.CopyAll(env.Dir(DevelInstInclPath('../m4ri')), 
                          env.Dir(BuildInclTopPath('m4ri'))))
    env.Alias('install-static', DevelInstLibPath("libm4ri.a"))

    env.Alias("m4ri-build", m4ribld)
    env.Append(LIBPATH=BuildLibPath())
    env.Depends(libgbShared, m4ribld)
    env.Clean(BuildPath('tmp'), m4ri_dir)


env.Alias('install-devel', ['install-static', 'install-headers'])
env.Alias('devel-install', 'install-devel') # allow old naming convention

# This one last!
env.Clean('.', '.sconsign.dblite')
