#!/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= 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" done [ "$RESEXTN" != "" ] && { rm -f $TMPFIL.* exit $rv } [ "$VERBOSE" = yes ] && eval "echo \"$LINK\"" 1>&2 eval "$LINK" rv=$? rm -f $TMPFIL.* 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 ;; -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 ; } # Loop for the pass list # The CCX variables _are_ expanded again. ret=1 for pass in $PASSLIST do for extn in '' res opt do eval "CCX$extn=\"\$CC$pass$extn\"" done [ "$CCX" = "" ] && continue; shuffel "$RESEXTN" $CCXres [ "$VERBOSE" = yes ] && eval "echo \"$CCX\"" 1>&2 eval "$CCX" || return 1 ret=0 [ "$CCXres" = "$RESEXTN" ] && break done [ "$ret" = 1 ] && { echo 'CC configuration error' 1>&2 ; return $ret ; } [ "$RESEXTN" != "$CCXres" ] && 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" 1>&2 $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='-0' DEFS= CPP="cpp" PASSLIST=2 CC2='bcc-cc1 $SYSINC $DEFS $CPPDEFS $CPPFLAGS $CGEN $SFILE -o $FILE' CC2res=s AS="as86" ASFLAGS='-u -w -0' ASNAME='-n ' LINK='ld86 $SYSLIB $LDOPTS $LDFLAGS -o $LDDEST $CRT0 $LDFILES $LIBS' LDFLAGS='-i -0' [ "$RESEXTN" = "i" ] && { PASSLIST="0" CC0='bcc-cc1 $SYSINC $DEFS $CPPDEFS $CPPFLAGS $CGEN $SFILE -E' CC0res=i } opt_ansi=yes run_ansi() { PASSLIST="0 1 2" CC0='bcc-cc1 $SYSINC $DEFS $CPPDEFS $CPPFLAGS $CGEN $SFILE -o $FILE -E' CC0res=k CC1res=i CC1='unproto $SFILE $FILE' CC2res=s CC2='bcc-cc1 $CGEN $SFILE -o $FILE' DEFS='-D__STDC__=0' } opt_I=yes; run_I() { SYSINC= ; } opt_L=yes; run_L() { SYSLIB= ; } opt_O=yes; run_O() { echo Warning -O ignored 1>&2 ; } opt_Mf=yes; run_Mf() { LIBS=-lc_f ; CGEN='-0 -f -c' ;} opt_Md=yes; run_Md() { LIBS=-ldos ; DEFS=$DEFS' -D__MSDOS__' LDFLAGS='-i -0 -d' ;} WILDOPT=yes wild_opt() { case "$1" in # For normal CC operation unknowns go to the linker. ie: # * ) LDFLAGS="$LDFLAGS $1" ; return 0 ;; # But do this instead. -[dMizmts] ) LDFLAGS="$LDFLAGS $1" ; return 0 ;; -[dMizmt]- ) LDFLAGS="$LDFLAGS $1" ; return 0 ;; -T* ) LDFLAGS="$LDFLAGS $1" ; return 0 ;; * ) return 1 ;; 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='-3' DEFS= CPP="cpp" PASSLIST=2 CC2='bcc-cc1 $SYSINC $DEFS $CPPDEFS $CPPFLAGS $CGEN $SFILE -o $FILE' CC2res=s AS="as86" ASFLAGS='-u -w -3' ASNAME='-n ' LINK='ld86 $SYSLIB $LDOPTS $LDFLAGS -o $LDDEST $CRT0 $LDFILES $LIBS' LDFLAGS='-3' [ "$RESEXTN" = "i" ] && { PASSLIST="0" CC0='bcc-cc1 $SYSINC $DEFS $CPPDEFS $CPPFLAGS $CGEN $SFILE -E' CC0res=i } opt_ansi=yes run_ansi() { PASSLIST="0 1 2" CC0='bcc-cc1 $SYSINC $DEFS $CPPDEFS $CPPFLAGS $CGEN $SFILE -o $FILE -E' CC0res=k CC1res=i CC1='unproto $SFILE $FILE' CC2res=s CC2='bcc-cc1 $CGEN $SFILE -o $FILE' DEFS='-D__STDC__=0' } opt_I=yes; run_I() { SYSINC= ; } opt_L=yes; run_L() { SYSLIB= ; } opt_O=yes; run_O() { echo Warning -O ignored 1>&2 ; } WILDOPT=yes wild_opt() { case "$1" in # For normal CC operation unknowns go to the linker. ie: # * ) LDFLAGS="$LDFLAGS $1" ; return 0 ;; # But do this instead. -[dMizmts] ) LDFLAGS="$LDFLAGS $1" ; return 0 ;; -[dMizmt]- ) LDFLAGS="$LDFLAGS $1" ; return 0 ;; -T* ) LDFLAGS="$LDFLAGS $1" ; return 0 ;; * ) return 1 ;; esac return 0 } } main "$@"