#!/usr/bin/env bash # # IRIX-MIPSpro-wrapper, Copyright 2008 Stuart Shelton # # This program is free software: you can redistribute it and/or modify # it under the terms of version 3 of the GNU General Public License as # published by the Free Software Foundation. # # 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, see . # # # IRIX-MIPSpro-wrapper: A tool to mangle binutils arguments to # automagically insert the library paths and includes required # to build software successfully in a prefix-portage environment. # # Required tools: # /bin/uname /sbin/hinv tr grep cut sed sort head # # # Environment variables which will affect operation... # wrapper="${MIPSPRO_WRAPPER:-1}" debug="${MIPSPRO_DEBUG:-0}" verbose="${MIPSPRO_VERBOSE:-0}" allownostd="${MIPSPRO_ALLOWNOSTD:-0}" permissive="${MIPSPRO_PERMISSIVE:-0}" # These should be auto-detected, but you may wish to change # OLIMIT or MIPSPRO_OPT. MIPSPRO_PLATFORM="${MIPSPRO_PLATFORM:-$( /bin/uname -m | \ tr [:upper:] [:lower:] )}" MIPSPRO_CPU="${MIPSPRO_CPU:-$( /sbin/hinv -c processor | \ grep ^CPU | cut -d" " -f 3 | tr [:upper:] [:lower:] )}" MIPSPRO_ISA="${MIPSPRO_ISA:-mips4}" MIPSPRO_ABI="${MIPSPRO_ABI:--n32}" OLIMIT="${OLIMIT:-8192}" OPTIMISE="${MIPSPRO_OPT:--O2}" # # Change nothing below here... # tool="$( basename "$0" )" name="IRIX-MIPSpro-wrapper" function die() { echo >&2 "$@" exit 1 } # die() function ifverbose() { (( verbose )) && echo -e "$name: $*" >&2 return $(( ! verbose )) } # ifverbose() function ifdebug() { (( debug )) && echo -e "\n$name$*\n" >&2 return $(( ! debug )) } # ifdebug() # FIXME for broken sys-libs/db test "$tool" = "none" && exit 0 test "$tool" = "ranlib" && exit 0 if test "$USER" != "portage"; then echo -e "\nWARNING: Not using MIPSpro wrapper for non-portage build!" echo " Please check your \$PATH" wrapper=0 fi test -n "${EPREFIX}" || die "FATAL: \${EPREFIX} is not set, cannot continue" case $tool in cc|c89|c99|CC|ld) (( wrapper )) || exec "/bin/$tool" "$@" ;; cpp) ifdebug ": !!BUG!!: Incorrect use of legacy (non-ANSI)/Fortran cpp" >&2 (( wrapper )) || exec /lib/cpp "$@" ;; *) die "FATAL: Unknown utility \"$tool\"" ;; esac shopt -s extglob || die "FATAL: Cannot enable shell option 'extglob'," \ "is $( type -p bash ) really bash?" function main() { local input="$@" local output ifdebug ": input:\t$tool $input" # Pass 1 - Join arguments where possible # # (This code attempts to do this entirely in-shell, but could be greatly # simplified through the use of sed...) # function pass1() { local input="$@" local prefix expect argument local skip=0 squash=0 unset output for argument in $input; do case $argument in -v|-verbose|--verbose) verbose=1 ;; esac if test -n "$prefix"; then case $prefix in "-Ofast= ") prefix="-Ofast=" expect="ip*" squash=1 ;; esac if test -n "$expect"; then case $argument in $expect) ifverbose "NOTICE: pass1: Found expected" \ "argument sequence $prefix $argument" (( squash )) \ && prefix="$prefix$argument " \ || prefix="$prefix $argument " unset argument unset expect squash=0 continue ;; *) ifverbose "INFO: pass1: Didn't find" \ "anticipated follow-on argument, adding $prefix" output="$output $prefix" unset prefix unset expect squash=0 esac else ifdebug ": DEBUG: pass1: Squashing \"$prefix $argument\"" argument="$prefix$argument" unset prefix fi fi # NB: -L is a synonym for -nostdlib, but -Ldir is the same as -L dir # so we need to know whether the following argument is an option # if ! (( skip )); then case $argument in -D|-I|-J|-l|-U|-W|-Y) prefix="$argument" ;; -G) prefix="$argument" expect="[0-9]*" squash=1 ;; -g) prefix="$argument" expect="[0-3s]*" squash=1 ;; -L) prefix="$argument" expect="[^-]*" squash=1 ;; -Ofast) prefix="$argument" expect="=*" squash=1 ;; --) skip=1 ;; esac fi test -z "$prefix" && output="$output $argument" done test -n "$prefix" && output="$output $prefix" } # pass1() function checkcppflags() { local input="$@" local skip argument swallow local found=1 unset output # Check for unknown arguments... # while (( found )); do found=0 skip=0 swallow=0 for argument in $input; do if ! (( skip )) && ! (( swallow )); then case $argument in -W*([fbalR])p*([fbalR]),*) output="$output $( echo "$argument" | \ sed 's!^-W[fbalR]*p[fbalR]*,!! ; s!,-! -!g' )" # Now we have that, let's go around again... # found=1 skip=1 ;; --) output="$output $argument" skip=1 ;; # These options are correct for MIPSpro 7.4.4m # Earlier verions may only support a subset, but there # should be no false negatives. # -C|-D*|-I*|-M|-max_rec_depth\=+([0-9])|-MDtarget|-MDupdate|-P|-U*) output="$output $argument" ;; -*) # Try to catch some common issues with passing # C(XX)FLAGS to cpp... case $argument in *) if (( permissive )); then ifverbose "WARNING: cpp: Unrecognised preprocessor option \"$argument\" passed" output="$output $argument" else ifverbose "WARNING: cpp: Unrecognised preprocessor option \"$argument\" dropped" fi ;; esac ;; *) output="$output $argument" ;; esac elif (( swallow )); then ifverbose "WARNING: cpp: Dropping follow-on argument \"$argument\"" swallow=0 else output="$output $argument" fi done done } # checkcppflags() function checkldflags() { local input="$@" local skip argument swallow progress local found=1 unset output # Check for unknown arguments... # while (( found )); do found=0 skip=0 swallow=0 for argument in $input; do if ! (( skip )) && ! (( swallow )); then case $argument in -W*([pfbaR])l*([pfbaR]),*) output="$output $( echo "$argument" | sed 's!^-W[pfbaR]*l[pfbaR]*,!! ; s!,-! -!g' )" # Now we have that, let's go around again... # found=1 skip=1 ;; --) output="$output $argument" skip=1 ;; -L|-nostdlib) if (( allownostd )); then output="$output $argument" else ifverbose "WARNING: ld: $argument passed to $tool, option dropped" fi ;; # These options are correct for MIPSpro 7.4.4m # Earlier verions may only support a subset, but there should be no false negatives. # Note that the -V (version) option also attempts to link objects, so shouldn't receive special treatment # -B?(direct)|-cckr|-cxx|-l*|-L*|-std|-no_archive|-u| \ -?(not)all|-exclude|-from|-make_cmdfile|-MDignore|-MDupdate|-objectlist| \ -aoutkeep|-f|-?(no)info|-m|-M|-show?(_unref)|-split_common|-v|-V|-y*| \ -LD_MSG:*|-allow_missing|-demangle|-?(dont_)warn_unused|-ignore_unresolved|-no_unresolved|-wall|-woff| \ -s|-x| \ -?(n)32|-64|-abi|-call_shared|-elf|-mips[2-4]|-?(non_)shared|-r| \ -d|-D|-elsmap|-elspec|-G*([0-9])|-?(no)ivpad|-LD_LAYOUT:*|-n|-N|-rdata_writable|-rdata_shared| \ -T*([0-9a-fA-F])|-Xlocal|-z| \ -LD_DYNAMIC\:rhf_mips_flags\=*|-?(default_)delay_load|-e|-exact_version|-exports?(_file)| \ -exported_symbol|-fini|-force_load|-full_transitive_link|-hiddens_file|-hidden_symbol|-hides|-I*| \ -ignore_minor|-ignore_version|-init|-no_library_replacement|-no_rqs|-?(no_)transitive_link| \ -require_minor|-rpath|-set_version|-soname| \ -mmap|-read| \ -allow_jump_at_eop|-no_jump_at_eop| \ -check_registry|-update_registry|-create_registry| \ -_SYSTYPE_SVR4|-o|-VS| \ -Wx,-G) output="$output $argument" ;; -a) output="$output -non_shared" ;; -ajeop) output="$output -allow_jump_at_eop" ;; -dn) output="$output -non_shared" ;; -dy) output="$output -call_shared" ;; -h) output="$output -soname" ;; -hides_files) output="$output -hiddens_file" ;; -none) output="$output -notall" ;; -o32) output="$output -32" ;; -OPT:reorg_common) output="$output -ivpad" ;; -rpath,*) output="$output $( echo "$argument" | sed -r 's!-rpath,(.*)$!-rpath \1!' )" ;; -SYSTYPE_SVR4) output="$output -_SYSTYPE_SVR4" ;; -U) output="$output -ignore_unresolved" ;; -w) output="$output -wall" ;; -Xlocaldata) output="$output -Xlocal" ;; -?(no)count|-gpinfo|-quickstart_info| \ -Xnobsschange|-X?(no)sortbss|-X?(nd)block|-Xblockrange|-Xndlocaldata|-X?(no)alignbss|-Xcachemisalign| \ -Xcache?(line)size|-Xdefmovemax|-Xsetalign|-Xdebug) ifverbose "WARNING: ld: Obsolete option \"$argument\" dropped" ;; -*) # Try to catch some common issues with passing C(XX)FLAGS to ld... case $argument in -diag_*) swallow=1 ;; *) if (( permissive )); then ifverbose "WARNING: ld: Unrecognised linker option \"$argument\" passed" output="$output $argument" else ifverbose "WARNING: ld: Unrecognised linker option \"$argument\" dropped" fi ;; esac ;; *) output="$output $argument" ;; esac elif (( swallow )); then ifverbose "WARNING: ld: Dropping follow-on argument \"$argument\"" swallow=0 else output="$output $argument" fi done done } # checkldflags() function checkcflags() { local input="$@" local argument progress local skip=0 unset output # Check for unknown arguments... # for argument in $input; do if ! (( skip )); then case $argument in -?(-)help) exec "/bin/$tool" "-help" ;; -?(-)version) exec "/bin/$tool" "-version" ;; --) output="$output $argument" skip=1 ;; -nostdinc) if (( allownostd )); then output="$output $argument" else ifverbose "WARNING: cc: $argument passed to $tool, option dropped" fi ;; # These options are correct for MIPSpro 7.4.4m # Earlier verions may only support a subset, but there should be no false negatives. # -?([on])32|-64| \ -all|-anach|-?(x)ansi|-cckr|-ansi[EW]|-apo|-apokeep|-apolist|-ar|-?(no_)auto_include| \ -bigp_off|-bigp_on|-brief_diagnostics| \ -c|-cfront|-clist|-CLIST:*|-common| \ -D*|-DEBUG:*|-diag_error|-diag_remark|-diag_suppress|-diag_warning|-dollar| \ -E|-EP|-P| \ -fb|-fb_create|-fb_opt|-FE:*|-float?(_const)|-fullwarn| \ -G+([0-9])|-g?([023])?(slim)|-I*|-INLINE:*|-IPA:*|-ignore_suffix| \ -J*([0-9])| \ -KPIC| \ -L*|-l*|-LANG:*|-LIST:*|-LNO:*| \ -M|-MDupdate|-MDtarget|-mips[1-4]|-MP:*|-mp?(list)| \ -nocpp|-noinline|-none| \ -o|-O?([0-3])|-Ofast?(=ip+([0-9]))|-OPT:*| \ -pca|-pcakeep|-pcalist|-pch|-pedantic|-?(no_)prelink|-pta?(ll)|-ptnone|-ptused|-ptv| \ -quiet_prelink| \ -r|-r[458]k|-r[458]000|-r1[0246]k|-r1[0246]000| \ -S|-?(non_)shared|-show|-signed| \ -TARG:*|-TENV:*|-trapuv| \ -U*|-use_readonly_const|-use_readwrite_const|-use_command|-use_suffix| \ -v|-version| \ -w?(off)| \ -Xcpluscomm|-x| \ -Y|-Y+([pfbalRISL]),*) output="$output $argument" ;; -c99) if [ "$tool" = "c89" ]; then ifverbose "WARNING: c89: Cannot run this front-end in C99 mode, \"$argument\" dropped" else output="$output $argument" fi ;; # NB: -W by itself should have been squashed by pass1 -W+([pfbalR]),*|-w?(off)) # We need to be careful here, because we don't want to clobber $output case $argument in -Wp,*) progress="$output" argument="$( echo "$arguments" | sed 's/,/ /g' )" checkcppflags $argument output="$progress $( echo "$output" | sed -r 's/ -/ -Wp,-/g ; s/ ([^-])/ -Wp,\1/g' )" ;; -Wl,*) progress="$output" argument="$( echo "$arguments" | sed 's/,/ /g' )" checkldflags $argument output="$progress $( echo "$output" | sed -r 's/ -/ -Wl,-/g ; s/ ([^-])/ -Wl,\1/g' )" ;; *) # There may be linker arguments in here too, but meh... output="$output $argument" ;; esac ;; -*) if (( permissive )); then ifverbose "WARNING: cc: Unrecognised compiler option \"$argument\" passed" output="$output $argument" else ifverbose "WARNING: cc: Unrecognised compiler option \"$argument\" dropped" fi ;; *) output="$output $argument" ;; esac else output="$output $argument" fi done output="$( echo "$output" | sed 's/\s\+-Wl,-rpath\s\+-Wl,/ -Wl,-rpath,/g' )" } # checkcflags() function checkcxxflags() { local input="$@" checkcflags "$input" } # checkcxxflags # Pass 2 - Set default values and filter out GNU arguments # function pass2() { local input="$@" local argument skip progress local skip=0 unset output for argument in $input; do (( ! skip )) && case $argument in --) skip=1 ;; -32|-o32|-n32|-64) if test "$argument" != "${MIPSPRO_ABI}"; then ifverbose "WARNING: pass2: ABI $argument upgraded to ${MIPSPRO_ABI}" argument="${MIPSPRO_ABI}" fi ;; -mips?) if test "$argument" != "-${MIPSPRO_ISA}"; then ifverbose "WARNING: pass2: ISA $argument upgraded to -${MIPSPRO_ISA}" argument="-${MIPSPRO_ISA}" fi ;; esac (( ! skip )) && case $tool in cpp|cc|c89|c99|CC) case $tool in cpp) case $argument in # FIXME for x11-libs/libX11 -undef) # This is a hack to work around the libX11 'cpp' checks... ifverbose "WARNING: pass2: GNU option $argument changed to -Uunix (as libX11 workaround)" argument="-Uunix" ;; -traditional) # This is a hack to work around the libX11 'cpp' checks... ifverbose "WARNING: pass2: GNU option $argument dropped" unset argument continue ;; esac ;; cc|c89|c99) case $argument in -anach|-ansiE|-ansiW|-?(no_)auto_include|-cfront|-FE:*|-g?([023])slim|-J*([0-9])|-?(no_)prelink|-pch|-pta?(ll)|-ptnone|-ptused|-ptv|-quiet_prelink) ifverbose "WARNING: pass2: CC-only option $argument dropped" unset argument continue ;; esac ;; CC) case $argument in -?(x)ansi|-cckr|-clist|-CLIST:*|-nocpp|-pca|-pcakeep|-pcalist) ifverbose "WARNING: pass2: cc-only option $argument dropped" unset argument continue ;; esac ;; esac case $argument in -MD) ifverbose "WARNING: pass2: -MD does not exist on IRIX, $argument changed to -M -MDupdate" ifverbose "WARNING: pass2: Output is approximated!" argument="-M -MDupdate" ;; -MF) ifverbose "WARNING: pass2: -MF does not exist on IRIX, $argument changed to -MDupdate" argument="-MDupdate" ;; -MT) # Although not documented -MDtarget is a vlaid cc/CC option! # (it is documented for cpp, but this is supposed to be for legacy # non-ANSI usage only...) ifverbose "WARNING: pass2: -MT does not exist on IRIX, $argument changed to -MDtarget" argument="-MDtarget" ;; esac [ "$tool" != "cpp" ] && case $argument in -fpic|-fPIC) ifverbose "WARNING: pass2: -KPIC is default on IRIX, $argument dropped" unset argument continue ;; -g?([023])?(slim)) ifverbose "WARNING: pass2: Debug level $argument dropped" unset argument continue ;; # We generally need our standard includes... # -nostdinc) if ! (( allownostd )); then ifverbose "WARNING: pass2: Standard includes are required, $argument dropped" unset argument continue fi ;; # Some programs seem keen on uber-optimisation... # -O?([0-3])) # Remember the lowest value of this argument... [ "$OPTIMISE" = "-O" ] && OPTIMISE="-O2" [ "$argument" = "-O" ] && argument="-O2" OPTIMISE="$( for argument in $OPTIMISE $argument; do echo $argument; done | sort -g | head -n 1 )" unset argument ;; -rdynamic) # I don't know what the MIPSpro equivalent is! ifverbose "WARNING: pass2: $argument equivalent is unknown, argument dropped" unset argument continue ;; -W+([pfbalR]),*) # Do nothing here - it's merely a placeholder to make the # match below easier... : ;; -W*) # For -Wall, -Wstrict-prototypes, etc. # ifverbose "WARNING: pass2: GNU option $argument changed to -fullwarn" argument="-fullwarn" ;; --version) ifverbose "WARNING: pass2: GNU option $argument changed to -version" argument="-version" ;; -v) # For cosmetic reasons only: -v may not be what was # intended # argument="-show" ;; esac ;; ld) case $argument in # We generally need our standard libraries... # -L|-nostdlib) if ! (( allownostd )); then ifverbose "WARNING: pass2: Standard libraries are required, $argument dropped" unset argument continue fi ;; -version|--version) argument="-V" ;; esac ;; esac test -n "$argument" && output="$output $argument" done input="$output" unset output # Common options with different meanings: # -x # case $tool in cc|c89|c99) checkcflags "$input" ;; CC) checkcxxflags "$input" ;; cpp) checkcppflags "$input" ;; ld) checkldflags "$input" ;; esac } # pass2() # Pass 3 - Ensure standard arguments are present # function pass3() { local input="$@" local options argument item found skip pass quotepass drop quiet unset output case "$tool" in cc|c99|CC) options="$options -TARG:isa=${MIPSPRO_ISA}:platform=${MIPSPRO_PLATFORM}:processor=${MIPSPRO_CPU} -${MIPSPRO_CPU}" options="$options -float_const -use_readonly_const -TENV:zeroinit_in_bss=ON" options="$options -OPT:fast_io=ON:Olimit=${OLIMIT}:reorg_common=ON:swp=ON" options="$options -LNO:auto_dist=ON:fusion_peeling_limit=8:gather_scatter=2" options="$options -Wl,-v -Wl,-s -Wl,-x -Wl,${MIPSPRO_ABI} -Wl,-${MIPSPRO_ISA} -Wl,-rdata_shared -Wl,-allow_jump_at_eop -Wl,-rpath,${EPREFIX}/usr/lib:${EPREFIX}/lib" options="$options -L${EPREFIX}/usr/lib -L${EPREFIX}/lib" options="$options -woff 1174,1183,1185,1552,3968,3970" options="$options -diag_error 1035" case "$tool" in # Preprocessor needs -c99 for headers such as stdint.h # This may generate incorrect results when compiling with # c89, but there's no way to detect if this will be the case # if cpp is invoked directly. # Likewise, we assume that cc really wants C99 compliance. cpp|cc|c99) options="-c99 $options" ;; CC) # Enable prelinker concurrent compilation #options="-J2 $options" options="$options -FE:eliminate_duplicate_inline_copies:template_in_elf_section" ;; esac ;; ld) options="$options -v -s -x -rdata_shared -allow_jump_at_eop -rpath ${EPREFIX}/usr/lib:${EPREFIX}/lib -L${EPREFIX}/usr/lib -L${EPREFIX}/lib" ;; esac if test "$tool" != "cpp"; then # -I is also a linker option, so we can't pass the modified # include path when $tool is being invoked as a linker. case "$tool" in ld) : ;; *) options="$options -I${EPREFIX}/usr/include" ;; esac input="${MIPSPRO_ABI} -${MIPSPRO_ISA} $input $options" # If no optimisation options are set, use ${OPTIMISE} # NB: -O is equivalent to -O2 # No -O is equivalent to -O0 - so technically this is cheating... if test "$tool" != "ld"; then found=0 for argument in $input; do case $argument in -O?) found=1 break ;; esac done (( found )) || input="${OPTIMISE} $input" fi fi # Eliminate duplicate arguments before any optional "--" only input="$( echo "$input" | sed -r 's!(-diag_[^ ]+) ([0-9]+)!\1_#_\2!g' )" input="$( echo "$input" | sed -r 's! -rpath([, ])([^ ]+)! -rpath_#_\2!g' )" input="$( echo "$input" | sed -r 's!-woff ([0-9,]+)!-woff_#_\1!g' )" skip=0 pass=0 quotepass=0 drop=0 quiet=0 for argument in $input; do test "$argument" = "--" && skip=1 if ! (( skip )); then if (( quotepass )); then pass=0 drop=0 ifverbose "NOTICE: pass3: Quoted string $argument passed..." output="$output $argument" continue elif (( pass )); then pass=0 drop=0 if [ -n "$( echo $argument | grep -- "^-" )" ]; then ifverbose "NOTICE: pass3: Passing follow-on option $argument" else ifverbose "NOTICE: pass3: Passing follow-on argument $argument" fi output="$output $argument" continue elif (( drop )); then drop=0 if [ -n "$( echo $argument | grep -- "^-" )" ]; then ifverbose "NOTICE: pass3: Passing follow-on option $argument" else ifverbose "NOTICE: pass3: Dropping follow-on argument $argument" fi unset argument continue fi found=0 case $argument in # FIXME for dev-lang/tcl -DTCL_PACKAGE_PATH=\"*) if [ -z "$( echo $argument | grep '"$' )" ]; then ifverbose "NOTICE: pass3: Correcting trailing space in define when building Tcl" argument="$( echo $argument | sed 's/$/"/' )" drop=1 fi ;; -MD*) ifverbose "NOTICE: pass3: Option $argument will always be passed..." pass=1 quiet=1 ;; -o) ifverbose "NOTICE: pass3: Option $argument will always be passed..." pass=1 quiet=1 ;; ?(-W*([pfbaR])l*([pfbaR]),)-rpath) pass=1 ;; \"|\'|\`) ifverbose "NOTICE: pass3: Quote character $argument passed..." quiet=1 ;; *\'*\'|*\"*\"|*\`*\`) if [ -n "$( echo $argument | grep -- "^-" )" ]; then ifverbose "NOTICE: pass3: Option with quoted string $argument passed..." else ifverbose "NOTICE: pass3: Argument with quoted string $argument passed..." fi quotedpass=0 quiet=1 ;; \'*|\"*|\`*) ifverbose "NOTICE: pass3: Start of quoted string $argument passed..." quotedpass=1 quiet=1 ;; *\'|*\"|*\`) ifverbose "NOTICE: pass3: End of quoted string $argument passed..." quotedpass=0 quiet=1 ;; -*) for item in $output; do if test "$item" = "$argument"; then ifverbose "WARNING: pass3: Dropping duplicate option $( echo $argument | sed 's!_#_! !g' )" found=1 break fi done ;; esac if ! (( found )); then (( quiet )) || case $argument in -*) ifverbose "NOTICE: pass3: Passing option $( echo $argument | sed 's!_#_! !g' )" ;; *) ifverbose "NOTICE: pass3: Passing argument $argument" ;; esac output="$output $argument" quiet=0 fi else case $argument in -*) ifverbose "NOTICE: pass3: Passing all remaining, option $argument" ;; *) ifverbose "NOTICE: pass3: Passing all remaining, argument $argument" ;; esac output="$output $argument" fi done output="$( echo "$output" | sed 's!_#_! !g' )" } # pass3() # At each stage, function output is stored in $output pass1 "$input" pass2 "$output" pass3 "$output" test "$tool" = "cpp" && tool="../lib/cpp" ifdebug ": output:\t/bin/$tool $output" exec "/bin/$tool" $output } # main() ifdebug ": INFO: IMpw: Optimising at $OPTIMISE or lower" main "$@" exit 0 # vi:set syntax=sh ts=4: