#! /bin/sh

# click-compile.in -- script compiles Click elements
# Eddie Kohler
#
# Copyright (c) 1999 Massachusetts Institute of Technology
# Copyright (c) 2001 International Computer Science Institute
# Copyright (c) 2005 Regents of the University of California
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, subject to the conditions
# listed in the Click LICENSE file. These conditions include: you must
# preserve this copyright notice, and you cannot mention the copyright
# holders in advertising related to the Software without their permission.
# The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
# notice is a summary of the Click LICENSE file; the license in that file is
# legally binding.

prefix=/usr/local
exec_prefix=${prefix}
includedir=/usr/local/include
libdir=/usr/local/lib
datadir=/usr/local/share
srcdir=${datadir}/click/src
linuxdir=NONE
freebsd_includedir=/usr/include
CLICK_VERSION=1.5.0

# determine mode
directory=.
driver=
package=NONE
cflags=
compileflag=-c
quiet=
gpl=y
while true; do
    bad=x
    case $1 in
      -t|--dr|--dri|--driv|--drive|--driver)
	driver=$2; shift 2;;
      -t*)
        driver=`echo "$1" | sed 's/^-t//'`; shift 1;;
      --dr=*|--dri=*|--driv=*|--drive=*|--driver=*)
	driver=`echo "$1" | sed 's/[-a-z]*=//'`; shift 1;;
      --de|--def|--defs)
	echo  -I$includedir
	exit 0;;
      --l|--li|--lib|--libs)
	echo -L$libdir -lclick -lpcap  
	exit 0;;
      --o|--ot|--oth|--othe|--other|--otherl|--otherli|--otherlib|--otherlibs)
	echo -lpcap  
	exit 0;;
      -d|--di|--dir|--dire|--direc|--direct|--directo|--director|--directory)
	directory=$2; shift 2;;
      -d*)
	directory=`echo "$1" | sed 's/^-d//'`; shift 1;;
      --di=*|--dir=*|--dire=*|--direc=*|--direct=*|--directo=*|--director=*|--directory=*)
	directory=`echo "$1" | sed 's/^[^=]*=//'`; shift 1;;
      --t|--ta|--tar|--targ|--targe|--target)
        echo "click-compile: '--target' is obsolete; change your script to use '--driver'" 1>&2
	driver=$2; shift 2;;
      --t=*|--ta=*|--tar=*|--targ=*|--targe=*|--target=*)
        echo "click-compile: '--target' is obsolete; change your script to use '--driver'" 1>&2
	driver=`echo "$1" | sed 's/[-a-z]*=//'`; shift 1;;
      -p|--p|--pa|--pac|--pack|--packa|--packag|--package)
	package=$2; shift 2;;
      -p*)
	package=`echo "$1" | sed 's/^-p//'`; shift 1;;
      --p=*|--pa=*|--pac=*|--pack=*|--packa=*|--packag=*|--package=*)
	package=`echo "$1" | sed 's/[-a-z]*=//'`; shift 1;;
      -q|--q|--qu|--qui|--quie|--quiet)
	quiet=y; shift 1;;
      --no-g|--no-gp|--no-gpl)
	gpl=n; shift 1;;
      -h|--h|--he|--hel|--help)
	cat <<'EOF'
'Click-compile' compiles a Click source file, or outputs any compiler options
relevant for userlevel Click drivers.

Usage: click-compile -t DRIVER [OPTIONS] SOURCEFILE...

Options:
      --defs              Outputs preprocessor options for userlevel drivers.
      --libs              Outputs link options for userlevel drivers.
      --otherlibs         Like '--libs' minus the Click library.
  -t, --driver DRIVER     Sets target driver to 'bsdmodule', 'linuxmodule',
                          'userlevel', 'ns', or 'tool'.
  -p, --package PACKAGE   Build a dynamically loadable package named PACKAGE.
  -d, --directory DIR     Change to directory DIR.
  -q, --quiet             Be quiet (don't echo commands or print warnings).
      --no-gpl            Omit "BSD/GPL" declaration from kernel package.
  -h, --help              Print this message and exit.
  -v, --version           Print version number and exit.
  Other options are passed to the compiler unchanged.

Report bugs to <click@pdos.lcs.mit.edu>.
EOF
	exit 0;;
      -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
	echo click-compile '(Click)' $CLICK_VERSION
	cat <<"EOF"
Copyright (C) 1999-2001 Massachusetts Institute of Technology
Copyright (C) 2002 International Computer Science Institute
Copyright (C) 2004 Regents of the University of California
This is free software; see the source for copying conditions.
There is NO warranty, not even for merchantability or fitness for any
particular purpose.
EOF
	exit 0;;
      -*)
	if test "$1" = -E -o "$1" = -c -o "$1" = -S; then
	    compileflag=$1
	else
	    cflags="$cflags '$1'"
	fi
	shift 1;;
      *)
	bad=;;
    esac
    if test -z "$bad"; then break; fi
