commit: 72ebd34b9821ad0b04bc98b7decf07c9588c7191 Author: Fabian Groffen <grobian <AT> gentoo <DOT> org> AuthorDate: Sun Feb 14 13:48:51 2016 +0000 Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org> CommitDate: Sun Feb 14 13:48:51 2016 +0000 URL: https://gitweb.gentoo.org/repo/proj/prefix.git/commit/?id=72ebd34b
sys-devel/binutils-config: first version of rewritten ldwrapper, bug #572390 Package-Manager: portage-2.2.20-prefix .../binutils-config/binutils-config-5-r2.ebuild | 40 ++-- .../files/binutils-config-5-ldwrapper.patch | 22 ++ sys-devel/binutils-config/files/ldwrapper.c | 252 +++++++++++++++++++++ 3 files changed, 297 insertions(+), 17 deletions(-) diff --git a/sys-devel/binutils-config/binutils-config-5-r2.ebuild b/sys-devel/binutils-config/binutils-config-5-r2.ebuild index 3af562d..60c601e 100644 --- a/sys-devel/binutils-config/binutils-config-5-r2.ebuild +++ b/sys-devel/binutils-config/binutils-config-5-r2.ebuild @@ -8,49 +8,55 @@ inherit eutils prefix DESCRIPTION="Utility to change the binutils version being used" HOMEPAGE="https://www.gentoo.org/" -W_VER="0.3.1723" -SRC_URI="http://dev.gentoo.org/~grobian/distfiles/toolchain-prefix-wrapper-${W_VER}.tar.xz" LICENSE="GPL-2" SLOT="0" KEYWORDS="~ppc-aix ~x64-freebsd ~x86-freebsd ~hppa-hpux ~ia64-hpux ~x86-interix ~amd64-linux ~ia64-linux ~x86-linux ~x86-linux ~ppc-macos ~x64-macos ~x86-macos ~m68k-mint ~sparc-solaris ~sparc64-solaris ~x64-solaris ~x86-solaris" -IUSE="sunld" # We also RDEPEND on sys-apps/findutils which is in base @system RDEPEND="sys-apps/gentoo-functions !<app-admin/eselect-1.4.5" -S=${WORKDIR}/toolchain-prefix-wrapper-${W_VER} +S=${WORKDIR} # NOTE: the ld wrapper is only enabled on rpath versions of prefix. src_prepare() { cp "${FILESDIR}"/${PN}-${PV} ./${PN} || die if use prefix-guest; then - epatch "${FILESDIR}/${PN}-4-ldwrapper.patch" + epatch "${FILESDIR}/${PN}-5-ldwrapper.patch" fi eprefixify ${PN} - # fix configure stupidity, until next release - sed -i -e 's/x10\.\[3456789\]/x10.*/' configure - epatch "${FILESDIR}"/${PN}-4-no-macosx-version-min.patch - epatch "${FILESDIR}"/${PN}-4-aix-ld-svr4.patch + cp "${FILESDIR}"/ldwrapper.c . || die } src_configure() { - if use prefix-guest; then - econf --with-macosx-version-min=${MACOSX_DEPLOYMENT_TARGET} \ - $(use_with sunld native-ld) - fi + : } -src_install() { - if use prefix-guest; then - emake install DESTDIR="${D}" - fi +src_compile() { + use prefix-guest || return + local args=( + $(tc-getCC) + ${CPPFLAGS} + ${CFLAGS} + -o ldwrapper ldwrapper.c + -DEPREFIX=\"${EPREFIX}\" + -DCHOST=\"${CHOST}\" + $([[ ${CHOST} == *-darwin* ]] && echo -DTARGET_DARWIN) + ${LDFLAGS} + ) + echo ${args[*]} + "${args[@]}" || die +} +src_install() { newbin "${S}"/${PN} ${PN} doman "${FILESDIR}"/${PN}.8 + dodir /usr/$(get_libdir)/misc/binutils-config + mv "${S}"/ldwrapper "${ED}"/usr/$(get_libdir)/misc/binutils-config/ + insinto /usr/share/eselect/modules doins "${FILESDIR}"/binutils.eselect } diff --git a/sys-devel/binutils-config/files/binutils-config-5-ldwrapper.patch b/sys-devel/binutils-config/files/binutils-config-5-ldwrapper.patch new file mode 100644 index 0000000..f184c20 --- /dev/null +++ b/sys-devel/binutils-config/files/binutils-config-5-ldwrapper.patch @@ -0,0 +1,22 @@ +diff --git a/binutils-config b/binutils-config +index 7454527..570a6b0 100755 +--- a/binutils-config ++++ b/binutils-config +@@ -121,7 +121,16 @@ switch_profile() { + cd "${ROOT}/${BINPATH}" || exit 1 + mkdir -p "${ROOT}/${BINPATH_LINKS}" "${EROOT}/usr/bin" + for x in * ; do +- atomic_ln "${BINPATH}/${x}" "${ROOT}/${BINPATH_LINKS}" "${x}" ++ case ${x} in ++ ld*) ++ # put ldwrapper in place ++ atomic_ln "${EROOT}/usr/lib/misc/binutils-config/ldwrapper" "${ROOT}/${BINPATH_LINKS}" "${x}" ++ ;; ++ *) ++ atomic_ln "${BINPATH}/${x}" "${ROOT}/${BINPATH_LINKS}" "${x}" ++ ;; ++ esac ++ + atomic_ln "${BINPATH_LINKS}/${x}" "${EROOT}/usr/bin" "${TARGET}-${x}" + if [[ ${TARGET} == ${HOST} ]] ; then + atomic_ln "${TARGET}-${x}" "${EROOT}/usr/bin" "${x}" diff --git a/sys-devel/binutils-config/files/ldwrapper.c b/sys-devel/binutils-config/files/ldwrapper.c new file mode 100644 index 0000000..355840f --- /dev/null +++ b/sys-devel/binutils-config/files/ldwrapper.c @@ -0,0 +1,252 @@ +/* + * Copyright 1999-2013 Gentoo Foundation + * Distributed under the terms of the GNU General Public License v2 + * Authors: Fabian Groffen <grob...@gentoo.org> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <strings.h> +#include <ctype.h> +#include <sys/stat.h> +#include <errno.h> + +/** + * ldwrapper: Prefix helper to inject -L and -R flags to the invocation + * of ld. + * + * On Darwin it adds -search_path_first to make sure the given paths are + * searched before the default search path. + * The wrapper will inject -L entries for: + * - EPREFIX/usr/CHOST/lib/gcc (when gcc) + * - EPREFIX/usr/CHOST/lib (when binutils) + * - EPREFIX/usr/lib + * - EPREFIX/lib + * On ELF platforms, the wrapper will then add -R (-rpath) entries for + * all -L entries found in the invocation to ensure the libraries found + * at link time will be found at runtime too. + */ + +#ifndef EPREFIX +# error EPREFIX must be defined! +#endif +#ifndef CHOST +# error CHOST must be defined! +#endif + + +static inline void +find_real_ld(char **ld, char verbose, char *wrapper) +{ + FILE *f = NULL; + char *ldoveride; + char *path; +#define ESIZ 1024 + char *e; + struct stat lde; + + /* respect the override in environment */ + ldoveride = getenv("BINUTILS_CONFIG_LD"); + if (ldoveride != NULL && *ldoveride != '\0') { + if (verbose) + fprintf(stdout, "%s: using BINUTILS_CONFIG_LD=%s " + "from environment\n", wrapper, ldoveride); + *ld = ldoveride; + return; + } + if (verbose) + fprintf(stdout, "%s: BINUTILS_CONFIG_LD not found in environment\n", + wrapper); + + if ((e = malloc(sizeof(char) * ESIZ)) == NULL) { + fprintf(stderr, "%s: out of memory allocating string for path to ld\n", + wrapper); + exit(1); + } + + /* find ld in PATH, allowing easy PATH overrides */ + path = getenv("PATH"); + if (path != NULL && *path != '\0') { + char *p; + char *q; + + for (p = path; (q = strchr(p, ':')) != NULL; p = q + 1) { + if (q) + *q = '\0'; + if (strstr(p, "/" CHOST "/binutils-bin/") != NULL) { + snprintf(e, ESIZ, "%s/%s", p, wrapper); + if (stat(e, &lde) == 0) { + *ld = e; + return; + } + } + if (!q) + break; + } + } + if (verbose) + fprintf(stdout, "%s: linker not found in PATH\n", wrapper); + + /* parse EPREFIX/etc/env.d/binutils/config-CHOST to get CURRENT, then + * consider $EPREFIX/usr/CHOST/binutils-bin/CURRENT where we should + * be able to find ld */ + if ((f = fopen(EPREFIX "/etc/env.d/binutils/config-" CHOST, "r")) != NULL) { + char p[ESIZ]; + while (fgets(p, ESIZ, f) != NULL) { + if (strncmp(p, "CURRENT=", strlen("CURRENT=")) == 0) { + char *q = p + strlen(p); + /* strip trailing whitespace (fgets at least includes + * the \n) */ + for (q--; isspace(*q); q--) + *q = '\0'; + ; + snprintf(e, ESIZ, EPREFIX "/usr/" CHOST "/binutils-bin/%s/%s", + p + strlen("CURRENT="), wrapper); + break; + } + } + fclose(f); + if (stat(e, &lde) == 0) { + *ld = e; + return; + } + } + if (verbose) + fprintf(stdout, "%s: linker not found via " EPREFIX + "/etc/env.d/binutils/config-" CHOST "\n", wrapper); + + /* last try, call binutils-config to tell us what the linker is + * supposed to be */ + if ((f = popen("binutils-config -c", "r")) != NULL) { + char p[ESIZ]; + if (fgets(p, ESIZ, f) != NULL) { + snprintf(e, ESIZ, EPREFIX "/usr/" CHOST "/binutils-bin/%s/%s", + p, wrapper); + } else { + *p = '\0'; + } + fclose(f); + if (*p && stat(e, &lde) == 0) { + *ld = e; + return; + } + } + if (verbose) + fprintf(stdout, "%s: linker not found via binutils-config -c\n", + wrapper); + + /* we didn't succeed finding the linker */ + *ld = NULL; +} + +int +main(int argc, char *argv[]) +{ + char *ld = NULL; + int newargc = 0; + char **newargv = NULL; + char *wrapper = argc > 0 ? argv[0] : "ld-wrapper"; + char verbose = getenv("BINUTILS_CONFIG_VERBOSE") != NULL; + char *p; + int i; + int j; + + /* cannonicanise wrapper, stripping path and CHOST */ + if ((p = strrchr(wrapper, '/')) != NULL) { + wrapper = p + 1; + p = CHOST "-"; + if (strncmp(wrapper, p, strlen(p)) == 0) + wrapper += strlen(p); + } + + /* walk over the arguments to see if there's anything interesting + * for us and calculate the final number of arguments */ + for (i = 1; i < argc; i++) { + /* -L: account space for the matching -R */ + if (argv[i][0] == '-') { + if (argv[i][1] == 'L') + newargc++; + if (argv[i][1] == 'v' || argv[i][1] == 'V') + verbose = 1; + } + } + /* account the original arguments */ + newargc += argc > 0 ? argc : 1; +#ifdef TARGET_DARWIN + /* add the 2 prefix paths (-L), -search_paths_first and a + * null-terminator */ + newargc += 2 + 1 + 1; +#else + /* add the 4 paths we want (-L + -R) and a null-terminator */ + newargc += 8 + 1; +#endif + + /* let's first try to find the real ld */ + find_real_ld(&ld, verbose, wrapper); + if (ld == NULL) { + fprintf(stderr, "%s: failed to locate the real ld!\n", wrapper); + exit(1); + } + + newargv = malloc(sizeof(char *) * newargc); + if (newargv == NULL) { + fprintf(stderr, "%s: failed to allocate memory for new arguments\n", + wrapper); + exit(1); + } + + /* construct the new argv */ + j = 0; + if ((p = strrchr(ld, '/')) != NULL) { + newargv[j++] = p + 1; + } else { + newargv[j++] = ld; + } +#ifdef TARGET_DARWIN + /* inject this first to make the intention clear */ + newargv[j++] = "-search_paths_first"; +#endif + for (i = 1; i < argc; i++, j++) { + newargv[j] = argv[i]; +#ifndef TARGET_DARWIN + /* on ELF targets we add runpaths for all found search paths */ + if (argv[i][0] == '-' && argv[i][1] == 'L') { + newargv[++j] = strdup(argv[i]); + if (newargv[j] == NULL) { + fprintf(stderr, "%s: failed to allocate memory for " + "'%s' -R argument\n", wrapper, argv[i]); + exit(1); + } + newargv[j][1] = 'R'; + } +#endif + } + /* add the custom paths */ +#ifdef TARGET_DARWIN + newargv[j++] = "-L" EPREFIX "/usr/lib"; + newargv[j++] = "-L" EPREFIX "/lib"; +#else + newargv[j++] = "-L" EPREFIX "/usr/" CHOST "/lib/gcc"; + newargv[j++] = "-R" EPREFIX "/usr/" CHOST "/lib/gcc"; + newargv[j++] = "-L" EPREFIX "/usr/" CHOST "/lib"; + newargv[j++] = "-R" EPREFIX "/usr/" CHOST "/lib"; + newargv[j++] = "-L" EPREFIX "/usr/lib"; + newargv[j++] = "-R" EPREFIX "/usr/lib"; + newargv[j++] = "-L" EPREFIX "/lib"; + newargv[j++] = "-R" EPREFIX "/lib"; +#endif + newargv[j] = NULL; + + if (verbose) { + fprintf(stdout, "%s: invoking %s with arguments:\n", wrapper, ld); + for (j = 0; newargv[j] != NULL; j++) + fprintf(stdout, " %s\n", newargv[j]); + } + + /* finally, execute the real ld */ + execv(ld, newargv); + fprintf(stderr, "%s: failed to execute %s: %s\n", + wrapper, ld, strerror(errno)); + exit(1); +}