#! /bin/sh # click-buildtool -- build tools for Click # Eddie Kohler # # Copyright (c) 2000-2001 Massachusetts Institute of Technology # Copyright (c) 2000-2006 Mazu Networks, Inc. # Copyright (c) 2001-2003 International Computer Science Institute # Copyright (c) 2004-2006 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=@prefix@ exec_prefix=@exec_prefix@ bindir=@bindir@ datadir=@datadir@ clickdatadir=@clickdatadir@ LINUXMODULE_2_6=@LINUXMODULE_2_6@ gmake=@GMAKE@ verbose="" elem2="" default_provisions="@provisions@" driver_provisions="@DRIVERS@" trap "exit 1" HUP # find a good version of awk if test -x /usr/bin/gawk; then awk=gawk elif test -x /usr/bin/nawk; then awk=nawk else awk=awk fi echo_n () { # suns can't echo -n, and Mac OS X can't echo "x\c" echo "$@" | tr -d ' ' } ############ # FINDELEM # ############ findelem_usage () { echo "Usage: click-buildtool findelem [-a] [-V] [-p PREFIX] < [FILES AND DIRECTORIES] Try 'click-buildtool findelem --help' for more information." 1>&2 exit 1 } elementmap_provisions () { elementmap="$1" grep "^&2 'Click-buildtool findelem' locates valid Click element source code. It starts with a collection of source code, then eliminates files whose requirements are not available until reaching a stable set of sources. It expects a list of files and directories on standard input. Directories are searched for .cc/.c source files. Only files containing EXPORT_ELEMENT() or ELEMENT_PROVIDES() are considered. The initial list of available requirements is the list of requirements specified with '-r', plus the list of EXPORT_ELEMENT() and ELEMENT_PROVIDES() keywords. Usage: click-buildtool findelem [OPTIONS] < [FILES AND DIRECTORIES] Options: -a, --all Include all subdirectories of 'elements' rather than reading standard input, and pretend all requirements are available (except for '-x'). -V, --verbose Print more information about dependency checking. -p, --prefix PREFIX Prepend PREFIX to every file and/or directory. -r, --provide REQ Provide requirement(s) in REQ. -e, --elementmap EMAP Provide requirement(s) from EMAP. -P, --package Provide requirement(s) from default elementmap. -S, --standards Mark standard elements as available. -x, --unprovide REQ Mark requirement(s) REQ as unavailable. -f, --filenames Output filenames only. -F, --filename-pairs Output "sourcefile:headerfile" pairs for elements. -h, --help Print this message and exit. Report bugs to . EOF exit 0;; *) findelem_usage;; esac done if test -n "$verbose" -a -n "$pfx"; then echo "Prefix: $pfx" 1>&2 fi # add defaults to provisions provisions="$provisions $default_provisions" # add standards to provisions if necessary if test "x$standards" != x; then provisions="$provisions AddressInfo AlignmentInfo ErrorElement PortInfo ScheduleInfo Storage" fi # expand provisions and unprovisions: require one per line provisions=`echo "$provisions" | tr -s ' \011\015\014\013' '\012'` unprovisions=`echo "$unprovisions" | tr -s ' \011\015\014\013' '\012'` if test -n "$verbose" -a -n "$provisions"; then echo 1>&2 echo "Provisions: $provisions" 1>&2 fi if test -n "$verbose" -a -n "$unprovisions"; then echo 1>&2 echo "Unprovisions: $unprovisions" 1>&2 fi # expand list of files if test -n "$all"; then fdir=${pfx} test -d ${pfx}elements && fdir=${pfx}elements first_files=`cd $fdir >/dev/null && ls` bad_first_files=`echo "$first_files $unprovisions" | sort | uniq -d` first_files=`echo "$first_files $bad_first_files" | sort | uniq -u` else first_files=`cat` fi files="" for i in $first_files; do ppfx="$pfx" if test -d "${pfx}elements/$i" && echo "$i" | grep -v '^\.' >/dev/null; then ppfx="${pfx}elements/" fi if test -d "${ppfx}$i"; then files="$files "`find ${ppfx}$i -follow \( -name \*.cc -o -name \*.c \) -print | grep -v '/[.,][^/]*$'` elif test -r "${ppfx}$i"; then files="$files ${ppfx}$i" fi done files=`echo "$files" | sort | uniq | grep .` # die if no files if test -z "$files"; then echo "no files found" 1>&2 exit 1 fi # if '$all', then accept all dependencies except the unprovisions dep_test='<=' if test -n "$all"; then dep_test='<' fi # check dependencies: generate a list of bad files, then remove those files # from the list of good files # first remove files that provide an unprovision awk_exports=`echo "$unprovisions" | sed 's/\(..*\)/dep["\1"]=-1;/'` bad_files=`egrep '^EXPORT_ELEMENT|^ELEMENT_PROVIDES' $files | sed 's/EXPORT_ELEMENT[ ]*(\(.*\)).*/\1/ s/ELEMENT_PROVIDES[ ]*(\(.*\)).*/\1/' | $awk -F: 'BEGIN {OFS="";'"$awk_exports"'} { split($2, deps, / +/); for (j in deps) { if (dep[deps[j]] < 0) { print $1; break; } } }' | sort | uniq` if test -n "$verbose" -a -n "$bad_files"; then echo 1>&2 echo "Files: $files" 1>&2 echo 1>&2 echo "Bad files: $bad_files" 1>&2 fi if test -n "$bad_files"; then files=`echo "$files $bad_files" | sort | uniq -u` fi # then cycle, removing files that require something not provided while true; do provides=`egrep '^EXPORT_ELEMENT|^ELEMENT_PROVIDES' $files | sed 's/.*(\(.*\)).*/\1/' | tr ' \011' '\012'` awk_exports=`echo "$provides"' '"$provisions" | sed 's/\(..*\)/dep["\1"]=1;/'`" "`echo "$unprovisions" | sed 's/\(..*\)/dep["\1"]=-1;/'` new_bad_files=`grep '^ELEMENT_REQUIRES' $files | sed 's/ELEMENT_REQUIRES[ ]*(\(.*\)).*/\1/' | $awk -F: 'BEGIN {OFS="";'"$awk_exports"'dep["true"]=1; dep["1"]=1;} { split($2, deps, / +/); for (j in deps) { i = deps[j] if (dep[i] <= 0) { bad = 1; split(i, or_deps, /\|+/); for (k in or_deps) { if (!(dep[or_deps[k]] '"$dep_test"' 0)) bad = 0; } if (bad) { print $1; break; } } } }' | sort | uniq` if test -n "$verbose"; then echo 1>&2 echo "Files: $files" 1>&2 echo 1>&2 echo "Bad files: $new_bad_files" 1>&2 fi if test -z "$new_bad_files"; then break else files=`echo "$files $new_bad_files" | sort | uniq -u` bad_files="$new_bad_files $bad_files" fi done header_files=`echo "$files" | sed 's/\.cc/\.hh/'` # generate output if test "$filenames" = f; then outscriptlet=i elif test "$filenames" = F; then outscriptlet='i, ":", header[i]' else echo "# Generated by 'click-buildtool findelem' on" `date` outscriptlet='i, "\t", header[i], "\t", ex' fi egrep '^ELEMENT_PROVIDES|^EXPORT_ELEMENT|^ELEMENT_HEADER|^ELEMENT_LIBS|^class|^[ ]*const *char *\* *class_name|^[ ]*static *void *static_[ic]|^}' $files $header_files /dev/null 2>/dev/null | $awk -F: 'BEGIN { OFS = ""; cur_class = ""; line_warned = 0; nexports = 0 } /:class[ ]/ { sub(/^class[ ]*/, "", $2); sub(/[ ]*$/, "", $2); cur_class = $2; next } /:}/ { cur_class = ""; next } /:EXPORT_ELEMENT/ { sub(/.*EXPORT_ELEMENT[ ]*\([ ]*/, "", $2); sub(/[ ]*\).*/, "", $2); if (exports[$1] != "") { exports[$1] = exports[$1] " " $2 } else { exports[$1] = $2; nexports++ } next } /:ELEMENT_PROVIDES/ { if (!($1 in exports)) { exports[$1] = ""; nexports++ } next } /:ELEMENT_HEADER/ { sub(/.*ELEMENT_HEADER[ ]*\(/, "", $2) sub(/\).*/, "", $2) header[$1] = $2 next } /:ELEMENT_LIBS/ { sub(/.*ELEMENT_LIBS[ ]*\(/, "", $2) sub(/\).*/, "", $2) gsub(/[ ][ ]*/, ";", $2) gsub(/-L;/, "-L", $2) libs[$1] = $2 next } /class_name.*return[ ]"/ { sub(/.*return[ ]*"/, "", $0); sub(/".*/, "", $0); class_name[cur_class] = $0 next } /class_name/ { print $1, ": ", cur_class, "::class_name method malformed" | "cat 1>&2" if (++line_warned == 1) print " (class_name methods must be written on a single line.)" | "cat 1>&2" } /static_initialize/ { static_initialize[cur_class] = 1 next } /static_cleanup/ { static_cleanup[cur_class] = 1 next } END { if (nexports == 0) print "click-buildtool: No elements found" | "cat 1>&2" if (line_warned || nexports == 0) system("kill -HUP '$$'") for (i in exports) { ex = exports[i] if (ex == "") { print i } else { if (header[i] == "") { header[i] = "\"" i "\""; sub(/\.cc/, ".hh", header[i]) } split(ex, exes, / /); ex = "" for (j in exes) { dash = index(exes[j], "-") if (dash == 0) { dash = length(exes[j]); if (class_name[exes[j]] == "") exes[j] = exes[j] "-" exes[j]; else exes[j] = exes[j] "-" class_name[exes[j]]; } ex = ex exes[j] " "; klass = substr(exes[j], 1, dash) if (static_initialize[klass]) { ex = ex klass "-!si "; static_initialize[klass] = 0 } if (static_cleanup[klass]) { ex = ex klass "-!sc "; static_cleanup[klass] = 0 } } if (libs[i]) ex = ex "-!lib" libs[i] " "; print '"$outscriptlet"' } } }' | sort exit $? } ########################## # ELEM2MAKE/ELEM2PACKAGE # ########################## elem2xxx_usage () { echo_n "Usage: click-buildtool elem2$elem2 [-p PREFIX] [-V]" 1>&2 if test "$elem2" = package; then echo_n " PKGNAME" 1>&2; fi echo " < elements.conf Try 'click-buildtool elem2$elem2 --help' for more information." 1>&2 exit 1 } elem2make () { driver="" makevar="" date=`date` linux26=x while [ x"$1" != x ]; do case $1 in -t|--d|--dr|--dri|--driv|--drive|--driver) if test $# -lt 2; then elem2xxx_usage; fi shift 1; driver="$1"; shift 1;; -t*) driver=`echo "$1" | sed 's/^-D//'`; shift 1;; --d=*|--dr=*|--dri=*|--driv=*|--drive=*|--driver=*) driver=`echo "$1" | sed 's/^[^=]*=//'`; shift 1;; --t|--ta|--tar|--targ|--targe|--target) if test $# -lt 2; then elem2xxx_usage; fi shift 1; driver="$1"; shift 1;; --t=*|--ta=*|--tar=*|--targ=*|--targe=*|--target=*) driver=`echo "$1" | sed 's/^[^=]*=//'`; shift 1;; -v|--m|--ma|--mak|--make|--make-|--make-v|--make-va|--make-var|--make-vari|--make-varia|--make-variab|--make-variabl|--make-variable) if test $# -lt 2; then elem2xxx_usage; fi shift 1; makevar="$1"; shift 1;; -v*) makevar=`echo "$1" | sed 's/^-v//'`; shift 1;; --m=*|--ma=*|--mak=*|--make=*|--make-=*|--make-v=*|--make-va=*|--make-var=*|--make-vari=*|--make-varia=*|--make-variab=*|--make-variabl=*|--make-variable=*) makevar=`echo "$1" | sed 's/^[^=]*=//'`; shift 1;; -x|--e|--ex|--exc|--excl|--exclu|--exclud|--exclude) if test $# -lt 2; then elem2xxx_usage; fi shift 1 for i in $1; do excludes=";/^$i"' \\$'"/d$excludes"; done shift 1;; -x*) this_exclude=`echo "$1" | sed 's/^-p//'` for i in $this_exclude; do excludes=";/^$i"' \\$'"/d$excludes"; done shift 1;; --e=*|--ex=*|--exc=*|--excl=*|--exclu=*|--exclud=*|--exclude=*) this_exclude=`echo "$1" | sed 's/^[^=]*=//'` for i in $this_exclude; do excludes=";/^$i"' \\$'"/d$excludes"; done shift 1;; --l|--li|--lin|--linu|--linux|--linux2|--linux26) linux26=1; shift 1;; --no-l|--no-li|--no-lin|--no-linu|--no-linux|--no-linux2|--no-linux26) linux26=0; shift 1;; -V|--verb|--verbo|--verbos|--verbose) verbose=1; shift 1;; -h|--h|--he|--hel|--help) cat <<'EOF' 1>&2 'Click-buildtool elem2make' reads an 'elements.conf' file generated by 'click-buildtool findelem' on the standard input, and writes a Makefile fragment defining the ELEMENT_OBJS variable to the standard output. Usage: click-buildtool elem2make [-t DRIVER] [-V] < elements.conf Options: -t, --driver DRIVER Set target driver to DRIVER ('userlevel', 'linuxmodule', 'bsdmodule', 'ns', or 'tool'). -v, --make-variable N Use make variable N. --linux26 Generate Linux 2.6-style makefile fragment. -x, --exclude FILE Do not include FILE. -V, --verbose Print more information. -h, --help Print this message and exit. Report bugs to . EOF exit 0;; *) elem2xxx_usage;; esac done L= defmakevar="ELEMENT_OBJS" if test -n "$driver"; then if test "$driver" = 'user' -o "$driver" = 'userlevel'; then L=u elif test "$driver" = 'kernel' -o "$driver" = 'linuxmodule'; then L=k test "$linux26" = x && linux26="$LINUXMODULE_2_6" elif test "$driver" = 'bsdmodule'; then L=b elif test "$driver" = 'ns' -o "$driver" = 'nsmodule'; then L=n elif test "$driver" = 'tool'; then L=t else echo "Unknown driver $driver" 1>&2 exit 1 fi fi osuffix=".${L}o" if test -z "$makevar"; then makevar=$defmakevar fi # expand list of files elemconf=`cat` files=`echo "$elemconf" | grep -v '^#' | sed 's/[ ].*//'` # find libraries libs=`echo "$elemconf" | sed '/-!lib/!d;s/^.*-!lib//g;s/;/ /g' | grep .` test -n "$libs" && libs=`echo "$libs" | tsort` # massage awk script based on Linux 2.6 or not if test "$linux26" = 1; then set_subdir_scriptlet=' if (dir != "" && substr(dir, 1, 1) == "/") subdirs[dirid] = dir; else subdirs[dirid] = "$(obj)/" dir; ' pattern_scriptlet='$(addprefix $(obj)/,$('"$makevar"'__", i, ")): $(obj)/%'"$osuffix" ccaction=' $(call if_changed_dep,cxxcompile)' caction=' $(call if_changed_dep,ccompile)' else set_subdir_scriptlet='subdirs[dirid] = dir;' pattern_scriptlet='$('"$makevar"'__", i, "): %'"$osuffix" ccaction=' $(call cxxcompile,-c $< -o $@,CXX)' caction=' $(call ccompile,-c $< -o $@,CC)' if test -n "$L"; then ccaction="$ccaction"'\n $(FIXDEP)' caction="$caction"'\n $(FIXDEP)' fi fi # output echo "# Generated by 'click-buildtool elem2make' on" `date` echo "$files" | $awk ' BEGIN { OFS = "" action["c"] = "'"$caction"'"; action["cc"] = "'"$ccaction"'"; } { filetype = ($0 ~ /\.c$/ ? "c" : "cc"); sub(/\.cc*$/, "'"$osuffix"'"); i = match($0, /\/[^\/]*$/); if (i == 0) { dir = ""; file = $0; } else { dir = substr($0, 1, RSTART); file = substr($0, RSTART + 1); } decdir = filetype dir; if (decdir in subdirid) dirid = subdirid[decdir]; else { dirid = nsubdirs++; subdirid[decdir] = dirid; subdirtype[dirid] = filetype; '"$set_subdir_scriptlet"' } elements[dirid] = elements[dirid] file " \\\n"; } END { for (i = 0; i < nsubdirs; i++) { print "'"$makevar"'__", i, " = \\\n", elements[i]; allsubdirs = allsubdirs "$('"$makevar"'__" i ") \\\n"; } print "'"$makevar"' = \\\n", allsubdirs; for (i = 0; i < nsubdirs; i++) { print "'"$pattern_scriptlet"': ", subdirs[i], "%.", subdirtype[i]; print action[subdirtype[i]]; } }' | sed "$excludes" echo if test -n "$libs"; then libvar=`echo $makevar | sed 's/OBJS$/LIBS/'` echo $libvar = $libs fi } elem2xxx () { package="" date=`date` standards='' includes='' while [ x"$1" != x ]; do case $1 in -S|--s|--st|--sta|--stan|--stand|--standa|--standar|--standard|--standards) standards=1; shift 1;; -V|--verb|--verbo|--verbos|--verbose) verbose=1; shift 1;; -i|--i|--in|--inc|--incl|--inclu|--includ|--include) if test $# -lt 2; then elem2xxx_usage; fi includes="$includes print '#include $2';"; shift 2;; -i*) this_include=`echo "$1" | sed 's/^-i//'` includes="$includes print '#include $this_include';"; shift 1;; --i=*|--in=*|--inc=*|--incl=*|--inclu=*|--includ=*|--include=*) this_include=`echo "$1" | sed 's/^[^=]*=//'` includes="$includes print '#include $this_include';"; shift 1;; -h|--h|--he|--hel|--help) if test "$elem2" = export; then cat <<'EOF' 1>&2 'Click-buildtool elem2export' reads an 'elements.conf' file generated by 'click-buildtool findelem' on the standard input, examines those files for exported elements, and writes a C++ source file defining the click_export_elements() function to the standard output. Usage: click-buildtool elem2export [-V] < elements.conf EOF elif test "$elem2" = package; then cat <<'EOF' 1>&2 'Click-buildtool elem2package' reads an 'elements.conf' file generated by 'click-buildtool findelem' on the standard input, examines those files for exported elements, and writes a C++ source file suitable for creating a dynamically linked package with those elements to the standard output. PKGNAME is the name of the package. Usage: click-buildtool elem2package [-p PREFIX] [-V] PKGNAME < elements.conf EOF fi cat <<'EOF' 1>&2 Options: -S, --standards Export standard required elements as well. -i, --include HDR Emit "#include HDR" at top of file. -V, --verbose Print more information. -h, --help Print this message and exit. Report bugs to . EOF exit 0;; -*) elem2xxx_usage;; *) if test -z "$package" -a "$elem2" = package; then package="$1"; shift 1; else elem2xxx_usage; fi;; esac done # set up awk program if test -n "$package"; then includes=" $includes "'print "#define WANT_MOD_USE_COUNT 1\n#include \n#include \n#include "; for (file in INCLUDES) { if (file != "-") print "#include ", file; }' awk_program='BEGIN { OFS = ""; nrebecca = 0; packname="'"$package"'"; } /^#/ { next; } { if (NF == 1) next; INCLUDES[$2] = 1; for (i = 3; i <= NF; i++) { split($i, ans, /-/); if (ans[2] == "!si") B = B " " ans[1] "::static_initialize();\n"; else if (ans[2] == "!sc") C = C " " ans[1] "::static_cleanup();\n"; else if (ans[2] !~ /^!/) { B = B " hatred_of_rebecca[" nrebecca "] = click_add_element_type(\"" ans[2] "\", beetlemonkey, " nrebecca ");\n" C = C " click_remove_element_type(hatred_of_rebecca[" nrebecca "]);\n"; D = D " case " nrebecca ": return new " ans[1] ";\n"; nrebecca++; } } } END { print "/* Generated by \"click-buildtool elem2package\" on '"$date"' */"; print "/* Package name: ", packname, " */\n"; '"$includes"' print "\nCLICK_USING_DECLS"; print "static int hatred_of_rebecca[", nrebecca, "];"; print "static Element *\nbeetlemonkey(uintptr_t heywood)\n{\n switch (heywood) {\n", D, " default: return 0;\n }\n}\n"; print "#ifdef CLICK_LINUXMODULE\n#define click_add_element_type(n, f, t) click_add_element_type((n), (f), (t), THIS_MODULE)\n#endif"; print "#ifdef CLICK_BSDMODULE\nstatic int\nmodevent(module_t, int t, void *)\n{\n if (t == MOD_LOAD) {\n#else\nextern \"C\" int\ninit_module()\n{\n#endif"; print " click_provide(\"", packname, "\");\n", B, " CLICK_DMALLOC_REG(\"nXXX\");\n return 0;"; print "#ifdef CLICK_BSDMODULE\n } else if (t == MOD_UNLOAD) {\n#else\n}\nextern \"C\" void\ncleanup_module()\n{\n#endif"; print C, " click_unprovide(\"", packname, "\");"; print "#ifdef CLICK_BSDMODULE\n return 0;\n } else\n return 0;\n}\nstatic moduledata_t modinfo = {\n \"", packname, "\", modevent, 0\n};\nDECLARE_MODULE(", packname, ", modinfo, SI_SUB_PSEUDO, SI_ORDER_ANY);\n#else\n}\n#endif"; } ' else includes="$includes"' print "#include \n#include "; for (file in INCLUDES) { if (file != "-") print "#include ", file; }' awk_program='BEGIN { OFS = ""; nrebecca = 0; } /^#/ { next; } { if (NF == 1) next; INCLUDES[$2] = 1; for (i = 3; i <= NF; i++) { split($i, ans, /-/); if (ans[2] == "!si") B = B " " ans[1] "::static_initialize();\n"; else if (ans[2] == "!sc") C = C " " ans[1] "::static_cleanup();\n"; else if (ans[2] !~ /^!/) { B = B " (void) click_add_element_type(\"" ans[2] "\", beetlemonkey, " nrebecca ");\n"; D = D " case " nrebecca ": return new " ans[1] ";\n"; } nrebecca++; } } END { print "/* Generated by \"click-buildtool elem2export\" on '"$date"' */\n"; '"$includes"' print "CLICK_USING_DECLS"; print "static Element *\nbeetlemonkey(uintptr_t heywood)\n{\n switch (heywood) {\n", D, " default: return 0;\n }\n}\n"; print "#ifdef CLICK_LINUXMODULE\n#define click_add_element_type(n, f, t) click_add_element_type((n), (f), (t), 0)\n#endif"; print "void\nclick_export_elements()\n{\n", B, " CLICK_DMALLOC_REG(\"nXXX\");\n}\n"; print "void\nclick_unexport_elements()\n{\n", C, "}"; } ' fi # Actually generate the command! if test -z "$standards"; then $awk "$awk_program" else cat </tmp/click-buildtool-standards.$$ - AddressInfo-AddressInfo - AlignmentInfo-AlignmentInfo - ErrorElement-ErrorElement - PortInfo-PortInfo - ScheduleInfo-ScheduleInfo EOF cat - /tmp/click-buildtool-standards.$$ | $awk "$awk_program" /bin/rm -f /tmp/click-buildtool-standards.$$ fi } ############ # PROVIDES # ############ provides_usage () { echo "Usage: click-buildtool provides [REQS]" 1>&2 echo "Try 'click-buildtool provides --help' for more information." 1>&2 exit 1 } provides () { provisions="$default_provisions $driver_provisions "`elementmap_provisions ${clickdatadir}/elementmap.xml` requirements="" stdin=n; query=n; print=n while [ x"$1" != x ]; do case $1 in -q|--q|--qu|--que|--quer|--query) query=y; shift 1;; -l|--pri|--prin|--print) print=y; shift 1;; -r|--pro|--prov|--provi|--provid|--provide) if test $# -lt 2; then provides_usage; fi shift 1; provisions="$1 $provisions"; shift 1;; -r*) provisions=`echo "$1" | sed 's/^-r//'`" $provisions"; shift 1;; --p=*|--pr=*|--pro=*|--prov=*|--provi=*|--provid=*|--provide=*) provisions=`echo "$1" | sed 's/^[^=]*=//'`" $provisions"; shift 1;; -e|--e|--el|--ele|--elem|--eleme|--elemen|--element|--elementm|--elementma|--elementmap) if test $# -lt 2; then provides_usage; fi shift 1; provisions=`elementmap_provisions $1`" $provisions"; shift 1;; -e*) emap=`echo "$1" | sed 's/^-e//'` provisions=`elementmap_provisions $emap`" $provisions"; shift 1;; --e=*|--el=*|--ele=*|--elem=*|--eleme=*|--elemen=*|--element=*|--elementm=*|--elementma=*|--elementmap=*) emap=`echo "$1" | sed 's/^[^=]*=//'` provisions=`elementmap_provisions $emap`" $provisions"; shift 1;; -h|--h|--he|--hel|--help) cat <<'EOF' 1>&2 'Click-buildtool provides' exits with status 0 if the Click installation provides all requirement(s) in REQ arguments, and status 1 otherwise. Usage: click-buildtool provides [OPTIONS] [REQ...] Options: -q, --query Print provisions to standard output. -r, --provide REQ Provide requirement(s) in REQ. -e, --elementmap EMAP Provide requirement(s) from EMAP. -l, --print Print 0 (REQs not provided) or 1 (REQs provided). -h, --help Print this message and exit. Report bugs to . EOF exit 0;; -) stdin=y; shift 1;; -*) provides_usage;; *) requirements="$1 $requirements"; shift 1;; esac done [ $stdin = y ] && requirements="`cat` $requirements" provisions="`echo "$provisions" | tr -s ' \011\015\014\013' '\012' | grep . | sort | uniq`" [ $query = y ] && echo "$provisions" requirements="`echo "$requirements" | tr -s ' \011\015\014\013' '\012' | grep . | sort | uniq`" awk_provisions="`echo "$provisions" | sed 's/\(..*\)/dep["\1"]=1;/'`" echo "$requirements" | $awk -F: 'BEGIN { '"$awk_provisions"' } /./ { if (!dep[$1]) exit 1; }' >/dev/null 2>&1 status=$? [ $print = y ] && expr 1 - $status exit $status } ############# # QUIETLINK # ############# quietlink_usage () { echo "Usage: click-buildtool quietlink" 1>&2 echo "Try 'click-buildtool quietlink --help' for more information." 1>&2 exit 1 } quietlink () { while [ x"$1" != x ]; do case $1 in -h|--h|--he|--hel|--help) cat <<'EOF' 1>&2 'Click-buildtool quietlink' quiets the GNU linker when linking an element package. Specifically, it removes undefined reference complaints. Usage: ld ... 2>&1 | click-buildtool quietlink Options: -h, --help Print this message and exit. Report bugs to . EOF exit 0;; *) quietlink_usage;; esac done $awk -F: 'BEGIN { context = "" } /: In function/ { context = $0 next } /: undefined reference to/ { next } /: more undefined references to/ { next } { if (context != "") { print context context = "" } print $0 }' 1>&2 } ########## # PREFIX # ########## prefix_usage () { echo "Usage: click-buildtool prefix" 1>&2 echo "Try 'click-buildtool prefix --help' for more information." 1>&2 exit 1 } prefix () { while [ x"$1" != x ]; do case $1 in -h|--h|--he|--hel|--help) cat <<'EOF' 1>&2 'Click-buildtool prefix' prints the Click prefix directory. Usage: click-buildtool prefix Options: -h, --help Print this message and exit. Report bugs to . EOF exit 0;; *) prefix_usage;; esac done echo $prefix } ############ # KVERSION # ############ kversion_usage () { echo_n "Usage: click-buildtool kversion [--gpl] > kversion.c" 1>&2 echo "Try 'click-buildtool kversion --help' for more information." 1>&2 exit 1 } kversion () { gpl=0 linux26=$LINUXMODULE_2_6 while [ x"$1" != x ]; do case $1 in --g|--gp|--gpl) gpl=1; shift 1;; -h|--h|--he|--hel|--help) cat <<'EOF' 1>&2 'Click-buildtool kversion' writes a kversion.c file, to be used for building a Click kernel package, on the standard output. Usage: click-buildtool kversion [--gpl] > kversion.c Options: --gpl The package is dual-licensed BSD/GPL (otherwise no license). -h, --help Print this message and exit. Report bugs to . EOF exit 0;; *) kversion_usage;; esac done cat < #include #include /* a new version of EXPORT_NO_SYMBOLS that works */ const int __ksymtab_nothing[0] __attribute__((section("__ksymtab"))) = { }; EOF test $gpl = 1 && cat < Kbuild" 1>&2 echo "Try 'click-buildtool kbuild --help' for more information." 1>&2 exit 1 } kbuild () { while [ x"$1" != x ]; do case $1 in -h|--h|--he|--hel|--help) cat <<'EOF' 1>&2 'Click-buildtool kbuild' writes a Kbuild file, to be used for building a Click kernel package for Linux 2.6 kernels, on the standard output. Usage: click-buildtool kbuild > Kbuild Options: -h, --help Print this message and exit. Report bugs to . EOF exit 0;; *) kversion_usage;; esac done echo "include ${clickdatadir}/pkg-linuxmodule-26.mk" } ############### # MAKEPACKAGE # ############### makepackage_usage () { echo "Usage: click-buildtool makepackage [-t DRIVER] PACKAGENAME SRCFILES..." 1>&2 echo "Try 'click-buildtool makepackage for more information." 1>&2 exit 1 } makepackage () { driver="" date=`date` dir= pkg= srcs= quiet= while [ x"$1" != x ]; do case $1 in -t|--d|--dr|--dri|--driv|--drive|--driver) test $# -lt 2 && makepackage_usage shift 1; driver="$1"; shift 1;; -t*) driver=`echo "$1" | sed 's/^-D//'`; shift 1;; --dr=*|--dri=*|--driv=*|--drive=*|--driver=*) driver=`echo "$1" | sed 's/^[^=]*=//'`; shift 1;; --t|--ta|--tar|--targ|--targe|--target) test $# -lt 2 && makepackage_usage shift 1; driver="$1"; shift 1;; --t=*|--ta=*|--tar=*|--targ=*|--targe=*|--target=*) driver=`echo "$1" | sed 's/^[^=]*=//'`; shift 1;; -C|--di|--dir|--dire|--direc|--direct|--directo|--director|--directory) test $# -lt 2 && makepackage_usage shift 1; dir="$1"; shift 1;; -C*) dir="`echo "$1" | sed 's/^-C//'`"/; shift 1;; --di=*|--dir=*|--dire=*|--direc=*|--direct=*|--directo=*|--director=*|--directory=*) dir="`echo "$1" | sed 's/^[^=]*=//'`"/; shift 1;; -q|--q|--qu|--qui|--quie|--quiet) quiet="-s"; shift 1;; -h|--h|--he|--hel|--help) cat <<'EOF' 1>&2 'Click-buildtool makepackage' builds a Click package for the specified driver from sources listed on the command line. Usage: click-buildtool makepackage [-t DRIVER] PACKAGENAME SRCFILES... Options: -t, --driver DRIVER Set target driver to DRIVER ('userlevel', 'linuxmodule', 'bsdmodule', 'ns', or 'tool'). -q, --quiet Build quietly (may be ignored). -C, --directory DIR Switch to DIR directory before building. -h, --help Print this message and exit. Report bugs to . EOF exit 0;; *) if test -z "$pkg"; then pkg="$1"; shift 1 else srcs="$srcs $1"; shift 1 fi;; esac done test -z "$srcs" && makepackage_usage objs= objsvar=OBJS if test -z "$driver" -o "$driver" = 'user' -o "$driver" = 'userlevel'; then L=u elif test "$driver" = 'kernel' -o "$driver" = 'linuxmodule'; then L=k elif test "$driver" = 'bsdmodule'; then L=b elif test "$driver" = 'ns' -o "$driver" = 'nsmodule'; then L=n elif test "$driver" = 'tool'; then L=t else echo "Unknown driver $driver" 1>&2 exit 1 fi osuffix=".${L}o" if test -n "$dir"; then cd "$dir"; fi echo > ${L}elements.conf echo "$srcs" | grep . | elem2make -t $driver > ${L}elements.mk echo "PACKAGE_OBJS :=" >> ${L}elements.mk echo "package = $pkg srcdir = . top_srcdir = . builddir = . top_builddir = . include ${clickdatadir}/config.mk include ${clickdatadir}/pkg-Makefile" > Makefile test -z "$quiet" && echo "+" $gmake $pkg$osuffix $gmake $quiet $pkg$osuffix } ######### # KSYMS # ######### ksyms_usage () { echo "Usage: click-buildtool ksyms OBJ... > KSYMS" 1>&2 echo "Try 'click-buildtool ksyms --help' for more information." 1>&2 exit 1 } ksyms () { driver="" date=`date` dir= objs= exclude= while [ x"$1" != x ]; do case $1 in -C|--di|--dir|--dire|--direc|--direct|--directo|--director|--directory) test $# -lt 2 && ksyms_usage shift 1; dir="$1"; shift 1;; -C*) dir="`echo "$1" | sed 's/^-C//'`"/; shift 1;; --di=*|--dir=*|--dire=*|--direc=*|--direct=*|--directo=*|--director=*|--directory=*) dir="`echo "$1" | sed 's/^[^=]*=//'`"/; shift 1;; -x|--e|--ex|--exc|--excl|--exclu|--exclud|--exclude) test $# -lt 2 && ksyms_usage shift 1; exclude="$exclude $1"; shift 1;; -x*) exclude="$exclude `echo "$1" | sed 's/^-x//'`"; shift 1;; --e=*|--ex=*|--exc=*|--excl=*|--exclu=*|--exclud=*|--exclude=*) exclude="$exclude `echo "$1" | sed 's/^[^=]*=//'`"; shift 1;; -h|--h|--he|--hel|--help) cat <<'EOF' 1>&2 'Click-buildtool ksyms' creates a C file that exports all symbols for the Click objects listed on the command line. Usage: click-buildtool ksyms OBJ... > KSYMS Options: -x, --exclude=FILE Ignore OBJ even if it is supplied as an argument. -C, --directory DIR Switch to DIR directory before running. -h, --help Print this message and exit. Report bugs to . EOF exit 0;; *) objs="$objs $1"; shift 1;; esac done test -z "$objs" && ksyms_usage objs=`echo "$objs" | sort | uniq` test -n "$exclude" && objs=`echo "$objs $exclude" | sort | uniq -u` if test -n "$dir"; then cd "$dir"; fi echo "// Created by 'click-buildtool ksyms' on $date" echo "#include " echo "#include " echo "#include " nm -g $objs | $awk ' BEGIN { printed["init_module"] = printed["cleanup_module"] = 1; } /^[ ]/ { next } /........[ ][ABCDGRSTVW]/ { x = $3; if (x ~ /^[_A-Za-z][_A-Za-z0-9]*$/ && !printed[x]) { printed[x] = 1; print "extern char " x "[];"; print "EXPORT_SYMBOL(" x ");"; } }' } ################ # MAIN PROGRAM # ################ if test $# = 0; then # force usage message set crapfunc fi while [ x"$1" != x ]; do case $1 in --vers|--versi|--versio|--version) cat <<'EOF' click-buildtool (Click) @CLICK_VERSION@ Copyright (c) 2000-2001 Massachusetts Institute of Technology Copyright (c) 2000-2004 Mazu Networks, Inc. Copyright (c) 2001-2003 International Computer Science Institute Copyright (c) 2004-2006 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 a particular purpose. EOF exit 0;; -V|--verb|--verbo|--verbos|--verbose) verbose=1; shift 1;; -h|--h|--he|--hel|--help) cat <<'EOF' 1>&2 'Click-buildtool' is a set of tools used when building Click. For information on a particular tool, run 'click-buildtool TOOLNAME --help'. Usage: click-buildtool elem2make [-V] [-p PREFIX] < [ELEMENTS] or: click-buildtool elem2export [-V] [-p PREFIX] < [ELEMENTS] or: click-buildtool elem2package [-V] [-p PREFIX] PACKAGENAME < [ELEMENTS] or: click-buildtool findelem [-a] [-V] [-p PREFIX] < [FILES AND DIRECTORIES] or: click-buildtool makepackage [-t DRIVER] PACKAGENAME SRCFILES... or: click-buildtool prefix or: click-buildtool provides [REQS] or: click-buildtool quietlink or: click-buildtool kbuild or: click-buildtool kversion [--gpl] or: click-buildtool ksyms OBJS > KSYMSFILE Options: -V, --verbose Print more information. -h, --help Print this message and exit. --version Print version number and exit. Report bugs to . EOF exit 0;; findelem) shift 1; findelem "$@"; exit 0;; elem2make) elem2="make"; shift 1; elem2make "$@"; exit 0;; elem2export) elem2="export"; shift 1; elem2xxx "$@"; exit 0;; elem2package) elem2="package"; shift 1; elem2xxx "$@"; exit 0;; makepackage) shift 1; makepackage "$@"; exit 0;; prefix) shift 1; prefix "$@"; exit 0;; provides) shift 1; provides "$@"; exit 0;; quietlink) shift 1; quietlink "$@"; exit 0;; kversion) shift 1; kversion "$@"; exit 0;; kbuild) shift 1; kbuild "$@"; exit 0;; ksyms) shift 1; ksyms "$@"; exit 0;; *) echo "Usage: click-buildtool TOOLNAME [ARGUMENTS] Try 'click-buildtool --help' for more information." 1>&2 exit 1;; esac done