#!/bin/bash # Copyright 1999-2004 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Header: /var/cvsroot/gentoo-x86/sys-devel/gcc-config/files/gcc-config-1.3.9,v 1.4 2005/01/19 23:26:13 vapier Exp $ # Author: Martin Schlemmer trap ":" INT QUIT TSTP source /etc/init.d/functions.sh || { echo "$0: Could not source /etc/init.d/functions.sh!" exit 1 } umask 022 usage() { cat << "USAGE_END" Usage: gcc-config [options] [CC Profile] Change the current cc/gcc profile, or give info about profiles. Options: -O, --use-old Use the old profile if one was selected. -P, --use-portage-chost Only set to given profile if its CHOST is the same as that set for portage in /etc/make.conf (or one of other portage config files...). -c, --get-current-profile Print current used gcc profile. -l, --list-profiles Print a list of available profiles. -E, --print-environ Print environment that can be used to setup the current gcc profile, or a specified one. -B, --get-bin-path Print path where binaries of the given/current profile are located. -L, --get-lib-path Print path where libraries of the given/current profile are located. -X, --get-stdcxx-incdir Print path where g++ include files of the given/current profile are located. Profile names are of the form: - For example: i686-pc-linux-gnu-3.2.1 USAGE_END exit $1 } [[ $# -lt 1 ]] && usage 1 find_path() { [[ -z $1 ]] && return 0 local fullpath="$(type -P $1)" if [[ -x ${fullpath} ]] ; then echo "${fullpath}" return 0 fi for x in /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin ; do if [[ -x ${x}/$1 ]] && [[ -r ${x}/$1 ]] ; then echo "${x}/$1" return 0 fi done return 0 } cmd_setup() { # Sourcing /etc/env.d/gcc/${CC_COMP} is going to mess up # PATH among things... CP="$(find_path cp)" RM="$(find_path rm)" MV="$(find_path mv)" LN="$(find_path ln)" CAT="$(find_path cat)" AWK="$(find_path gawk)" GREP="$(find_path grep)" FIND="$(find_path find)" CHMOD="$(find_path chmod)" TOUCH="$(find_path touch)" ENV_UPDATE="$(find_path env-update)" } get_real_chost() { [[ -n ${REAL_CHOST} ]] && return 0 export REAL_CHOST="$(env -u CHOST portageq envvar CHOST)" if [[ -z ${REAL_CHOST} ]] ; then eerror "$0: Could not get portage CHOST!" return 1 fi } is_cross_compiler() { get_real_chost [[ ${CC_COMP/${REAL_CHOST}} = ${CC_COMP} ]] } switch_profile() { local MY_LDPATH= local GCC_PROFILES= local OLD_CC_COMP= local GCC_BIN_PATH= if [[ "$(id -u)" -ne 0 ]] ; then eerror "$0: Must be root." exit 1 fi ebegin "Switching to ${CC_COMP} compiler" # Sourcing /etc/env.d/gcc/${CC_COMP} is going to mess up # PATH among things... cmd_setup if ! is_cross_compiler ; then # Order our profiles to have the default first ... # We do this so that we can have them ordered with default # first in /etc/ld.so.conf, as the logical is that all # compilers for default CHOST will be used to compile stuff, # and thus we want all their lib paths in /etc/ld.so.conf ... get_real_chost GCC_PROFILES="$(${FIND} "${GCC_ENV_D}" -name "${REAL_CHOST}-*" -a ! -name "${CC_COMP}")" GCC_PROFILES="${GCC_ENV_D}/${CC_COMP} ${GCC_PROFILES}" # Extract all LDPATH's for our CHOST MY_LDPATH="" for x in ${GCC_PROFILES} ; do if [[ -f ${x} ]] ; then source "${x}" # Handle LDPATH's that have multiple directories local old_IFS="${IFS}" export IFS=":" local sub_ldpath= for sub_ldpath in ${LDPATH} ; do if [[ -d ${sub_ldpath} ]] ; then if [[ ${MY_LDPATH/:${sub_ldpath}} = ${MY_LDPATH} ]] ; then MY_LDPATH="${MY_LDPATH}:${sub_ldpath}" fi fi done export IFS="${old_IFS}" fi done MY_LDPATH="${MY_LDPATH:1}" # trim leading : fi # Setup things properly again for this profile unset GCC_SPECS LDPATH source "${GCC_ENV_D}/${CC_COMP}" OLD_CC_COMP=$(get_current_profile) CTARGET="${CTARGET:-${REAL_CHOST}}" # What kind of env.d entry are we going to generate ? if is_cross_compiler ; then # Only keep PATH/ROOTPATH ${AWK} '/^(PATH|ROOTPATH)=/ {print $0}' \ "${GCC_ENV_D}/${CC_COMP}" > "${ENV_D}/05gcc-${CTARGET}" echo "CURRENT=${CC_COMP}" > "${GCC_ENV_D}/config-${CTARGET}" else # Pass all by default ${AWK} '!/^(STDCXX_INCDIR|LDPATH|CC|CXX|CTARGET|GCCBITS|GCC_SPECS)=/ {print $0}' \ "${GCC_ENV_D}/${CC_COMP}" > "${ENV_D}/05gcc" echo "LDPATH=\"${MY_LDPATH}\"" >> "${ENV_D}/05gcc" if [[ -n ${GCC_SPECS} ]] && [[ -e ${ROOT}/${GCC_SPECS} ]] ; then echo "GCC_SPECS=\"${GCC_SPECS}\"" >> "${ENV_D}/05gcc" else # People need to rebuild their gcc or setting GCC_SPECS to # "" will cause issues again :( if [[ ${ROOT} != "/" ]] ; then echo "GCC_SPECS=\"\"" >> "${ENV_D}/05gcc" else if ! GCC_SPECS="" /usr/bin/gcc -v &>/dev/null ; then echo ewarn "Your gcc has a bug with GCC_SPECS." ewarn "Please re-emerge gcc." ewarn "http://bugs.gentoo.org/show_bug.cgi?id=68395" echo else echo "GCC_SPECS=\"\"" >> "${ENV_D}/05gcc" fi fi fi echo "CURRENT=${CC_COMP}" > "${GCC_ENV_D}/config" fi # Save PATH GCC_BIN_PATH="${PATH}" # Fix environment source /etc/profile umask 022 # Update the wrappers for this profile local native="gcc cpp cc c++ g++ f77 g77 gcj" is_cross_compiler && native="" for x in ${native} ${CTARGET}-{gcc,c++,g++,f77,g77,gcj} ; do # Make sure we have no stale wrappers ${RM} -f "${ROOT}/usr/bin/${x}" [[ ${x:${#x}-3} = "gcc" || ${x:${#x}-3} = "g++" ]] \ && ${RM} -f "${ROOT}/usr/bin/${x}"{32,64} # Only install a wrapper if the binary exists ... # We want to figure out the 'reference file' for each # wrapper (the binary we're 'wrapping') so that we can # sync mtimes together. This makes things like ccache # happy. See Bug #70548 for more info. local ref=${ROOT}/${GCC_BIN_PATH}/${x} [[ ${x} = "cc" ]] && ref=${ROOT}/${GCC_BIN_PATH}/gcc if [[ -x ${ref} ]] ; then ${CP} -f "${ROOT}/usr/lib/gcc-config/wrapper" \ "${ROOT}/usr/bin/${x}" touch -r "${ref}" "${ROOT}/usr/bin/${x}" # Install 32bit and 64bit wrappers if need be # This should probably get folded back into the wrapper ... if [[ ${x:${#x}-3} = "gcc" ]] || [[ ${x:${#x}-3} = "g++" ]] ; then for bits in ${GCCBITS} ; do cp -f "${ROOT}/usr/lib/gcc-config/wrapper" \ "${ROOT}/usr/bin/${x}${bits}" done fi fi done # Only install cpp if switching to a native one if ! is_cross_compiler ; then ${RM} -f "${ROOT}/lib/cpp" ${CP} -f "${ROOT}/usr/lib/gcc-config/wrapper" "${ROOT}/lib/cpp" fi # We need to make sure that libgcc_s.so makes it into /lib. # On many systems (x86/amd64/etc...), this will probably never matter, # but on other systems (arm/mips/etc...), this is quite critical. # http://bugs.gentoo.org/show_bug.cgi?id=60190 if ! is_cross_compiler && [[ -e ${ROOT}/${LDPATH}/libgcc_s.so ]] ; then rm -f "${ROOT}"/lib/libgcc_so.so* cp -a "${ROOT}/${LDPATH}"/libgcc_s.so* "${ROOT}"/lib/ fi if [[ ${ROOT} = "/" ]] && [[ ${OLD_CC_COMP} != ${CC_COMP} ]] ; then ${ENV_UPDATE} &>/dev/null fi eend 0 if [[ ${ROOT} = "/" ]] && [[ ${OLD_CC_COMP} != ${CC_COMP} ]] ; then echo ewarn "If you intend to use the gcc from the new profile in an already" ewarn "running shell, please remember to do:" echo ewarn " # source /etc/profile" echo fi return 0 } get_current_profile() { local conf="${GCC_ENV_D}/config" if [[ -n ${CTARGET} ]] ; then conf="${conf}-${CTARGET}" elif [[ -f ${GCC_ENV_D}/config-${CC_COMP} ]] ; then conf="${conf}-${CC_COMP}" fi if [[ ! -f ${conf} ]] ; then eerror "$0: No gcc profile is active!" return 1 fi source "${conf}" if [[ -z ${CURRENT} ]] ; then eerror "$0: No gcc profile is active!" return 1 fi echo "${CURRENT}" return 0 } list_profiles() { local i=1 if [[ ! -f ${GCC_ENV_D}/config ]] ; then eerror "$0: No gcc profile is active; please select one!" else get_current_profile >/dev/null fi if [[ ${ROOT} != "/" ]] ; then echo "Using gcc-config info in ${ROOT}" fi for x in "${GCC_ENV_D}"/* ; do if [[ -f ${x} ]] && [[ ${x/\/config} = ${x} ]] ; then x=${x##*/} [[ ${x} = ${CURRENT} ]] && x="${x} *" echo "[${i}] ${x}" i=$((i + 1)) fi done } print_environ() { local OLDPATH="${PATH}" local ENV_CMD= local SET_ELEMENT= source "${GCC_ENV_D}/${CC_COMP}" case ${SHELL} in */csh|*/tsch) ENV_CMD="setenv" SET_ELEMENT=" " ;; *) ENV_CMD="export" SET_ELEMENT="=" ;; esac echo "${ENV_CMD} PATH${SET_ELEMENT}\"${PATH}:${OLDPATH}\"" } get_bin_path() { if [[ -e ${GCC_ENV_D}/${CC_COMP} ]] ; then source "${GCC_ENV_D}/${CC_COMP}" echo "${PATH}" else echo "no-config" echo "${GCC_ENV_D}/${CC_COMP} doesnt exist" 1>&2 fi return 0 } get_lib_path() { if [[ -e ${GCC_ENV_D}/${CC_COMP} ]] ; then source "${GCC_ENV_D}/${CC_COMP}" echo "${LDPATH}" else echo "no-config" echo "${GCC_ENV_D}/${CC_COMP} doesnt exist" 1>&2 fi return 0 } get_stdcxx_incdir() { if [[ -e ${GCC_ENV_D}/${CC_COMP} ]] ; then source "${GCC_ENV_D}/${CC_COMP}" echo "${LDPATH}/include/${STDCXX_INCDIR}" else echo "no-config" echo "${GCC_ENV_D}/${CC_COMP} doesnt exist" 1>&2 fi return 0 } NEED_ACTION="yes" DOIT="switch_profile" CHECK_CHOST="no" CC_COMP= [[ -z ${ROOT} ]] && ROOT="/" [[ ${ROOT:-1} != "/" ]] && ROOT="${ROOT}/" ENV_D="${ROOT}etc/env.d" GCC_ENV_D="${ENV_D}/gcc" for x in "$@" ; do case "${x}" in # Only use specified compiler if one is not already selected. -O|--use-old) if get_current_profile &>/dev/null ; then CC_COMP="$(get_current_profile)" fi ;; -P|--use-portage-chost) CHECK_CHOST="yes" ;; -c|--get-current-profile) if [[ ${NEED_ACTION} = "yes" ]] ; then NEED_ACTION="no" DOIT="get_current_profile" fi ;; -l|--list-profiles) if [[ ${NEED_ACTION} = "yes" ]] ; then NEED_ACTION="no" DOIT="list_profiles" fi ;; -E|--print-environ) if [[ ${NEED_ACTION} = "yes" ]] ; then NEED_ACTION="no" DOIT="print_environ" fi ;; -B|--get-bin-path) if [[ ${NEED_ACTION} = "yes" ]] ; then NEED_ACTION="no" DOIT="get_bin_path" fi ;; -L|--get-lib-path) if [[ ${NEED_ACTION} = "yes" ]] ; then NEED_ACTION="no" DOIT="get_lib_path" fi ;; -X|--get-stdcxx-incdir) if [[ ${NEED_ACTION} = "yes" ]] ; then NEED_ACTION="no" DOIT="get_stdcxx_incdir" fi ;; -h|--help) usage 0 exit 0 ;; -v|--version) echo "gcc-config-PORTAGE-VERSION" exit 0 ;; -*) eerror "$0: Invalid switch! Run $0 without parameters for help." exit 1 ;; *) if [[ -z ${CC_COMP} ]] ; then if [[ -z $(echo ${x} | tr -d '[:digit:]') ]] ; then # User gave us a # representing the profile i=1 for y in "${GCC_ENV_D}"/* ; do [[ ${y/\/config} != ${y} ]] && continue if [[ -f ${y} ]] && [[ ${x} = ${i} ]] ; then CC_COMP="${y##*/}" break fi i=$((i + 1)) done else # User gave us a full HOST-gccver x=${x##*/} if [[ ${DOIT} != "get_current_profile" ]] && \ [[ ! -f ${GCC_ENV_D}/${x} ]] then eerror "$0: Could not locate '$x' in '${GCC_ENV_D}/'!" exit 1 fi CC_COMP="${x}" fi else eerror "$0: Too many arguments! Run $0 without parameters for help." exit 1 fi ;; esac done if [[ ${DOIT} = "switch_profile" ]] && [[ -z ${CC_COMP} ]] ; then usage 1 fi if [[ -z ${CC_COMP} ]] ; then if get_current_profile &>/dev/null then CC_COMP="$(get_current_profile)" else list_profiles exit 1 fi fi if [[ ${DOIT} != "get_current_profile" ]] ; then CC_COMP_NO_SPECS=$(echo ${CC_COMP} | awk -F- '{ print $1"-"$2"-"$3"-"$4"-"$5 }') GCC_LIB=$(source "${GCC_ENV_D}/${CC_COMP}" cmd_setup echo ${LDPATH} | ${AWK} -F/ '{ print "/"$2"/"$3"/"$4"/" }') if [[ ! -d ${ROOT}/${GCC_LIB}/${CC_COMP_NO_SPECS%-*}/${CC_COMP_NO_SPECS##*-} ]] || \ [[ ! -f ${GCC_ENV_D}/${CC_COMP} ]] then eerror "$0: Profile does not exist or invalid setting for ${GCC_ENV_D}/${CC_COMP}" 1>&2 #exit 1 fi fi if [[ ${CHECK_CHOST} = "yes" ]] ; then # Chosen CHOST are not the same as the real CHOST according to # make.conf, and --use-portage-chost option was given, so do nothing get_real_chost [[ ${CC_COMP%-*} != ${REAL_CHOST} ]] && exit 0 fi eval ${DOIT} # vim:ts=4