# 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

import os, glob

curdir = Dir('.').path + '/'

net = {}

net['core'] = [ 
    'sock.c', 'skbuff.c', 'iovec.c',
    'datagram.c', 'scm.c', 'sysctl_net_core.c',
    'filter.c', 'dev.c', 'dev_mcast.c',
    'dst.c', 'neighbour.c', 'rtnetlink.c',
    'utils.c', 'netfilter.c',
    'ethtool.c', 
    ]

net['ethernet'] = [
    'eth.c', 'sysctl_net_ether.c'
    ]

net['ipv4'] = [
    'utils.c', 'route.c', 'inetpeer.c', 'proc.c',
    'protocol.c', 'ip_input.c', 'ip_fragment.c',
    'ip_forward.c', 'ip_options.c', 'ip_output.c',
    'ip_sockglue.c', 'tcp.c', 'tcp_input.c',
    'tcp_output.c', 'tcp_timer.c', 'tcp_ipv4.c',
    'tcp_minisocks.c', 'tcp_diag.c', 'raw.c',
    'udp.c', 'arp.c', 'icmp.c', 'devinet.c',
    'af_inet.c', 'igmp.c', 'sysctl_net_ipv4.c',
    'fib_frontend.c', 'fib_semantics.c',
    'fib_hash.c', 'syncookies.c'
    ]

net['sctp'] = Split(
"""adler32.c debug.c        objcnt.c     sla1.c           ssnmap.c
associola.c  endpointola.c  output.c     sm_make_chunk.c  sysctl.c
bind_addr.c  hashdriver.c   outqueue.c   sm_sideeffect.c  transport.c
chunk.c      input.c        primitive.c  sm_statefuns.c   tsnmap.c
command.c    inqueue.c      proc.c       sm_statetable.c  ulpevent.c
     ipv6.c         protocol.c   socket.c         ulpqueue.c"""
    )
    

# 'ipv6_syms.c', 'ip6_fw.c', 
net['ipv6'] = [
    'addrconf.c', 'icmp.c', 'ip6_output.c', 'route.c', 
    'af_inet6.c', 'ip6_fib.c', 'ipv6_sockglue.c', 'proc.c', 'sit.c', 
    'anycast.c', 'ip6_flowlabel.c', 'protocol.c', 
    'sysctl_net_ipv6.c', 'datagram.c', 'mcast.c', 'raw.c', 
    'tcp_ipv6.c', 'exthdrs.c', 'ip6_input.c', 'ndisc.c', 'reassembly.c', 
    'udp.c',
    ]

net['netlink'] = [
    'af_netlink.c'
    ]

net['packet'] = [
    'af_packet.c'
    ]

net['sched'] = [
    'sch_generic.c'
    ]

net['.'] = [
    'socket.c', 'sysctl_net.c'
    ]

# This array specifies the order. This order is used when linking; we need
# to make sure things are linked in the correct order so the initialisation
# functions -- initcall functions -- are called in the correct order.
# There was a problem earlier where sctp_init was being called before
# inet_init, which caused problems. The array below fixes that.
dir_order = [ '.', 'core', 'packet', 'sched', 'netlink', 'ethernet', 'ipv4', 
	'ipv6', 'sctp' ]

src = reduce(lambda x,y:x+y, [ ['net/' + d + '/' + f for f in net[d]] 
                                    for d in dir_order ])

src.extend( [ 'nsc/unimplemented.c', 'nsc/globals.c',
    'nsc/implemented.c', 'nsc/support.c',
    'drivers/net/loopback.c', 'kernel/softirq.c', 'drivers/net/net_init.c',
    'kernel/timer.c', 'kernel/itimer.c', 'kernel/sysctl.c'
] )

# -----------------------------------------------

