#!/bin/bash # (C) Martin V\"ath # SPDX-License-Identifier: GPL-2.0-only FLAG_FILTER_C_CXX=( '-fall-intrinsics' '-fbackslash' '-fcray-pointer' '-fd-lines-as-*' '-fdec*' '-fdefault-*' '-fdollar-ok' '-ffixed-*' '-ffree-*' '-fimplicit-none' '-finteger-4-integer-8' '-fmax-identifier-length*' '-fmodule-private' '-fno-range-check' '-freal-*' '-ftest-forall-temp' '-std=f*' '-std=gnu' '-std=legacy' ) FLAG_FILTER_CXX_FORTRAN=( '-std=c1*' '-std=c8*' '-std=c9*' '-std=gnu1*' '-std=gnu8*' '-std=gnu9*' '-std=iso*' '-Wimplicit-function-declaration' ) FLAG_FILTER_C_FORTRAN=( '-fabi-*' '-faligned-new' '-fcheck-new' '-fconcepts' '-fconstexpr-*' '-fdeduce-init-list' '-fext*' '-ffor-scope' '-ffriend-injection' '-fms-extensions' '-fnew-inheriting-ctors' '-fnew-ttp-matching' '-fno-access-control' '-fno-elide-constructors' '-fno-enforce-eh-specs' '-fno-extern-tls-init' '-fno-for-scope' '-fno-gnu-keywords' '-fno-implement-inlines' '-fno-implicit-*' '-fno-nonansi-builtins' '-fno-operator-names' '-fno-optional-diags' '-fno-pretty-templates' '-fno-rtti' '-fno-threadsafe-statics' '-fno-use-cxa-get-exception-ptr' '-fno-weak' '-fnothrow-opt' '-fpermissive' '-frepo' '-fsized-deallocation' '-fstrict-enums' '-fstrong-eval-order' '-ftemplate-*' '-fuse-cxa-atexit' '-fvisibility-*' '-nostdinc++' '-std=c++*' '-std=gnu++*' '-Wabi*' '-Wctor-dtor-privacy' '-Wdelete-non-virtual-dtor' '-Weffc++' '-Wliteral-suffix' '-Wlto-type-mismatch' '-Wmultiple-inheritance' '-Wnamespaces' '-Wno-narrowing' '-Wno-non-template-friend' '-Wno-pmf-conversions' '-Wno-terminate' '-Wnoexcept' '-Wnon-virtual-dtor' '-Wold-style-cast' '-Woverloaded-virtual' '-Wregister' '-Wreorder' '-Wsign-promo' '-Wstrict-null-sentinel' '-Wtemplates' '-Wvirtual-inheritance' ) FLAG_FILTER_CFLAGS=( ) FLAG_FILTER_CXXFLAGS=( ) FLAG_FILTER_FORTRAN=( '-ansi' '-fallow-parameterless-variadic-functions' '-fcilkplus' '-fcond-mismatch' '-fdirectives-only' '-ffreestanding' '-fgimple' '-fgnu-tm' '-fgnu89-inline' '-fhosted' '-flax-vector-conversions' '-fms-extensions' '-fno-asm' '-fno-builtin*' '-fno-signed-bitfields' '-fno-unsigned-bitfields' '-fpermitted-flt-eval-methods*' '-fplan9-extensions' '-fsigned-*' '-fsso-struct*' '-funsigned-*' '-Wchkp' '-Wclobbered' '-Wformat*' '-Wvolatile-register-var' ) FLAG_FILTER_FFLAGS=( ) FLAG_FILTER_FCFLAGS=( ) FLAG_FILTER_F77FLAGS=( ) FLAG_FILTER_NONGNU=( '-fcf-protection*' '-fdevirtualize-at-ltrans' '-fdevirtualize-speculatively' '-fdirectives-only' '-ffat-lto-objects' '-fgcse*' '-fgraphite*' '-finline-functions' '-fipa-pta' '-fira-loop-pressure' '-fisolate-erroneous-paths-attribute' '-fivopts' '-flimit-function-alignment' '-floop*' '-flto=[0-9]*' '-flto=auto' '-flto=jobserver' '-flto-partition=*' '-flto-compression-level=*' '-fmodulo*' '-fno-enforce-eh-specs' '-fno-ident' '-fno-ipa-cp-clone' '-fno-plt' # causes various runtime segfaults for clang:6 compiled code '-fno-semantic-interposition' '-fnothrow-opt' '-fpredictive-commoning' '-frename-registers' '-freorder-functions' '-frerun-cse-after-loop' '-fsched*' '-fsection-anchors' '-fstack-clash-protection' '-ftree*' '-funsafe-loop*' '-fuse-linker-plugin' '-fvect-cost-model' '-fweb' '-fwhole-program' '-malign-data*' '-mfunction-return*' '-mindirect-branch*' '-mvectorize*' '-Wl,-z,retpolineplt' # does not work, currently ) FLAG_FILTER_GNU=( '-emit-llvm' '-flto=full' '-flto=thin' '-flto-jobs=*' '-fopenmp=*' '-frewrite-includes' '-fsanitize=cfi' '-fsanitize=safe-stack' '-mllvm' '-mretpoline*' '-polly*' '-Wl,-z,retpolineplt' ) FlagEval() { case $- in *f*) eval "$*";; *) set -f eval "$*" set +f;; esac } FlagNodupAdd() { local addres addf addvar dups dups=$1 shift addvar=$1 shift eval addres=\$$addvar for addf do case " $addres $dups " in *[[:space:]]"$addf"[[:space:]]*) continue;; esac addres=$addres${addres:+\ }$addf done eval $addvar=\$addres } FlagAdd() { FlagNodupAdd '' "$@" } FlagSub() { local subres subpat subf subvar sublist subvar=$1 shift subres= eval sublist=\$$subvar for subf in $sublist do for subpat do [ -n "${subpat:++}" ] || continue case $subf in $subpat) subf= break;; esac done [ -z "${subf:++}" ] || subres=$subres${subres:+\ }$subf done eval $subvar=\$subres } FlagReplace() { local repres repf repcurr repvar reppat repvar=$1 shift eval repf=\$$repvar reppat=$1 shift repres= for repcurr in $repf do case $repcurr in $reppat) $repfound && FlagAdd repres "$@" continue;; esac repres=$repres${repres:+\ }$repcurr done eval $repvar=\$repres } FlagSet() { local setvar setvar=$1 shift eval $setvar=\$* } FlagAddCFlags() { FlagAdd CFLAGS "$@" FlagAdd CXXFLAGS "$@" } FlagSubCFlags() { FlagSub CFLAGS "$@" FlagSub CXXFLAGS "$@" FlagSub CPPFLAGS "$@" FlagSub OPTCFLAGS "$@" FlagSub OPTCXXFLAGS "$@" FlagSub OPTCPPFLAGS "$@" } FlagReplaceCFlags() { FlagReplace CFLAGS "$@" FlagReplace CXXFLAGS "$@" FlagReplace CPPFLAGS "$@" FlagSub OPTCFLAGS "$1" FlagSub OPTCXXFLAGS "$1" FlagSub OPTCPPFLAGS "$1" } FlagSetCFlags() { FlagSet CFLAGS "$@" CXXFLAGS=$CFLAGS CPPFLAGS= OPTCFLAGS= OPTCXXFLAGS= OPTCPPFLAGS= } FlagAddFFlags() { FlagAdd FFLAGS "$@" FlagAdd FCFLAGS "$@" FlagAdd F77FLAGS "$@" } FlagSubFFlags() { FlagSub FFLAGS "$@" FlagSub FCFLAGS "$@" FlagSub F77FLAGS "$@" } FlagReplaceFFlags() { FlagReplace FFLAGS "$@" FlagReplace FCFLAGS "$@" FlagReplace F77FLAGS "$@" } FlagSetFFlags() { FlagSet FFLAGS "$@" FlagSet FCFLAGS "$@" FlagSet F77FLAGS "$@" } FlagAddAllFlags() { FlagAddCFlags "$@" FlagAddFFlags "$@" } FlagSubAllFlags() { FlagSubCFlags "$@" FlagSubFFlags "$@" FlagSub LDFLAGS "$@" FlagSub OPTLDFLAGS "$@" } FlagReplaceAllFlags() { FlagReplaceCFlags "$@" FlagReplaceFFlags "$@" FlagSub LDFLAGS "$1" FlagSub OPTLDFLAGS "$1" } FlagSetAllFlags() { FlagSetCFlags "$@" FlagSetFFlags "$@" LDFLAGS= OPTLDFLAGS= } FlagAthlon() { FlagSubCFlags '-march=*' FlagAddCFlags '-march=athlon-4' command -v x86_64-pc-linux-gnu-gcc32 >/dev/null 2>&1 && \ export CC=x86_64-pc-linux-gnu-gcc32 command -v x86_64-pc-linux-gnu-g++32 >/dev/null 2>&1 && \ export CXX=x86_64-pc-linux-gnu-g++32 } FlagExecute() { local ex exy excurr for excurr do case $excurr in '#'*) return;; '!'*) [ "$HOSTTYPE" = 'i686' ] || continue ex=${excurr#?};; '~'*) [ "$HOSTTYPE" = 'x86_64' ] || continue ex=${excurr#?};; *) ex=$excurr;; esac case $ex in /*/*) ex=${ex%/} ex=${ex#/} FlagEval FlagReplaceAllFlags "${ex%%/*}" "${ex#*/}";; '-'*) FlagAddCFlags "$ex";; '+flto*') FlagSubAllFlags '-flto*' '-fuse-linker-plugin' '-emit-llvm';; '+'*) FlagSubAllFlags "-${ex#+}";; 'C*FLAGS-='*) FlagEval FlagSubCFlags ${ex#*-=};; 'C*FLAGS+='*) FlagEval FlagAddCFlags ${ex#*+=};; 'C*FLAGS='*) FlagEval FlagSetCFlags "${ex#*=}";; 'C*FLAGS/=/'*/*) ex=${ex%/} ex=${ex#*/=/} FlagEval FlagReplaceCFlags "${ex%%/*}" "${ex#*/}";; 'F*FLAGS-='*) FlagEval FlagSubFFlags ${ex#*-=};; 'F*FLAGS+='*) FlagEval FlagAddFFlags ${ex#*+=};; 'F*FLAGS='*) FlagEval FlagSetFFlags "${ex#*=}";; 'F*FLAGS/=/'*/*) ex=${ex%/} ex=${ex#*/=/} FlagEval FlagReplaceFFlags "${ex%%/*}" "${ex#*/}";; '*FLAGS-='*) FlagEval FlagSubAllFlags ${ex#*-=};; '*FLAGS+='*) FlagEval FlagAddAllFlags ${ex#*+=};; '*FLAGS='*) FlagEval FlagSetAllFlags "${ex#*=}";; '*FLAGS/=/'*/*) ex=${ex%/} ex=${ex#*/=/} FlagEval FlagReplaceAllFlags "${ex%%/*}" "${ex#*/}";; 'ATHLON32') FlagAthlon;; 'NOC*OPT='*|'NOC*='*) FlagEval FlagSet NOCOPT "${ex#*=}" NOCXXOPT=$NOCOPT NOCPPOPT=$NOCOPT;; 'NO*OPT='*) FlagEval FlagSet NOCOPT "${ex#*=}" NOCXXOPT=$NOCOPT NOCPPOPT=$NOCOPT NOLDOPT=$NOCOPT;; 'NOLD*='*) FlagEval FlagSet NOLDOPT "${ex#*=}" NOLDADD=$NOLDOPT;; 'NO*'*) FlagEval FlagSet NOCOPT "${ex#*=}" NOCXXOPT=$NOCOPT NOCPPOPT=$NOCOPT NOLDOPT=$NOCOPT NOLDADD=$NOCOPT NOFFLAGS=$NOCOPT NOFCFLAGS=$NOCOPT NOF77FLAGS=$NOCOPT;; 'SAFE') NOCOPT=1 NOCXXOPT=1 NOCPPOPT=1 NOLDOPT=1 MESONDEDUP=1 LDFLAGS= CONFIG_SITE= NOLAFILEREMOVE=1 unset CMAKE_MAKEFILE_GENERATOR;; *' '*'='*) FlagEval "$ex";; *'/=/'*'/'*) ex=${ex%/} exy=${ex#*/=/} FlagEval FlagReplace "${ex%%/=/*}" "${exy%%/*}" "${exy#*/}";; *'-='*) FlagEval FlagSub "${ex%%-=*}" ${ex#*-=};; *'+='*) FlagEval FlagAdd "${ex%%+=*}" ${ex#*+=};; *'='*) FlagEval FlagSet "${ex%%=*}" "${ex#*=}";; *) FlagEval "$ex";; esac done } FlagMask() { if command -v masked-packages >/dev/null 2>&1 then FlagMask() { masked-packages -qm "$1" -- "$CATEGORY/$PF:${SLOT:-0}${PORTAGE_REPO_NAME:+::}${PORTAGE_REPO_NAME-}" } else FlagMask() { local add= case ${1%::*} in *':'*) add=:${SLOT:-0};; esac case $1 in *'::'*) add=$add::$PORTAGE_REPO_NAME;; esac case $1 in '~'*) case "~$CATEGORY/$PN-$PV$add" in $1) return;; esac;; '='*) case "=$CATEGORY/$PF$add" in $1) return;; esac;; *) case "$CATEGORY/$PN$add" in $1) return;; esac;; esac return 1 } fi FlagMask "$@" } FlagParseLine() { local scanp scanl scansaveifs scanl=$2 while : do case $scanl in [[:space:]]*) scanl=${scanl#?} continue;; '#'*) return;; *[[:space:]]*) break;; esac return done scanp=${scanl%%[[:space:]]*} scanl=${scanl#*[[:space:]]} [ -n "${scanl:++}" ] || return 0 FlagMask "$scanp" || return 0 scansaveifs=$IFS IFS=$1 BashrcdEcho "$scanfile -> $scanp: $scanl" FlagEval FlagExecute $scanl IFS=$scansaveifs } FlagScanFiles() { local scanfile scanl oldifs scanifs scanifs=$IFS IFS= for scanfile do [ -z "${scanfile:++}" ] && continue test -r "$scanfile" || continue while read -r scanl do FlagParseLine "$scanifs" "$scanl" done <"$scanfile" done IFS=$scanifs } FlagScanDir() { local scantmp scanifs scanfile scanifs=$IFS if test -d "$1" then IFS=' ' for scantmp in `find -L "$1" \ '(' '(' -name '.*' -o -name '*~' ')' -prune ')' -o \ -type f -print` do IFS=$scanifs FlagScanFiles "$scantmp" done else FlagScanFiles "$1" fi scanfile='FLAG_ADDLINES' IFS=' ' for scantmp in $FLAG_ADDLINES do FlagParseLine "$scanifs" "$scantmp" done IFS=$scanifs } FlagSetUseNonGNU() { case $CC$CXX in *clang*) return 0;; esac return 1 } FlagSetNonGNU() { : ${NOLDADD:=1} FlagSubAllFlags "${FLAG_FILTER_NONGNU[@]}" FlagReplaceAllFlags '-fstack-check*' '-fstack-check' # FlagAddCFlags '-flto' '-emit-llvm' } FlagSetGNU() { FlagSubAllFlags "${FLAG_FILTER_GNU[@]}" } FlagMesonDedup() { local newld= FlagNodupAdd "$CFLAGS $CXXFLAGS $CPPFLAGS $FFLAGS $FCFLAGS $F77FLAGS" \ newld $LDFLAGS LDFLAGS=$newld } FlagSetFlags() { local ld i ld= : ${PGO_PARENT:=/var/cache/pgo} : ${PGO_DIR:=$PGO_PARENT/$CATEGORY:$P} FlagScanDir "${PORTAGE_CONFIGROOT%/}/etc/portage/package.cflags" [ -z "${USE_NONGNU++}" ] && FlagSetUseNonGNU && USE_NONGNU=1 if BashrcdTrue "${USE_NONGNU-}" then FlagSetNonGNU else FlagSetGNU fi if [ -n "$FLAG_ADD" ] then BashrcdEcho "FLAG_ADD: $FLAG_ADD" FlagEval FlagExecute "$FLAG_ADD" fi PGO_DIR=${PGO_DIR%/} case ${PGO_DIR:-/} in /) error 'PGO_DIR must not be empty' false;; /*) :;; *) error 'PGO_DIR must be an absolute path' false;; esac || { die 'Bad PGO_DIR' exit 2 } use_pgo=false if test -r "$PGO_DIR" then unset PGO BashrcdTrue $NOPGO || use_pgo=: fi if BashrcdTrue $PGO then FlagAddCFlags "-fprofile-generate=$PGO_DIR" \ -fvpt -fprofile-arcs FlagAdd LDFLAGS -fprofile-arcs addpredict "$PGO_PARENT" elif $use_pgo then FlagAddCFlags "-fprofile-use=$PGO_DIR" \ -fvpt -fbranch-probabilities -fprofile-correction else : ${KEEPPGO:=:} fi BashrcdTrue $NOLDOPT || FlagAdd LDFLAGS $OPTLDFLAGS BashrcdTrue $NOCADD || BashrcdTrue $MESONDEDUP || \ case " $LDFLAGS $CFLAGS $CXXFLAGS" in *[[:space:]]'-flto'*) ld="$CFLAGS $CXXFLAGS";; esac BashrcdTrue $NOLDADD || BashrcdTrue $MESONDEDUP || FlagAddCFlags $LDFLAGS FlagAdd LDFLAGS $ld BashrcdTrue $NOCOPT || FlagAdd CFLAGS $OPTCFLAGS BashrcdTrue $NOCXXOPT || FlagAdd CXXFLAGS $OPTCXXFLAGS BashrcdTrue $NOCPPOPT || FlagAdd CPPFLAGS $OPTCPPFLAGS BashrcdTrue $NOFFLAGS || FFLAGS=$CFLAGS BashrcdTrue $NOFCFLAGS || FCFLAGS=$FFLAGS BashrcdTrue $NOF77FLAGS || F77FLAGS=$FFLAGS BashrcdTrue $NOFILTER_CXXFLAGS || FlagSub CXXFLAGS \ "${FLAG_FILTER_C_CXX[@]}" "${FLAG_FILTER_CXX_FORTRAN[@]}" \ "${FLAG_FILTER_CXXFLAGS[@]}" BashrcdTrue $NOFILTER_CFLAGS || FlagSub CFLAGS \ "${FLAG_FILTER_C_CXX[@]}" "${FLAG_FILTER_C_FORTRAN[@]}" \ "${FLAG_FILTER_CFLAGS[@]}" BashrcdTrue $NOFILTER_FFLAGS || FlagSub FFLAGS \ "${FLAG_FILTER_C_FORTRAN[@]}" "${FLAG_FILTER_CXX_FORTRAN[@]}" \ "${FLAG_FILTER_FORTRAN[@]}" "${FLAG_FILTER_FFLAGS[@]}" BashrcdTrue $NOFILTER_FCFLAGS || FlagSub FCFLAGS \ "${FLAG_FILTER_C_FORTRAN[@]}" "${FLAG_FILTER_CXX_FORTRAN[@]}" \ "${FLAG_FILTER_FORTRAN[@]}" "${FLAG_FILTER_FCFLAGS[@]}" BashrcdTrue $NOFILTER_F77FLAGS || FlagSub FCFLAGS \ "${FLAG_FILTER_C_FORTRAN[@]}" "${FLAG_FILTER_CXX_FORTRAN[@]}" \ "${FLAG_FILTER_FORTRAN[@]}" "${FLAG_FILTER_F77LAGS[@]}" ! BashrcdTrue $MESONDEDUP || FlagMesonDedup unset OPTCFLAGS OPTCXXFLAGS OPTCPPFLAGS OPTLDFLAGS unset NOLDOPT NOLDADD NOCOPT NOCXXOPT NOFFLAGS NOFCFLAGS NOF77FLAGS unset NOFILTER_CXXFLAGS NOFILTER_CFLAGS unset NOFILTER_FFLAGS NOFILTER_FCFLAGS NOFILTER_F77FLAGS } FlagInfoExport() { local out for out in FEATURES CFLAGS CXXFLAGS CPPFLAGS FFLAGS FCFLAGS F77FLAGS \ LDFLAGS MAKEOPTS EXTRA_ECONF EXTRA_EMAKE USE_NONGNU do eval "if [ -n \"\${$out:++}\" ] then export $out BashrcdEcho \"$out='\$$out'\" else unset $out fi" done if BashrcdTrue $PGO then BashrcdEcho "Create PGO into $PGO_DIR" elif $use_pgo then BashrcdEcho "Using PGO from $PGO_DIR" fi out=`${CC:-gcc} --version | head -n 1` || out= BashrcdEcho "${out:-cannot determine gcc version}" out=`${CXX:-g++} --version | head -n 1` || out= BashrcdEcho "${out:-cannot determine g++ version}" out=`${LD:-ld} --version | head -n 1` || out= BashrcdEcho "${out:-cannot determine ld version}" BashrcdEcho "`uname -a`" } FlagCompile() { eerror \ "${PORTAGE_CONFIGROOT%/}/etc/portage/bashrc.d/*flag.sh strange order of EBUILD_PHASE:" die "compile or preinst before setup" exit 2 } FlagPreinst() { FlagCompile } FlagSetup() { FlagCompile() { : } local use_pgo FlagSetFlags if BashrcdTrue $PGO then FlagPreinst() { test -d "$PGO_DIR" || mkdir -p -m +1777 -- "$PGO_DIR" || { eerror "cannot create pgo directory $PGO_DIR" die 'cannot create PGO_DIR' exit 2 } ewarn "$CATEGORY/$PN will write profile info to world-writable" ewarn "$PGO_DIR" ewarn 'Reemerge it soon for an optimized version and removal of that directory' } elif BashrcdTrue $KEEPPGO then FlagPreinst() { : } else FlagPreinst() { test -d "$PGO_DIR" || return 0 BashrcdLog "removing pgo directory $PGO_DIR" rm -r -f -- "$PGO_DIR" || { eerror "cannot remove pgo directory $PGO_DIR" die 'cannot remove PGO_DIR' exit 2 } local g g=${PGO_DIR%/*} [ -z "$g" ] || rmdir -p -- "$g" >/dev/null 2>&1 } fi FlagInfoExport } BashrcdPhase compile FlagCompile BashrcdPhase preinst FlagPreinst BashrcdPhase setup FlagSetup