#!/bin/bash # Copyright 1999-2004 Gentoo Technologies, Inc. # Distributed under the terms of the GNU General Public License v2 # $Header: /var/cvsroot/gentoo-x86/sys-devel/gcc-config/files/gcc-config-1.4.1,v 1.3 2004/03/06 04:14:45 vapier Exp $ # Author: Martin Schlemmer # Cross-compiling toolchain contributions by: # Zach Welch and James Boddington # handle not ROOT installs [ -z "${ROOT}" ] && ROOT="/" source /etc/init.d/functions.sh || { echo "$0: Could not source /etc/init.d/functions.sh!" exit 1 } die() { echo "$*" exit 1 } usage() { cat << "USAGE_END" Usage: gcc-config [Option] [CC Profile] Change the current cc/gcc profile, or give info about profiles. Options: --use-old Use the old profile if one was selected. --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...). --get-current-profile Print current used gcc profile. --list-profiles Print a list of available profiles. --print-environ Print environment that can be used to setup things for current gcc profile, or specified one ... --get-bin-path Print path where binaries of given/current profile are located. --get-lib-path Print path where libraries of given/current profile are located. --get-stdcxx-incdir Print path to g++ include files of given/current profile. --install-toolchain Install a new cross-compiling toolchain (that does not appear in the list of available profiles) and create the specified profile. --remove-toolchain Remove a cross-compiling tollchain. The profile name is in the form of: - For example: i686-pc-linux-gnu-3.2.1 USAGE_END exit 1 } if [ "$#" -lt 1 ] then usage fi HAVE_WHICH="no" if [ -n "$(which which 2> /dev/null)" ] then HAVE_WHICH="yes" fi find_path() { [ -z "$1" ] && return 0 if [ "${HAVE_WHICH}" = "yes" ] then local fullpath="$(which $1 2> /dev/null)" if [ -x "${fullpath}" ] then echo "${fullpath}" return 0 fi fi for x in /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin do if [ -x "${x}/$1" -a -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)" } CC_COMP="" PORTDIR="$(portageq portdir)" PORTDIR_OVERLAY="$(portageq portdir_overlay)" get_real_chost() { [ -n "$REAL_CHOST" ] && return 0 REAL_CHOST="$(portageq envvar CHOST)" if [ -z "${REAL_CHOST}" ] then eerror "$0: Could not get portage CHOST!" return 1 fi } switch_profile() { local MY_LDPATH="" local GCC_PROFILES="" local OLD_CC_COMP="" if [ -r ${ROOT}etc/env.d/gcc/config ] then source ${ROOT}etc/env.d/gcc/config if [ -n "${CURRENT}" ] then OLD_CC_COMP="${CURRENT}" fi fi if [ "$(id -u)" -ne 0 ] then eerror "$0: Must be root." exit 1 fi ebegin "Switching to ${CC_COMP} compiler" # Sourcing ${ROOT}etc/env.d/gcc/${CC_COMP} is going to mess up # PATH among things... cmd_setup # 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} ${ROOT}etc/env.d/gcc/ -name "${REAL_CHOST}-*")" GCC_PROFILES="${GCC_PROFILES/\/etc\/env.d\/gcc\/${CC_COMP}}" GCC_PROFILES="/etc/env.d/gcc/${CC_COMP} ${GCC_PROFILES}" # Extract all LDPATH's for our CHOST for x in ${GCC_PROFILES} do if [ -f "${x}" ] then source "${x}" if [ -z "${MY_LDPATH}" ] then if [ -d "${LDPATH}" ] then MY_LDPATH="${LDPATH}" fi else if [ -d "${LDPATH}" ] then MY_LDPATH="${MY_LDPATH}:${LDPATH}" fi fi fi done # Setup things properly again for this profile source "${ROOT}etc/env.d/gcc/${CC_COMP}" # Setup ${ROOT}etc/env.d/05gcc ${AWK} '!/^STDCXX_INCDIR=|^LDPATH=/ {print $0}' \ "/etc/env.d/gcc/${CC_COMP}" > ${ROOT}etc/env.d/05gcc # Add our custom LDPATH echo "LDPATH=\"${MY_LDPATH}\"" >> ${ROOT}etc/env.d/05gcc # Make sure we do not recreate /lib/cpp and /usr/bin/cc ... # echo "DISABLE_GEN_GCC_WRAPPERS=\"yes\"" >> ${ROOT}etc/env.d/05gcc echo "CURRENT=${CC_COMP}" > ${ROOT}etc/env.d/gcc/config source /etc/profile # These might not be installed, and we want to update the mtime # for ccache and distcc anyhow ... ${RM} -f ${ROOT}lib/cpp ${CP} -f ${ROOT}usr/lib/gcc-config/wrapper ${ROOT}lib/cpp for x in gcc cpp cc c++ g++ "${CHOST}-gcc" "${CHOST}-c++" "${CHOST}-g++" do ${RM} -f "${ROOT}usr/bin/${x}" ${CP} -f ${ROOT}usr/lib/gcc-config/wrapper "${ROOT}usr/bin/${x}" if [ "${OLD_CC_COMP}" != "${CC_COMP}" ] then ${TOUCH} -m "${ROOT}usr/bin/${x}" fi done ${ENV_UPDATE} &> /dev/null eend 0 if [ "${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() { if [ ! -f ${ROOT}etc/env.d/gcc/config ] then eerror "$0: No gcc profile is active!" return 1 fi source ${ROOT}etc/env.d/gcc/config if [ -z "${CURRENT}" ] then eerror "$0: No gcc profile is active!" return 1 fi echo "${CURRENT}" return 0 } list_profiles() { if [ ! -f ${ROOT}etc/env.d/gcc/config ] then eerror "$0: No gcc profile is active!" return 1 fi for x in ${ROOT}etc/env.d/gcc/* do if [ -f "${x}" -a "${x}" != "${ROOT}etc/env.d/gcc/config" ] then echo "${x##*/}" fi done } print_environ() { local OLDPATH="${PATH}" source "${ROOT}etc/env.d/gcc/${CC_COMP}" echo "export PATH=\"${PATH}:${OLDPATH}\"" # if [ -z "${LD_LIBRARY_PATH}" ] # then # echo "export LD_LIBRARY_PATH=\"${LDPATH}\"" # else # echo "export LD_LIBRARY_PATH=\"${LDPATH}:${LD_LIBRARY_PATH}\"" # fi echo "export CC=\"${CC}\"" echo "export CXX=\"${CXX}\"" } get_bin_path() { source "${ROOT}etc/env.d/gcc/${CC_COMP}" echo "${PATH}" return 0 } get_lib_path() { source "${ROOT}etc/env.d/gcc/${CC_COMP}" echo "${LDPATH}" return 0 } get_stdcxx_incdir() { source "${ROOT}etc/env.d/gcc/${CC_COMP}" eerror "${LDPATH}/include/${STDCXX_INCDIR}" return 0 } # =============================================================== # cross-compiler install portions get_arch() { echo $1 | \ awk -F '-' '{print $1}' \ sed -e 's/arm.*/arm/' return # this might work.... # case ${ACCHOST} in # i[3456]86-*) ADIR="arch-x86" ;; # alpha-*) ADIR="arch-alpha" ;; # arm*-*) ADIR="arch-arm" ;; # hppa-*) ADIR="arch-hppa" ;; # mips-*) ADIR="arch-mips" ;; # powerpc-*) ADIR="arch-powerpc" ;; # sparc-*) ADIR="arch-sparc" ;; # *) echo "bad CHOST spec"; exit 0 ;; # esac # and this might give better substring matching if [ $(expr "${ACCHOST}" : 'i[3456]86') -eq 4 ]; then # x86 echo "x86" elif [ $(expr "${ACCHOST}" : alpha) -eq 5 ]; then # Alpha echo "alpha" elif [ $(expr "${ACCHOST}" : arm) -eq 3 ]; then # ARM echo "arm" elif [ $(expr "${ACCHOST}" : hppa) -eq 4 ]; then # HP PA-Risc echo "hppa" elif [ $(expr "${ACCHOST}" : mips) -eq 4 ]; then # MIPS echo "mips" elif [ $(expr "${ACCHOST}" : powerpc) -eq 7 ]; then # PowerPC echo "ppc" elif [ $(expr "${ACCHOST}" : sparc) -eq 5 ]; then # sparc echo "sparc" else echo "unknown CHOST=${ACCHOST} - time to hack on gcc-config" exit 1 fi } EMERGE="/usr/bin/emerge" install_toolchain() { local ADIR PADIR x local ACCHOST="${CC_COMP%-*}" local AGCCVERS="${CC_COMP##*-}" local AROOT="${ROOT}usr/${ACCHOST}/" local PORTDIR="$(portage_setting PORTDIR)" get_real_chost [ -z "${ACCHOST}" -o -z "${AGCCVERS}" ] && \ die "Invalid profile specification" [ -f "${ROOT}etc/env.d/gcc/${CC_COMP}" ] && \ die "Toolchain is already installed, use --force" [ "${ACCHOST}" = "${REAL_CHOST}" ] && \ echo "gcc-config should not be used to build a native toolchain" ebegin "Installing cross-compiling toolchain for ${ACCHOST}-${AGCCVERS}" [ -n "${ROOT}" ] && AROOT="${ROOT}${AROOT}" einfo "Creating ${AROOT}..." mkdir -p "${AROOT}" || die "Unable to create ${AROOT}" AARCH="$(get-arch ${ACCHOST})" ADIR="arch-${AARCH}" einfo "Looking for ${AARCH}-headers..." if ! emerge --pretend "sys-kernel/${AARCH}-headers" then einfo "Using default linux-headers..." AHDRS="linux" else einfo "Using arch specific ${AARCH}-headers..." AHDRS="${AARCH}" fi # create the portage arch directory, if it doesn't exist PADIR="${PORTDIR}/${ADIR}" if [ ! -d "${PADIR}" ]; then einfo "Creating ${PADIR} symlinks..." mkdir "${PADIR}" || die "Can't create ${PADIR}" ( cd "${PADIR}" && for x in sys-devel/binutils sys-devel/gcc sys-libs/glibc \ "sys-kernel/${AHDRS}-headers" do ln -s ../$x done ) || die "Unable to create symlinks in ${PADIR}" fi ACCEPT_KEYWORDS="${AARCH}" ARCH="${AARCH}" CCHOST="${ACCHOST}" \ USE="build ${AARCH}" ${EMERGE} \ ${ADIR}/binutils ${ADIR}/${AHDRS}-headers \ ">=${ADIR}/gcc-${AGCCVERS}*" "${ADIR}/glibc" || \ die "Unable to merge cross toolchain for ${ACCHOST}" ACCEPT_KEYWORDS="${AARCH}" CCHOST="${ACCHOST}" ARCH="${AARCH}" \ USE="${AARCH}" ${EMERGE} \ ">=${ADIR}/gcc-${AGCCVERS}*" || \ die "Unable to merge cross toolchain for ${ACCHOST}" eend 0 } # # Unmerge the cross compiler. # remove_toolchain() { local AARCH="$(get_arch $1)" local ADIR="arch-${AARCH}" local AHDRS APKGS if [ ! -d ${PORTDIR}/arch-${ARCH} ]; then echo A compiler for $1 is not installed return fi [ -d "${PORTDIR}/sys-kernel/${AARCH}-headers" ] AHDRS="${AARCH}" || AHDRS="linux" APKGS="${ADIR}/binutils ${ADIR}/${AARCH}-headers ${ADIR}/glibc ${ADIR}/gcc" ACCEPT_KEYWORDS="${AARCH}" \ ARCH="${AARCH}" \ CCHOST=${1} \ ${EMERGE} unmerge ${APKGS} || \ ewarn "Errors unmerging parts of the toolchain..." } # =============================================================== # Main program begins here NEED_ACTION="yes" DOIT="switch_profile" CHECK_CHOST="no" for x in $* do case "${x}" in # Only use specified compiler if one is not already selected. --use-old) if get_current_profile &> /dev/null then CC_COMP="$(get_current_profile)" fi ;; --use-portage-chost) CHECK_CHOST="yes" ;; --get-current-profile) if [ "${NEED_ACTION}" = "yes" ] then NEED_ACTION="no" DOIT="get_current_profile" fi ;; --list-profiles) if [ "${NEED_ACTION}" = "yes" ] then NEED_ACTION="no" DOIT="list_profiles" fi ;; --print-environ) if [ "${NEED_ACTION}" = "yes" ] then NEED_ACTION="no" DOIT="print_environ" fi ;; --get-bin-path) if [ "${NEED_ACTION}" = "yes" ] then NEED_ACTION="no" DOIT="get_bin_path" fi ;; --get-lib-path) if [ "${NEED_ACTION}" = "yes" ] then NEED_ACTION="no" DOIT="get_lib_path" fi ;; --get-stdcxx-incdir) if [ "${NEED_ACTION}" = "yes" ] then NEED_ACTION="no" DOIT="get_stdcxx_incdir" fi ;; --install-toolchain) if [ "${NEED_ACTION}" = "yes" ] then NEED_ACTION="no" DOIT="install_toolchain" fi ;; --remove-toolchain) if [ "${NEED_ACTION}" = "yes" ] then NEED_ACTION="no" DOIT="remove_toolchain" fi ;; --*) eerror "$0: Invalid switch! Run $0 without parameters for help." exit 1 ;; *) if [ -z "${CC_COMP}" ] then CC_COMP="${x}" fi ;; esac done if [ \( "${DOIT}" = "install_toolchain" -o \ "${DOIT}" = "switch_profile" \) -a \ -z "${CC_COMP}" ] then usage fi if [ -z "${CC_COMP}" ] then if get_current_profile &> /dev/null then CC_COMP="$(get_current_profile)" else eerror "$0: No default profile setup!" exit 1 fi fi if [ "${DOIT}" != "install_toolchain" -a \ \( ! -d "${ROOT}usr/lib/gcc-lib/${CC_COMP%-*}/${CC_COMP##*-}" -o \ ! -f "${ROOT}etc/env.d/gcc/${CC_COMP}" \) ] then eerror "$0: Profile does not exist!" exit 1 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