# We might want to change the include dir later 
# used to have: -O2
cflags = '-D__KERNEL__ -Wall -Wstrict-prototypes -Wno-trigraphs -nostdinc -fno-inline -O2 -iwithprefix include -DKBUILD_BASENAME=clnt -DMODVERSIONS -DEXPORT_SYMTAB '
# -fno-strict-aliasing -fno-common -fomit-frame-pointer -pipe -mpreferred-stack-boundary=2 -march=i686 -malign-functions=4
cflags += ' -g ' # -finstrument-functions 

# You really need to undefine whatever symbol is defined for the operating
# system you are compiling on and make sure the various linux symbols are
# defined. __linux__ is the only important one I've found; though compilers
# tend to define __linux and __Linux__ and so on and so forth.
cflags += ' -U__FreeBSD__ -D__linux__=1 -Dlinux=1 -D__linux=1 '
# the -DKBUILD_BASENAME probably doesn't matter?

link_flags = '-Wl,-O1  '
ext_cflags = ''

if os.uname()[4] == 'x86_64':
    link_flags += '-m32 '
    ext_cflags += '-m32 '

cflags += ext_cflags

include_path = [ 'include', '../sim', 'nsc', 'override' ]

cc = 'gcc-3.3'
cxx = 'g++'
linker_script = 'linker-script-full.ld'

# Hack to use gcc 3.3 on FreeBSD 5.3. Would be nice to use ust 3.4, but
# that currently ends up in compile problems. At some point in the future I
# guess we can just use 3.4 on Linux.
gcc_version = os.popen("gcc -v 2>&1 | grep '^gcc version'").read()[:-1].split(" ")[2][0:3]

#print "Normal gcc version is", gcc_version

# LSB
if float(gcc_version) >= 3.4: 
#if float(gcc_version) >= 5.4:
    #    print \
    #"""NSC: gcc version detected to be 3.4, but 3.3 is required to build this lib.
    #NSC: Attempting to use gcc33 as the C compiler, if this does not work please
    #NSC: specify the path and filename of gcc 3.3 on your system in 
    #NSC: linux-2.4/SConscript.
    #    """
    cc = "gcc-3.3"
    cxx = "g++"
    linker_script = 'linker-script-full-2.ld'
elif gcc_version == '3.3':
    linker_script = 'linker-script-full-2.ld'

#print "CC is", cc
Import('default_env')

env = default_env.Copy(CC=cc, CXX = cxx, CCFLAGS = cflags, 
        CPPPATH = include_path, LINK = cxx, 
        GLB_LIST = curdir + '/global_list.txt')
drv_env = default_env.Copy(CC=cc, CXX = cxx, 
        GLB_LIST = curdir + '/global_list.txt', 
        CCFLAGS = cflags + '-DEXPORT_SYMTAB', CPPPATH = include_path)

sim_env = Environment(CC=cc, CXX=cxx, 
		CCFLAGS = '-g -Wall -O2 ' + ext_cflags, 
		CPPPATH = [ '../sim', 'nsc' ])

# Tell our Parser to parse everything in input_sources
parsed_sources = []
# The following isn't just "for i in src" because we need to get the order
# correct.
for i in src:
    output = os.path.splitext(i)[0]+'.parsed.c'
    if i[:7] == 'drivers':
        parsed_sources.append( drv_env.Parser(output, i) )
    else:
        parsed_sources.append( env.Parser(output, i) )
    # Make sure the parser is built so we can actually create the output
    # file.
    env.Depends(output, '#' + default_env['GLOBALISER'])

#####
ss = sim_env.SharedObject('nsc/sim_support.cpp')
parsed_sources.append(ss)
parsed_sources.append("asm/checksum.S")

parsed_sources.append(
    Environment(CC=cc,CCFLAGS="-g -m32").SharedObject('nsc/debug.c')
    )

#src.append('linker-script.ld')
if len(linker_script):
    link_flags += '-Wl,-T' + curdir + linker_script

output = env.Program(source = parsed_sources, target = 'liblinux2.4.28.so',
    LINKFLAGS = '-shared -Wl,-O1 ' + link_flags
)

Install(dir = "..", source = output)
