summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Schlemmer <azarah@gentoo.org>2003-02-23 16:20:10 +0000
committerMartin Schlemmer <azarah@gentoo.org>2003-02-23 16:20:10 +0000
commit3fb55bb0f76523422e774ff926f5ca90b2fc2fb1 (patch)
treec9820b5afef8333da38d24f710578454dfa0b25a /sys-devel/gcc-config
parentFix libgd ChangeLog typo... (diff)
downloadhistorical-3fb55bb0f76523422e774ff926f5ca90b2fc2fb1.tar.gz
historical-3fb55bb0f76523422e774ff926f5ca90b2fc2fb1.tar.bz2
historical-3fb55bb0f76523422e774ff926f5ca90b2fc2fb1.zip
add new wrapper and gcc-config script
Diffstat (limited to 'sys-devel/gcc-config')
-rw-r--r--sys-devel/gcc-config/ChangeLog21
-rw-r--r--sys-devel/gcc-config/files/gcc-config-1.4551
-rw-r--r--sys-devel/gcc-config/files/wrapper-1.4.c228
3 files changed, 795 insertions, 5 deletions
diff --git a/sys-devel/gcc-config/ChangeLog b/sys-devel/gcc-config/ChangeLog
index f1ee76afa936..f4f92709b7d2 100644
--- a/sys-devel/gcc-config/ChangeLog
+++ b/sys-devel/gcc-config/ChangeLog
@@ -1,8 +1,19 @@
# ChangeLog for sys-devel/gcc-config
# Copyright 2002-2003 Gentoo Technologies, Inc.; Distributed under the GPL v2
-# $Header: /var/cvsroot/gentoo-x86/sys-devel/gcc-config/ChangeLog,v 1.28 2003/02/21 22:09:59 agriffis Exp $
-
- 19 Feb 2003; <gmsoft@gneoot.org> gcc-config-1.3.1.ebuild :
+# $Header: /var/cvsroot/gentoo-x86/sys-devel/gcc-config/ChangeLog,v 1.29 2003/02/23 16:20:10 azarah Exp $
+
+ 23 Feb 2003; Martin Schlemmer <azarah@gentoo.org> gcc-config-1.4,
+ wrapper-1.4.c :
+ - Add gcc-config-1.4 with '--install-toolchain' support written by
+ Zach Welch <zwelch@gentoo.org>. I am not 100% sure on the status
+ on this, so not adding a ebuild for now.
+ - Add wrapper-1.4.c that is borken up in functions. This is also
+ thanks to Zach Welch <zwelch@gentoo.org>. I also tweaked it to
+ modify PATH by appending gcc's bin path to it ... this should
+ speed up calls gcc does to its tools. I also fixed a few possible
+ memory leaks.
+
+ 19 Feb 2003; Guy Martin <gmsoft@gneoot.org> gcc-config-1.3.1.ebuild :
Changed ~hppa to hppa.
*gcc-config-1.3.1 (19 Jan 2003)
@@ -10,10 +21,10 @@
21 Feb 2003; Aron Griffis <agriffis@gentoo.org> gcc-config-1.3.1.ebuild :
Mark stable on alpha
- 18 Feb 2003; <zwelch@gentoo.org> gcc-config-1.3.1.ebuild :
+ 18 Feb 2003; Zach Welch <zwelch@gentoo.org> gcc-config-1.3.1.ebuild :
Add stable for arm
- 18 Feb 2003; <seemant@gentoo.org> gcc-config-1.3.1.ebuild :
+ 18 Feb 2003; Seemant <seemant@gentoo.org> gcc-config-1.3.1.ebuild :
moved to stable for x86
19 Feb 2003; Martin Schlemmer <azarah@gentoo.org> gcc-config-1.3.1 :
diff --git a/sys-devel/gcc-config/files/gcc-config-1.4 b/sys-devel/gcc-config/files/gcc-config-1.4
new file mode 100644
index 000000000000..b2fab26bdf57
--- /dev/null
+++ b/sys-devel/gcc-config/files/gcc-config-1.4
@@ -0,0 +1,551 @@
+#!/bin/bash
+# Copyright 1999-2003 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License, v2 or later
+# Author: Martin Schlemmer <azarah@gentoo.org>
+# $Header: /var/cvsroot/gentoo-x86/sys-devel/gcc-config/files/gcc-config-1.4,v 1.1 2003/02/23 16:20:10 azarah Exp $
+
+
+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.
+
+The profile name is in the form of:
+
+ <CHOST>-<gcc version>
+
+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=""
+REAL_CHOST="$(/usr/bin/python -c 'import portage; print portage.settings["CHOST"];' 2> /dev/null)"
+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 /etc/env.d/gcc/config ]
+ then
+ source /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 /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 ...
+ GCC_PROFILES="$(${FIND} /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 "/etc/env.d/gcc/${CC_COMP}"
+
+ # Setup /etc/env.d/05gcc
+ ${AWK} '!/^STDCXX_INCDIR=|^LDPATH=/ {print $0}' \
+ "/etc/env.d/gcc/${CC_COMP}" > /etc/env.d/05gcc
+
+ # Add our custom LDPATH
+ echo "LDPATH=\"${MY_LDPATH}\"" >> /etc/env.d/05gcc
+
+ # Make sure we do not recreate /lib/cpp and /usr/bin/cc ...
+# echo "DISABLE_GEN_GCC_WRAPPERS=\"yes\"" >> /etc/env.d/05gcc
+
+ echo "CURRENT=${CC_COMP}" > /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 /lib/cpp
+ ${CP} -f /usr/lib/gcc-config/wrapper /lib/cpp
+ for x in gcc cpp cc c++ g++ "${CHOST}-gcc" "${CHOST}-c++" "${CHOST}-g++"
+ do
+ ${RM} -f "/usr/bin/${x}"
+ ${CP} -f /usr/lib/gcc-config/wrapper "/usr/bin/${x}"
+
+ if [ "${OLD_CC_COMP}" != "${CC_COMP}" ]
+ then
+ ${TOUCH} -m "/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 /etc/env.d/gcc/config ]
+ then
+ eerror "$0: No gcc profile is active!"
+ return 1
+ fi
+
+ source /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 /etc/env.d/gcc/config ]
+ then
+ eerror "$0: No gcc profile is active!"
+ return 1
+ fi
+
+ for x in /etc/env.d/gcc/*
+ do
+ if [ -f "${x}" -a "${x}" != "/etc/env.d/gcc/config" ]
+ then
+ echo "${x##*/}"
+ fi
+ done
+}
+
+print_environ() {
+ local OLDPATH="${PATH}"
+
+ source "/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 "/etc/env.d/gcc/${CC_COMP}"
+
+ echo "${PATH}"
+
+ return 0
+}
+
+get_lib_path() {
+ source "/etc/env.d/gcc/${CC_COMP}"
+
+ echo "${LDPATH}"
+
+ return 0
+}
+
+get_stdcxx_incdir() {
+ source "/etc/env.d/gcc/${CC_COMP}"
+
+ eerror "${LDPATH}/include/${STDCXX_INCDIR}"
+
+ return 0
+}
+
+# ===============================================================
+# cross-compiler install portions
+
+install_toolchain() {
+ local ADIR PADIR x
+ local ACCHOST="${CC_COMP%-*}"
+ local AGCCVERS="${CC_COMP##*-}"
+ local AROOT="/usr/${ACCHOST}/"
+ local EMERGE="/usr/bin/emerge"
+ local PORTDIR="$(portage_setting PORTDIR)"
+
+ [ -z "${ACCHOST}" -o -z "${AGCCVERS}" ] && \
+ die "Invalid profile specification"
+
+ [ -f "/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}"
+
+ # 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
+
+ # but this gives better substring matching
+ if [ $(expr "${ACCHOST}" : 'i[3456]86') -eq 4 ]; then
+ # x86
+ ADIR="arch-x86"
+ elif [ $(expr "${ACCHOST}" : alpha) -eq 5 ]; then
+ # Alpha
+ ADIR="arch-alpha"
+ elif [ $(expr "${ACCHOST}" : arm) -eq 3 ]; then
+ # ARM
+ ADIR="arch-arm"
+ elif [ $(expr "${ACCHOST}" : hppa) -eq 4 ]; then
+ # HP PA-Risc
+ ADIR="arch-hppa"
+ elif [ $(expr "${ACCHOST}" : mips) -eq 4 ]; then
+ # MIPS
+ ADIR="arch-mips"
+ elif [ $(expr "${ACCHOST}" : powerpc) -eq 7 ]; then
+ # PowerPC
+ ADIR="arch-ppc"
+ elif [ $(expr "${ACCHOST}" : sparc) -eq 5 ]; then
+ # sparc
+ ADIR="arch-sparc"
+ else
+ echo "unknown CHOST=${ACCHOST} - time to hack on gcc-config"
+ exit 1
+ fi
+
+ # create the portage arch directory, if it doesn't exist
+ PADIR="${PORTDIR}/${ADIR}"
+ if [ ! -d "${PADIR}" ]; then
+ einfo "Creating ${PADIR} directory..."
+ mkdir "${PADIR}" || die "Can't create ${PADIR}"
+ einfo "Creating ${PADIR} symlinks..."
+ ( cd "${PADIR}" &&
+ for x in sys-devel/binutils sys-devel/gcc sys-libs/glibc \
+ sys-kernel/linux-headers; do
+ ln -s ../$x
+ done ) || die "Unable to create symlinks in ${PADIR}"
+ fi
+
+ einfo "Starting on cross-binutils for ${ACCHOST}..."
+ ACCEPT_KEYWORDS="~x86" \
+ CCHOST=${ACCHOST} \
+ ${EMERGE} ${ADIR}/binutils -p || \
+ die "Unable to merge cross binutils"
+
+ einfo "Cross-compiling Linux headers for ${ACCHOST} in ${AROOT}..."
+ ACCEPT_KEYWORDS="~x86" \
+ ROOT=${AROOT} \
+ CHOST=${ACCHOST} \
+ CCHOST=${ACCHOST} \
+ ${EMERGE} ${ADIR}/linux-headers -p || \
+ die "Unable to merge cross headers"
+
+ einfo "Starting on initial cross-gcc for ${ACCHOST}..."
+ ACCEPT_KEYWORDS="~x86" \
+ CCHOST=${ACCHOST} \
+ USE=build \
+ ${EMERGE} ">=${ADIR}/gcc-${AGCCVERS}*" -p || \
+ die "Unable to merge initial cross gcc"
+
+ einfo "Cross-compiling glibc for ${ACCHOST} in ${AROOT}..."
+ ACCEPT_KEYWORDS="~x86" \
+ ROOT=${AROOT} \
+ CHOST=${ACCHOST} \
+ CCHOST=${ACCHOST} \
+ USE="build" \
+ ${EMERGE} ${ADIR}/glibc --nodeps -p || \
+ die "Unable to merge cross glibc"
+
+ einfo "Starting on full cross-gcc for ${ACCHOST}..."
+ ACCEPT_KEYWORDS="~x86" \
+ CCHOST=${ACCHOST} \
+ ${EMERGE} ">=${ADIR}/gcc-${AGCCVERS}*" -p || \
+ die "Unable to merge full cross gcc"
+
+ eend 0
+
+}
+
+# ===============================================================
+# 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
+ ;;
+ --*)
+ 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 "/usr/lib/gcc-lib/${CC_COMP%-*}/${CC_COMP##*-}" -o \
+ ! -f "/etc/env.d/gcc/${CC_COMP}" \) ]
+then
+ eerror "$0: Profile does not exist!"
+ exit 1
+fi
+
+# Chosen CHOST are not the same as the real CHOST according to make.conf,
+# and --use-portage-chost option was given, so do nothing ...
+if [ "${CHECK_CHOST}" = "yes" -a "${CC_COMP%-*}" != "${REAL_CHOST}" ]
+then
+ exit 0
+fi
+
+eval ${DOIT}
+
+
+# vim:ts=4
diff --git a/sys-devel/gcc-config/files/wrapper-1.4.c b/sys-devel/gcc-config/files/wrapper-1.4.c
new file mode 100644
index 000000000000..049ae72c92e0
--- /dev/null
+++ b/sys-devel/gcc-config/files/wrapper-1.4.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright 1999-2003 Gentoo Technologies, Inc.
+ * Distributed under the terms of the GNU General Public License v2
+ * Author: Martin Schlemmer <azarah@gentoo.org>
+ * $Header: /var/cvsroot/gentoo-x86/sys-devel/gcc-config/files/wrapper-1.4.c,v 1.1 2003/02/23 16:20:10 azarah Exp $
+ */
+
+#define _REENTRANT
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <wait.h>
+#include <libgen.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+
+struct wrapper_data {
+ char name[MAXPATHLEN + 1];
+ char fullname[MAXPATHLEN + 1];
+ char bin[MAXPATHLEN + 1];
+ char tmp[MAXPATHLEN + 1];
+
+ char *path;
+};
+
+static const char *wrapper_strerror(int err, struct wrapper_data *data)
+{
+ strerror_r(err, data->tmp, sizeof(data->tmp));
+ return data->tmp;
+}
+
+static void wrapper_exit(char *msg, ...)
+{
+ va_list args;
+ va_start(args, msg);
+ vfprintf(stderr, msg, args);
+ va_end(args);
+ exit(1);
+}
+
+/* find_bin checks in path for the file we are seeking
+ it returns 1 if found (with data->bin setup), 0 if not
+ and negative on error */
+static int check_for_target(char *path, struct wrapper_data *data)
+{
+ struct stat sbuf;
+ int result = 0;
+ char *str = data->tmp;
+ size_t len = strlen(path) + strlen(data->name) + 2;
+
+ snprintf(str, len, "%s/%s", path, data->name);
+
+ /* Stat possible file to check that
+ 1) it exist and is a regular file, and
+ 2) it is not the wrapper itself, and
+ 3) it is in a /gcc-bin/ directory tree */
+ result = stat(str, &sbuf);
+ if ((0 == result) && (sbuf.st_mode & S_IFREG) &&
+ (0 != strcmp(str, data->fullname)) &&
+ (0 != strstr(str, "/gcc-bin/"))) {
+ strncpy(data->bin, str, MAXPATHLEN);
+ data->bin[MAXPATHLEN] = 0;
+ result = 1;
+ }
+ else
+ result = 0;
+
+ return result;
+}
+
+static int find_target_in_path(struct wrapper_data *data)
+{
+ char *token = NULL, *str = data->tmp, *state;
+
+ if (NULL == data->path) return 0;
+
+ /* Make a copy since strtok_r will modify path */
+ snprintf(str, MAXPATHLEN + 1, "%s", data->path);
+
+ token = strtok_r(str, ":", &state);
+
+ /* Find the first file with suitable name in PATH. The idea here is
+ * that we do not want to bind ourselfs to something static like the
+ * default profile, or some odd environment variable, but want to be
+ * able to build something with a non default gcc by just tweaking
+ * the PATH ... */
+ while ((NULL != token) && (strlen(token) > 0)) {
+ if (check_for_target(token, data))
+ return 1;
+
+ token = strtok_r(NULL, ":", &state);
+ }
+
+ return 0;
+}
+
+static void find_wrapper_target(struct wrapper_data *data)
+{
+ FILE *inpipe = NULL;
+ char *str = data->tmp;
+
+ if (find_target_in_path(data))
+ return;
+
+ /* Only our wrapper is in PATH, so
+ get the CC path using gcc-config and
+ execute the real binary in there... */
+ inpipe = popen("/usr/bin/gcc-config --get-bin-path", "r");
+ if (NULL == inpipe) {
+ wrapper_exit(
+ "Could not open pipe for /usr/bin/gcc-config: %s\n",
+ wrapper_strerror(errno, data));
+ }
+
+ if (0 == fgets(str, MAXPATHLEN, inpipe))
+ wrapper_exit("Could not get compiler binary path: %s\n",
+ wrapper_strerror(errno, data));
+
+ strncpy(data->bin, str, sizeof(data->bin) - 1);
+ data->bin[strlen(data->bin) - 1] = '/';
+ strncat(data->bin, data->name, sizeof(data->bin) - 1);
+ data->bin[MAXPATHLEN] = 0;
+
+ pclose(inpipe);
+}
+
+/* This function modifies PATH to have gcc's bin path appended */
+static void modify_path(struct wrapper_data *data)
+{
+ char *newpath = NULL, *token = NULL, *state;
+ char dname_data[MAXPATHLEN + 1];
+ char *str = data->tmp, *str2 = dname_data, *dname = dname_data;
+ size_t len = 0;
+
+ if (NULL == data->bin)
+ return;
+
+ snprintf(str2, MAXPATHLEN + 1, "%s", data->bin);
+
+ if (NULL == (dname = dirname(str2)))
+ return;
+
+ if (NULL == data->path)
+ return;
+
+ /* Make a copy since strtok_r will modify path */
+ snprintf(str, MAXPATHLEN + 1, "%s", data->path);
+
+ token = strtok_r(str, ":", &state);
+
+ /* Check if we already appended our bin location to PATH */
+ if ((NULL != token) && (strlen(token) > 0)) {
+ if (0 == strcmp(token, dname))
+ return;
+ }
+
+ len = strlen(dname) + strlen(data->path) + 2;
+
+ newpath = (char *)malloc(len);
+ if (NULL == newpath)
+ wrapper_exit("wrapper: out of memory\n");
+ memset(newpath, 0, len);
+
+ snprintf(newpath, len, "%s:%s", dname, data->path);
+ setenv("PATH", newpath, 1);
+
+ if (newpath)
+ free(newpath);
+ newpath = NULL;
+}
+
+int main(int argc, char **argv)
+{
+ struct wrapper_data *data;
+ size_t size;
+ char *path;
+ int result = 0;
+
+ data = alloca(sizeof(*data));
+ if (NULL == data)
+ wrapper_exit("%s wrapper: out of memory\n", argv[0]);
+ memset(data, 0, sizeof(*data));
+
+ path = getenv("PATH");
+ if (NULL != path) {
+ data->path = strdup(getenv("PATH"));
+ if (NULL == data->path)
+ wrapper_exit("%s wrapper: out of memory\n", argv[0]);
+ }
+
+ /* What should we find ? */
+ strcpy(data->name, basename(argv[0]));
+
+ /* cc calls "/full/path/to/gcc" ... */
+ if (0 == strcmp(data->name, "cc"))
+ strcpy(data->name, "gcc");
+
+ /* What is the full name of our wrapper? */
+ size = sizeof(data->fullname);
+ result = snprintf(data->fullname, size, "/usr/bin/%s", data->name);
+ if ((-1 == result) || (result > size))
+ wrapper_exit("invalid wrapper name: \"%s\"\n", data->name);
+
+ find_wrapper_target(data);
+
+ modify_path(data);
+
+ if (data->path)
+ free(data->path);
+ data->path = NULL;
+
+ /* Set argv[0] to the correct binary, else gcc do not find internal
+ * headers, etc (bug #8132). */
+ argv[0] = data->bin;
+
+ /* Ok, do it ... */
+ if (execv(data->bin, argv) < 0)
+ wrapper_exit("Could not run/locate \"%s\"\n", data->name);
+
+ return 0;
+}
+