# vim: filetype=python

#  Network Simulation Cradle
#  Copyright (C) 2003-2005 Sam Jansen
#
#  This program 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 of the License, or (at your option)
#  any later version.
#
#  This program 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., 59
#  Temple Place, Suite 330, Boston, MA 02111-1307 USA

# Doesn't work? Had problems using timestamp signatures. Might have sped things
# up...
#SourceSignatures('timestamp')


Help("""
     use 'scons libstackname.so' to built a specific stack.
     use 'scons target=arch' to specify target architecture (either amd64 or x86).
     Default target architecture is autodetect.
     """)

# We use newer SCons versions and naming, need at least 1.0 to build. Scons
# 1.0.1 is included locally, just use "python scons.py".
EnsureSConsVersion(1,0)

def get_target_architecture(context):
    import os
    def get_elf_class(filename):
        file = open(str(filename))
        data = file.read(5)
        file.close()
        # Valid ELF header?
        if data[0] == '\x7f' and data[1] == 'E' and data[2] == 'L' and data[3] == 'F':
            if data[4] == '\x01':
                return 'x86'
            elif data[4] == '\x02':
                return 'amd64'
            raise TypeError, "Unknown ELF class"
        else:
            raise TypeError, "%s: not in ELF format" % filename

    target = ARGUMENTS.get('target')
    # allow user to override using scons target=(amd64|x86)
    if target:
        context.Result('Target set to %s on command line, check skipped' % target)
        os.environ['NSC_TARGET_ARCHITECTURE'] = target
        return target
    arch = os.uname()[4]
    context.Message('Checking target architecure...')
    if arch == 'i686' or arch == 'i586' or arch == 'i486' or arch == 'i386':
        result = 'x86'
    elif arch == 'x86_64':
        source = 'int main(void)\n{return 0;}\n'
        context.Message('amd64, checking userland ...')
        result = context.TryCompile(source, '.c')
        if not result:
            return result
        result = get_elf_class(context.lastTarget)
    else:
        raise OSError, ('Unsupported architecture, if you want to '
                        'crosscompile, use \"scons target=x86\" (or amd64)')

    context.Result(result)
    context.env['NSC_TARGET_ARCHITECTURE'] = result
    return result

def filter_globalised(target, source, env):
  """Used by the globaliser builder to remove already globalised files.

  This is required because the suffix for globalised files is still the same as
  the original files (both have .c at the end). We use '.globalised.c' to
  indicate files that have been globalised, so if the source has this string in
  it, we return empty lists to inform SCons that there is no action to be
  taken.
  """
  if len(source) > 1 or len(target) > 1:
    return ([], [])
  if str(source[0]).find('.globalised.') != -1:
    return ([], [])
  env.Depends(target, '#' + env['GLOBALISER'])
  return (target, source)

# -----------------------------------------------------------------------------
# The globaliser action is configured as follows:
#   single_source=True -- This means that if the action is given a list of
#     source files, it will be invoked once for each source file
#   emitter=filter_globalised -- This filtered out alread-globalised files. See
#     the docstring of filter_globalised
#   source_scanner=SourceFileScanner -- Use the default scanner to find
#     dependencies of the source files. This means that the source list will go
#     through the normal C dependency scanning.
globaliser_action = '$CC $CCFLAGS $GLB_CCFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS ' \
    + ' -E $SOURCE -o - | $GLOBALISER $GLB_FLAGS $GLB_LIST >$TARGET'
globaliser_builder = Builder(action=globaliser_action,
                             src_suffix='.c',
                             suffix='.globalised.c',
                             single_source=True,
                             emitter=filter_globalised,
                             source_scanner=SourceFileScanner)

# -----------------------------------------------------------------------------
# Site-local customisation: load a custom.py (if it exists), and allow
# overriding the C and C++ compilers. This allows the user to e.g. specify a
# cross-compiler to compile in 32-bit mode on a 64-bit machine.
vars = Variables('custom.py')
vars.AddVariables(
    ('CC', 'The default C compiler used'),
    ('CXX', 'The default C++ compiler user'),
    ('LINKFLAGS', 'Extra arguments passed to the linker'),
    )

# -----------------------------------------------------------------------------
# Run the configure tests and build the environment
env = Environment(variables=vars)
conf = Configure(env, custom_tests={
      'get_target_architecture': get_target_architecture})
if not conf.get_target_architecture():
    Exit(1)
env = conf.Finish()

# -----------------------------------------------------------------------------
# 'default_env' is exported, it is expected that all SConscript files import
# this environment and Clone it.
default_env = env.Clone(GLOBALISER='globaliser/globaliser', GLB_FLAGS='')
default_env.Append(BUILDERS={'Globaliser': globaliser_builder})
Export('default_env')

# -----------------------------------------------------------------------------
# The list of SConscript files to read in.
SConscript('globaliser/SConscript')

SConscript('freebsd5/SConscript')
SConscript('lwip-HEAD/src/SConscript')
SConscript('openbsd3/SConscript')

SConscript('linux-2.6/SConscript')
SConscript("linux-2.6.18/SConscript")
SConscript("linux-2.6.26/SConscript")

SConscript('test/SConscript')
