#!/bin/ash # # This is a shell version of the bcc compiler driver. It's a little slower # than a C version but overall seems to be a lot cleaner, perhaps a C version # based on this might be a good idea ... # # The compiler works on a 'modal' basis certain flags given to it put the # compiler into specific modes, it can only be in one mode for a run. # # The mode defines the basic passes and specific options that are available # # To define a mode see the functions 'run_0' and 'run_3' for examples. The # variable assignments just above the definitions enable the functions. # # This script is specifically designed so the there is as little interaction # between the modes as is possible. # # It's run using ash because this appears to be _much_ faster than bash, it's # also reasonable with ksh. # (On other interpreters I think perl would be too big, but awk might work...) # TMPFIL="/tmp/cc$$" trap "rm -f $TMPFIL.* ; exit 1" 1 2 3 15 TMPCNT=0 FILES= OPTS= RESEXTN= OPTIM=no VERBOSE=no MULTISRC=no LDOPTS= DESTDEF=no LDDEST=a.out DEFMODE=0 ccmode= LIBPATH="/lib:/usr/lib:/usr/bin" main() { scanargs "$@" PATH="$LIBPATH:$PATH" [ "$EXEC_PREFIX" != "" ] && PATH="$EXEC_PREFIX:$PATH" rv=0 LDFILES= [ "$MULTISRC" = yes -o "$RESEXTN" = "" ] && DESTDEF=no for FILE in $FILES do case "$FILE" in *.c ) PASS=cpp ; BASE="`basename $FILE .c`" ;; *.s ) PASS=as ; BASE="`basename $FILE .s`" ;; * ) PASS=lnk ;; esac NAME="`basename $FILE`" DEST="`dirname $FILE`/" [ "$DEST" = "./" ] && DEST= DEST="$DEST$BASE.$RESEXTN" [ "$DESTDEF" = yes ] && DEST="$LDDEST" STEMP=0 INTEMP=0 [ "$PASS" = "cpp" ] && { compile $FILE || rv=$? ; } [ "$PASS" = "as" ] && { assem $FILE || rv=$? ; } if [ "$PASS" = "lnk" ] then LDFILES="$LDFILES $FILE" else # If there's a fail can't link - still assembling to temps tho. [ "$RESEXTN" = "" ] && RESEXTN=O fi [ "$STEMP" = 1 ] && rm -f "$SFILE" [ "$INTEMP" = 1 ] && RMFILES="$RMFILES $FILE" done [ "$RESEXTN" != "" ] && exit $rv [ "$VERBOSE" = yes ] && echo "$LD $SYSLIB $LDOPTS $LDFLAGS -o $LDDEST $CRT0 $LDFILES $LIBS" $LD $SYSLIB $LDOPTS $LDFLAGS -o $LDDEST $CRT0 $LDFILES $LIBS rv=$? [ "$RMFILES" != "" ] && rm -f $RMFILES exit "$rv" } scanargs() { WILDOPT=no while [ "$#" -gt 0 ] do case "$1" in -[DU]* ) CPPDEFS="$CPPDEFS $1" ;; -B?* ) PATH="`echo '.$1:$PATH' | sed 's/...//'`" ;; -I?* ) CPPFLAGS="$CPPFLAGS $1" ;; -L?* ) LDOPTS="$LDOPTS $1" ;; -o ) LDDEST="$2"; DESTDEF=yes ; shift ;; -b ) . /usr/lib/idcc/opts_$2 || exit 1; shift ;; -E ) RESEXTN=i ;; -S ) RESEXTN=s ;; -c ) RESEXTN=o ;; -O ) OPTIM=yes ;; -v ) VERBOSE=yes ;; -l?* ) FILES="$FILES $1" ; MULTISRC=yes ;; -* ) OPTS="$OPTS `echo .$1 | sed 's/..//'`" ;; * ) [ "$FILES" != "" ] && MULTISRC=yes ; FILES="$FILES $1" ;; esac shift done while [ "$OPTS" != "" -o "$DEFMODE" != "" ] do # So they can try again ... with DEFMODE if needed MOPTS="$OPTS" OPTS= for opt in $MOPTS do # Option can be defined only for specific mode so if we haven't seen # the mode yet save the opt. If we have check for conflicts too. [ "$ccmode" = "" -a "$DEFMODE" != "" ] && { eval "[ \"\$opt_$opt\" = yes ]" || { OPTS="$OPTS $opt" ; opt= ; } } [ "$opt" != "" ] && { [ "$ccmode" = "" ] || { eval "[ \"\$mode_$opt\" = yes ]" && { echo Option "-$opt incompatible with -$ccmode" 1>&2 exit 2 } } eval "[ \"\$opt_$opt\" = yes ]" || { { eval "[ \"$WILDOPT\" = yes ]" && wild_opt "-$opt" ; } || { echo Option '-'$opt unknown for this mode 1>&2 exit 3 } } eval "[ \"\$opt_$opt\" = yes ]" && run_$opt eval "[ \"\$mode_$opt\" = yes ]" && ccmode="$opt" } done [ "$ccmode" = "" -a "$DEFMODE" != "" ] && OPTS="$DEFMODE $OPTS" DEFMODE= done } compile() { [ -r "$FILE" ] || { echo "Cannot open $FILE" 1>&2 ; return 1 ; } [ "$RESEXTN" = "i" ] && { cpp_only $FILE return } # Loop for the pass list # The CCX variables _are_ expanded again. ret=1 for pass in $PASSLIST do for extn in '' pre post inf res opt do eval "CCX$extn=\"\$CC$pass$extn\"" done [ "$CCX" = "" ] && continue; [ "$OPTIM" = "" -a "$CCXopt" = yes ] && continue; shuffel "$RESEXTN" $CCXres [ "$VERBOSE" = yes ] && eval "echo \"$CCX $CCXpre $SFILE $CCXinf $FILE $CCXpost\"" eval "$CCX $CCXpre $SFILE $CCXinf $FILE $CCXpost" || return 1 ret=0 done [ "$ret" = 1 ] && { echo 'CC configuration error' 1>&2 ; return $ret ; } [ "$RESEXTN" != "s" ] && PASS=as return 0 } assem() { [ -r "$FILE" ] || { echo "Cannot open $FILE" 1>&2 ; return 1 ; } shuffel "$RESEXTN" o n= [ "$ASNAME" != "" ] && n="$ASNAME$NAME" [ "$VERBOSE" = yes ] && echo "$AS $ASFLAGS $n $SFILE -o $FILE" $AS $ASFLAGS $n $SFILE -o $FILE || return [ "$RESEXTN" != "o" ] && PASS=lnk return 0 } if [ "2" = "$[1+1]" ] ; then inc_tmpcnt() { TMPCNT="$[$TMPCNT+1]" ; } else inc_tmpcnt() { TMPCNT="`expr $TMPCNT + 1`" ; } fi shuffel() { [ "$STEMP" = 1 ] && rm -f "$SFILE" SFILE="$FILE" STEMP="$INTEMP" if [ "$1" = "$2" ] then FILE="$DEST" INTEMP=0 else inc_tmpcnt FILE="$TMPFIL.$TMPCNT.$2" INTEMP=1 fi } mode_0=yes opt_0=yes run_0() { SYSINC="-I/usr/bcc/include" SYSLIB="-L/usr/bcc/lib/bcc/i86/" LIBPATH="/usr/bcc/lib/bcc" CRT0="-C0" LIBS="-lc" CGEN= DEFS= CPP="cpp" PASSLIST=2 CC2="bcc-cc1" CC2pre='$SYSINC $DEFS $CPPFLAGS' CC2inf='-o' CC2post='-0 $CGEN $CPPDEFS' CC2res=s AS="as86" ASFLAGS='-u -w -0' ASNAME='-n ' LD="ld86" LDFLAGS='-i -0' opt_ansi=yes run_ansi() { PASSLIST="0 1 2" CC0="bcc-cc1" CC0pre='$SYSINC $DEFS $CPPFLAGS' CC0inf='-o' CC0post='-0 -E -D__STDC__=0 $CPPDEFS' CC0res=i CC1="unproto" CC1pre='' CC1inf='' CC1post='' CC1res=k CC2="bcc-cc1" CC2pre='$CGEN' CC2inf='-o' CC2post='-0' CC2res=s } opt_I=yes; run_I() { SYSINC= ; } opt_L=yes; run_L() { SYSLIB= ; } opt_s=yes; run_s() { LDFLAGS="$LDFLAGS -s" ; } opt_Mf=yes; run_Mf() { LIBS=-lc_f ; CGEN='-f -c' ;} opt_Md=yes; run_Md() { LIBS=-ldos ; DEFS='-D__MSDOS__' LDFLAGS='-i -0 -d' ;} WILDOPT=yes wild_opt() { case "$1" in -O* ) OPTIM=yes ; OPTFLG="$OPTFLG $1" ;; * ) return 1 ;; # For normal CC operation unknowns go to the linker. ie: # * ) LDFLAGS="$LDFLAGS $1" ; return 0 ;; esac return 0 } } mode_3=yes opt_3=yes run_3() { SYSINC="-I/usr/bcc/include" SYSLIB="-L/usr/bcc/lib/bcc/i386/" LIBPATH="/usr/bcc/lib/bcc" CRT0="-C0" LIBS="-lc" CGEN= DEFS= CPP="cpp" PASSLIST=2 CC2="bcc-cc3" CC2pre='$SYSINC $DEFS $CPPFLAGS' CC2inf='-o' CC2post='-3 $CGEN $CPPDEFS' CC2res=s AS="as86" ASFLAGS='-u -w -3' ASNAME='-n ' LD="ld86" LDFLAGS='-i -3' opt_ansi=yes run_ansi() { PASSLIST="0 1 2" CC0="bcc-cc3" CC0pre='$SYSINC $DEFS $CPPFLAGS' CC0inf='-o' CC0post='-3 -E -D__STDC__=0 $CPPDEFS' CC0res=i CC1="unproto" CC1pre='' CC1inf='' CC1post='' CC1res=k CC2="bcc-cc1" CC2pre='$CGEN' CC2inf='-o' CC2post='-3' CC2res=s } opt_I=yes; run_I() { SYSINC= ; } opt_L=yes; run_L() { SYSLIB= ; } opt_s=yes; run_s() { LDFLAGS="$LDFLAGS -s" ; } WILDOPT=yes wild_opt() { case "$1" in -O* ) OPTIM=yes ; OPTFLG="$OPTFLG $1" ;; * ) return 1 ;; esac return 0 } } main "$@"