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);
+}

Reply via email to