# 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

stackname = "linux2.6.26"

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

net = {}

net['core'] = \
Split("""
datagram.c   ethtool.c        iovec.c                    sock.c
dev.c        filter.c         link_watch.c               stream.c
dev_mcast.c  flow.c           neighbour.c   rtnetlink.c  sysctl_net_core.c
dst.c        gen_estimator.c  net-sysfs.c   scm.c        utils.c
             gen_stats.c      skbuff.c      netevent.c	net_namespace.c
request_sock.c
""")

net['ethernet'] = \
Split("""
eth.c        
""")

net['ipv4'] = \
Split("""
af_inet.c        icmp.c                     syncookies.c       udp.c	udplite.c
ah4.c            igmp.c         ipconfig.c  sysctl_net_ipv4.c  
arp.c            inetpeer.c                 tcp.c                            
datagram.c       ip_forward.c   ipmr.c      inet_diag.c                       
devinet.c        ip_fragment.c              tcp_input.c                     
esp4.c           tcp_ipv4.c
fib_frontend.c   ip_input.c     tcp_minisocks.c
fib_hash.c       ip_options.c   protocol.c  tcp_output.c
                 ip_output.c    raw.c       
fib_semantics.c  ip_sockglue.c  route.c     tcp_timer.c
inet_connection_sock.c
inet_fragment.c
tcp_cong.c	tcp_cubic.c	tcp_highspeed.c
tcp_htcp.c	tcp_vegas.c	tcp_veno.c	tcp_westwood.c
inet_hashtables.c		tcp_diag.c	tcp_scalable.c
inet_timewait_sock.c 		tcp_hybla.c	tcp_illinois.c
tcp_lp.c	tcp_bic.c	tcp_yeah.c
""")

net['ipv6'] = \
Split("""
addrconf.c     addrlabel.c              protocol.c	syncookies.c         udp.c	udplite.c
af_inet6.c  icmp.c           ipv6_sockglue.c  raw.c
ip6_fib.c  	reassembly.c
anycast.c   ip6_flowlabel.c  mcast.c          route.c
datagram.c  ip6_input.c      ndisc.c
ip6_output.c                      sysctl_net_ipv6.c
addrconf_core.c
exthdrs.c                    tcp_ipv6.c
inet6_hashtables.c	     inet6_connection_sock.c
""")
# exthdrs_core.c ?
    
net['sctp'] = \
Split("""
auth.c associola.c  endpointola.c  outqueue.c       sm_statefuns.c   tsnmap.c
bind_addr.c  input.c        primitive.c      sm_statetable.c  ulpevent.c
chunk.c      inqueue.c                socket.c         ulpqueue.c
command.c    ipv6.c         protocol.c       ssnmap.c
sm_make_chunk.c  sysctl.c
debug.c      output.c       sm_sideeffect.c  transport.c
""")

# NOTE: DCCP does not work completely yet; there is an infinite loop when
# a dccp connection is being shut down.
# For the time being, it isn't compiled.
net['dccp'] = \
Split("""
feat.c   ipv4.c  minisocks.c  proto.c ccid.c options.c sysctl.c
ackvec.c  input.c  output.c     timer.c
ccids/ccid2.c
""")
net['dccp/ccids'] = \
Split("""
loss_interval.c, packet_history.c tfrc.c tfrc_equation.c
""")

net['netlink'] = \
Split("""
attr.c
af_netlink.c
""")

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

net['sched'] = \
Split("""
              cls_api.c        cls_u32.c    sch_atm.c             sch_hfsc.c
              cls_basic.c                   sch_blackhole.c       sch_htb.c
              cls_fw.c                      sch_cbq.c             sch_ingress.c
                                            sch_dsmark.c          sch_netem.c
                                            sch_fifo.c            sch_prio.c
              cls_rsvp.c                    sch_generic.c         sch_red.c
                                                                  sch_sfq.c
              cls_rsvp6.c      sch_tbf.c
              cls_tcindex.c    sch_api.c    sch_gred.c            sch_teql.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/implemented.c', 'nsc/support.c',
    'nsc/sysctl.c', 'nsc/tc.c',
    'kernel/softirq.c', 'kernel/timer.c', 'kernel/itimer.c', 'kernel/sysctl.c',
    'kernel/rwsem.c',
    'drivers/net/loopback.c',
    'drivers/char/random.c',
    'lib/find_next_bit.c',
    'lib/libcrc32c.c',
    'lib/idr.c', # used by SCTP
    'lib/rbtree.c', 'lib/hexdump.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 -iwithprefix include -DKBUILD_BASENAME=\\"clnt\\" ' + \
    '-DKBUILD_MODNAME=\\"gsim\\" ' + \
    '-DMODVERSIONS -DEXPORT_SYMTAB  -include linux/config.h'
# ...
glb_cflags = '-include nsc_override.h '

# -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 '

include_path = [ 
    'include', 
    'include/asm/mach-default', 
    '../sim', 'nsc', 'override' ]

cc = 'gcc'
cxx = 'g++'
arch_i386 = os.getenv('NSC_TARGET_ARCHITECTURE')
if not arch_i386:
   arch_i386 = True
else:
   if arch_i386 == 'amd64':
       arch_i386 = False
   else:
       arch_i386 = True

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

# older mercurial versions have problems with
# symbolic links being stored in the repository, so
# we create the needed link here instead.
if not os.path.exists("include/asm"):
  os.symlink("asm-x86", "include/asm")

as_flags = '-D__ASSEMBLY__'
if arch_i386:
    linker_script = 'arch/x86/kernel/linker-script-32.ld'
    cflags += '-DCONFIG_X86_32=1 '
else:
    linker_script = 'arch/x86/kernel/linker-script-64.ld'
    ext_cflags += '-fPIC '
    as_flags += '-fPIC '
    cflags += '-DCONFIG_X86_64=1 '

cflags += ext_cflags

Import('default_env')

env = default_env.Clone(CC=cc, CCFLAGS = cflags, CPPPATH = include_path,
        GLB_CCFLAGS = glb_cflags, GLB_LIST = curdir + '/global_list.txt',
        LINK = cxx)
drv_env = default_env.Clone(CC=cc, CCFLAGS = cflags + '-DEXPORT_SYMTAB',
        GLB_CCFLAGS = glb_cflags, GLB_LIST = curdir + '/global_list.txt',
        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
use_globaliser = True
parsed_sources = []

if arch_i386:
    parsed_sources.append('arch/x86/lib/checksum_32.S')
else:
    parsed_sources.append('arch/x86/lib/csum-copy_64.S')
    parsed_sources.append('arch/x86/lib/getuser_64.S')
    parsed_sources.append('arch/x86/lib/csum-partial_64.c')
    parsed_sources.append('arch/x86/lib/csum-wrappers_64.c')


# The following isn't just "for i in src" because we need to get the order
# correct.
for i in src:
    if use_globaliser:
        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'])
    else:
        output = os.path.splitext(i)[0]+'.o'
        if i[:7] == 'drivers':
            parsed_sources.append( drv_env.Object(output, i) )
        else:
            parsed_sources.append( env.Object(output, i) )

#####
ss = sim_env.SharedObject('nsc/sim_support.cpp')
parsed_sources.append(ss)


# Using Program and -shared is a hacky way to make a shared library in SCons
# without requiring -fPIC.
output = env.Program(source = parsed_sources, target = 'lib' + stackname + '.so',
# We need a special linker script to set up some variables for
# initialisation in Linux
    LINKFLAGS = link_flags + '-shared -Wl,-O1 -Wl,-T' + curdir + linker_script,
    ASFLAGS = as_flags
)

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