done

cd $directory

# test directory function
test_dir () {
    test -d "$1" -a -d "$1/elements" -a -d "$1/lib"
}

# analyze CLICKPATH to find sources
path=${CLICKPATH-:}
tried_defaults=
include_source=
while true; do
    case $path in
      :*)
	if test -z "$tried_defaults" && test_dir "$srcdir"; then
	    include_source="-I$srcdir"
	else
	    tried_defaults=y
	fi
	path=`echo "$path" | sed 's/://'`
	;;
      *:*)
	dir=`echo "$path" | sed 's/:.*//'`
	if test_dir "$dir"; then include_source="-I$dir"; fi
	path=`echo "$path" | sed 's/[^:]*://'`
	;;
      *:)
	dir=`echo "$path" | sed 's/:.*//'`
	if test_dir "$dir"; then include_source="-I$dir"; fi
	path=":"
	;;
      *)
	if test_dir "$path"; then include_source="-I$path"; fi
	path=""
	;;
    esac
    if test -z "$path" -o -n "$include_source"; then break; fi
done

if test ! -d "$includedir"; then
    echo "click-compile: Cannot find Click include directory!" 1>&2
    echo "  (Have you installed Click yet?)" 1>&2
    exit 1
elif test -z "$include_source"; then
    if test -z "$quiet"; then
	echo "click-compile: warning: cannot find full Click source" 1>&2
    fi
fi


case $driver in
  u|us|use|user|userl|userle|userlev|userleve|userlevel)
    idefs="-DHAVE_CONFIG_H -DCLICK_USERLEVEL"
    iincludes="${include_source} -I${includedir}"
    icppflags=""
    icxxflags="-fPIC -O2 -pipe -fno-strict-aliasing "
    icflags="-fPIC -O2 -pipe -fno-strict-aliasing "
    command="${CXX-c++} ${DEFS-$idefs} ${INCLUDES-$iincludes} ${CPPFLAGS-$icppflags} ${CXXFLAGS-$icxxflags} $cflags $compileflag"
    c_command="${CC-cc} ${DEFS-$idefs} ${INCLUDES-$iincludes} ${CPPFLAGS-$icppflags} ${CFLAGS-$icflags} $cflags $compileflag"
    driver=userlevel;;
  k|ke|ker|kern|kerne|kernel|l|li|lin|linu|linux|linuxm|linuxmo|linuxmod|linuxmodu|linuxmodul|linuxmodule)
    idefs="-DHAVE_CONFIG_H -DCLICK_LINUXMODULE"
    iincludes="${include_source} -I${includedir} -I${linuxdir}/include"
    icppflags=""
    icxxflags="-O2 -pipe -fno-strict-aliasing "
    icflags="-O2 -pipe -fno-strict-aliasing "
    command="${CXX-c++ -w  -fno-exceptions -fno-rtti } ${DEFS-$idefs} ${INCLUDES-$iincludes} ${CPPFLAGS-$icppflags} ${CXXFLAGS-$icxxflags} $cflags $compileflag"
    c_command="${CC-cc} ${DEFS-$idefs} ${INCLUDES-$iincludes} ${CPPFLAGS-$icppflags} ${CFLAGS-$icflags} $cflags $compileflag"
    driver=linuxmodule;;
  b|bs|bsd|bsdm|bsdmo|bsdmod|bsdmodu|bsdmodul|bsdmodule)
    idefs="-DHAVE_CONFIG_H -DCLICK_BSDMODULE"
    iincludes="-nostdinc ${include_source} -I${includedir}"
    icppflags=""
    icxxflags="-O2 -pipe -fno-strict-aliasing "
    icflags="-O2 -pipe -fno-strict-aliasing "
    command="${CXX-c++ -w  -fno-exceptions -fno-rtti } ${DEFS-$idefs} ${INCLUDES-$iincludes} ${CPPFLAGS-$icppflags} ${CXXFLAGS-$icxxflags} $cflags $compileflag"
    c_command="${CC-cc} ${DEFS-$idefs} ${INCLUDES-$iincludes} ${CPPFLAGS-$icppflags} ${CFLAGS-$icflags} $cflags $compileflag"
    driver=bsdmodule;;
  ns|nsm|nsmo|nsmod|nsmodu|nsmodul|nsmodule)
    idefs="-DHAVE_CONFIG_H -DCLICK_NS"
    iincludes="${include_source} -I${includedir}"
    icppflags=""
    icxxflags="-fPIC -O2 -pipe -fno-strict-aliasing "
    icflags="-fPIC -O2 -pipe -fno-strict-aliasing "
    command="${CXX-c++} ${DEFS-$idefs} ${INCLUDES-$iincludes} ${CPPFLAGS-$icppflags} ${CXXFLAGS-$icxxflags} $cflags $compileflag"
    c_command="${CC-cc} ${DEFS-$idefs} ${INCLUDES-$iincludes} ${CPPFLAGS-$icppflags} ${CFLAGS-$icflags} $cflags $compileflag"
    driver=ns;;
  t|to|too|tool)
    idefs="-DHAVE_CONFIG_H -DCLICK_TOOL"
    iincludes="${include_source} -I${includedir}"
    icppflags=""
    icxxflags="-fPIC -O2 -pipe -fno-strict-aliasing "
    icflags="-fPIC -O2 -pipe -fno-strict-aliasing "
    command="${CXX-c++} ${DEFS-$idefs} ${INCLUDES-$iincludes} ${CPPFLAGS-$icppflags} ${CXXFLAGS-$icxxflags} $cflags $compileflag"
    c_command="${CC-cc} ${DEFS-$idefs} ${INCLUDES-$iincludes} ${CPPFLAGS-$icppflags} ${CFLAGS-$icflags} $cflags $compileflag"
    driver=tool;;
  "")
    echo "click-compile: you must specify a driver" 1>&2; exit 1;;
  *)
    echo "click-compile: acceptable drivers are 'userlevel', 'linuxmodule'," 1>&2
    echo "click-compile:   'bsdmodule', and 'tool'" 1>&2; exit 1;;
esac

exec_command () {
    if test -z "$quiet"; then
	echo "$@" 1>&2
    fi
    eval "$@" || exit 1
}

compile_file () {
    option=
    source="$1"; shift
    if test -r "$source"; then
	option=`head -n 5 $source | grep '^/\*\* click-compile:' | sed -e 's/\/\*\* click-compile://g' -e 's/\*\///g'`
    fi
    exec_command $command $option $source "$@"
}

# do stuff
if test "x$package" != "xNONE"; then
    command="$command -DCLICK_PACKAGE"
    files=; rmfiles=
    trap 'rm -f $rmfiles' 0
    trap 'rm -f $rmfiles; exit 1' 1 2 15
    for file; do
	if echo "$file" | grep '\.cc*$' >/dev/null 2>&1; then
	    objfile=`echo "$file" | sed 's/\.c*$/'"$$"'\.o/;s/^.*\///'`
	    compile_file $file -o $objfile
	    rmfiles="$rmfiles $objfile "`echo $objfile | sed 's/\.o/\.d/'`
	else
	    objfile="$file"
	fi
	files="$files $objfile"
    done
    if test $driver = linuxmodule; then
	vfile=kernelversion$$
	test -f $vfile.c && echo "click-compile: A file '$vfile.c' already exists in this directory!" 1>&2 && echo "click-compile: You must remove it, or run me somewhere else." 1>&2 && exit 1
	files="$files $vfile.o"
	rmfiles="$rmfiles $vfile.o $vfile.c $vfile.d"
	cat > $vfile.c <<EOF
#include <click/config.h>
#include <linux/module.h>
/* a new version of EXPORT_NO_SYMBOLS that works */
const int __ksymtab_nothing[0] __attribute__((section("__ksymtab"))) = { };
EOF
	if test $gpl = y; then
	    cat >> $vfile.c <<EOF
#ifdef MODULE_LICENSE
MODULE_LICENSE("Dual BSD/GPL");
#endif
EOF
	fi
	c_command_nowarn=`echo $c_command | sed 's/-W[-a-z]*//g'`
	exec_command $c_command_nowarn $vfile.c
	exec_command "ld -r -o $package $cflags $files"
	exit 0
    elif test $driver = userlevel -o $driver = tool -o $driver = ns; then
	exec_command "${CXX-c++} ${CXXFLAGS-$icxxflags} -shared -o $package $cflags $files"
	exit 0
    elif test $driver = bsdmodule; then
	exec_command "ld -Bshareable -o $package $cflags $files"
	exit 0
    fi
else
    exec_command "$command $@"
    exit 0
fi
