diff options
author | Fabian Groffen <grobian@gentoo.org> | 2017-12-25 20:47:01 +0100 |
---|---|---|
committer | Fabian Groffen <grobian@gentoo.org> | 2017-12-25 20:47:01 +0100 |
commit | 548521db9b370ac42d6497a4bdcc9fe73ce25019 (patch) | |
tree | 7abbed907101ce991a9de30af7bf61a62d643f5f /sys-devel | |
parent | sys-devel/binutils-config: add cross-support to ldwrapper (diff) | |
download | prefix-548521db9b370ac42d6497a4bdcc9fe73ce25019.tar.gz prefix-548521db9b370ac42d6497a4bdcc9fe73ce25019.tar.bz2 prefix-548521db9b370ac42d6497a4bdcc9fe73ce25019.zip |
sys-devel/binutils-config: rework cross-support
This is on top of previous commit which is Michael Weiser's work from
bug #583202. This rework avoids some mallocs, and tries to optimise the
path needed for a run.
Closes: https://bugs.gentoo.org/583202
Package-Manager: Portage-2.3.18-prefix, Repoman-2.3.6
Diffstat (limited to 'sys-devel')
-rw-r--r-- | sys-devel/binutils-config/Manifest | 1 | ||||
-rw-r--r-- | sys-devel/binutils-config/binutils-config-5-r03.1.ebuild | 8 | ||||
-rw-r--r-- | sys-devel/binutils-config/binutils-config-5-r03.2.ebuild | 74 | ||||
-rw-r--r-- | sys-devel/binutils-config/files/ldwrapper.c | 334 |
4 files changed, 229 insertions, 188 deletions
diff --git a/sys-devel/binutils-config/Manifest b/sys-devel/binutils-config/Manifest new file mode 100644 index 0000000000..03c89e40d2 --- /dev/null +++ b/sys-devel/binutils-config/Manifest @@ -0,0 +1 @@ +DIST binutils-config-ldwrapper-5.3.1.c 8342 BLAKE2B 18658a8188acfcd7494981bd60f53590f5610c7ffd9173f223da740c09acd9ed40aaf911faa6f9a517e5e8779cbaaea9d4398679b7a3037655a7994d9c319345 SHA512 af21c1b9bb465990e8490641023403ec27e31bd69f94fc86572392285a540ddc25d59fd8f682c0cb2d2a84c5e33fea08bd0ec2cb52861147075ccfd5e18067b0 diff --git a/sys-devel/binutils-config/binutils-config-5-r03.1.ebuild b/sys-devel/binutils-config/binutils-config-5-r03.1.ebuild index dc74595d72..142a1e62ee 100644 --- a/sys-devel/binutils-config/binutils-config-5-r03.1.ebuild +++ b/sys-devel/binutils-config/binutils-config-5-r03.1.ebuild @@ -7,7 +7,9 @@ inherit eutils prefix DESCRIPTION="Utility to change the binutils version being used" HOMEPAGE="https://www.gentoo.org/" -SRC_URI="" +GIT_REV="d469b099b5e8aed45ff2edf78f91822b805440d3" +WRAPPER_REV="${PV}.3.1" +SRC_URI="https://gitweb.gentoo.org/repo/proj/prefix.git/plain/sys-devel/binutils-config/files/ldwrapper.c?id=${GIT_REV} -> ${PN}-ldwrapper-${WRAPPER_REV}.c" LICENSE="GPL-2" SLOT="0" @@ -27,8 +29,6 @@ src_prepare() { epatch "${FILESDIR}/${PN}-5-ldwrapper.patch" fi eprefixify ${PN} - - cp "${FILESDIR}"/ldwrapper.c . || die } src_configure() { @@ -41,7 +41,7 @@ src_compile() { $(tc-getCC) ${CPPFLAGS} ${CFLAGS} - -o ldwrapper ldwrapper.c + -o ldwrapper "${S}"/${PN}-ldwrapper-${WRAPPER_REV}.c -DEPREFIX=\"${EPREFIX}\" -DCHOST=\"${CHOST}\" $([[ ${CHOST} == *-darwin* ]] && echo -DTARGET_DARWIN) diff --git a/sys-devel/binutils-config/binutils-config-5-r03.2.ebuild b/sys-devel/binutils-config/binutils-config-5-r03.2.ebuild new file mode 100644 index 0000000000..942065aee5 --- /dev/null +++ b/sys-devel/binutils-config/binutils-config-5-r03.2.ebuild @@ -0,0 +1,74 @@ +# Copyright 1999-2017 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +EAPI="5" + +inherit eutils prefix + +DESCRIPTION="Utility to change the binutils version being used" +HOMEPAGE="https://www.gentoo.org/" +SRC_URI="" + +LICENSE="GPL-2" +SLOT="0" +KEYWORDS="~ppc-aix ~x64-cygwin ~amd64-linux ~x86-linux ~ppc-macos ~x64-macos ~x86-macos ~m68k-mint ~sparc-solaris ~sparc64-solaris ~x64-solaris ~x86-solaris" +IUSE="" + +# 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} + +# 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}-5-ldwrapper.patch" + fi + eprefixify ${PN} +} + +src_configure() { + : +} + +src_compile() { + use prefix-guest || return + local args=( + $(tc-getCC) + ${CPPFLAGS} + ${CFLAGS} + -o ldwrapper "${FILESDIR}"/ldwrapper.c + -DEPREFIX=\"${EPREFIX}\" + -DCHOST=\"${CHOST}\" + ${LDFLAGS} + ) + echo ${args[*]} + "${args[@]}" || die +} + +src_install() { + dobin ${PN} + use prefix && eprefixify "${ED}"/usr/bin/${PN} + sed -i "s:@PV@:${PVR}:g" "${ED}"/usr/bin/${PN} || die + 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 +} + +pkg_preinst() { + # Force a refresh when upgrading from an older version that symlinked + # in all the libs & includes that binutils-libs handles. #528088 + if has_version "<${CATEGORY}/${PN}-5" ; then + local bc current + bc="${ED}/usr/bin/binutils-config" + if current=$("${bc}" -c) ; then + "${bc}" "${current}" + fi + fi +} diff --git a/sys-devel/binutils-config/files/ldwrapper.c b/sys-devel/binutils-config/files/ldwrapper.c index 81b78adf20..bf9f00728b 100644 --- a/sys-devel/binutils-config/files/ldwrapper.c +++ b/sys-devel/binutils-config/files/ldwrapper.c @@ -12,9 +12,9 @@ #include <string.h> #include <ctype.h> #include <sys/stat.h> +#include <sys/types.h> #include <errno.h> -#include <glob.h> -#include <stdarg.h> +#include <dirent.h> /** * ldwrapper: Prefix helper to inject -L and -R flags to the invocation @@ -40,89 +40,65 @@ # error CHOST must be defined! #endif -static inline int is_cross(const char *ctarget) { - return strcmp(ctarget, CHOST); -} - -static inline int is_darwin(const char *ctarget) { - return (strstr(ctarget, "-darwin") != NULL); -} - -static inline int is_aix(const char *ctarget) { - return (strstr(ctarget, "-aix") != NULL); -} +#define ESIZ 1024 /* POSIX_MAX_PATH */ -static inline char * -find_real_ld(const char verbose, const char *wrapper, const char *ctarget) +static inline char +find_real_ld(char **ld, size_t ldlen, const char verbose, const char is_cross, + const char *wrapper, const char *ctarget) { FILE *f = NULL; - char *ldoveride; + char *ldoverride; char *path; -#define ESIZ 1024 /* POSIX_MAX_PATH */ char *ret; struct stat lde; - char *config; - const char *config_prefix; - size_t configlen; + char config[ESIZ]; + size_t len; /* respect the override in environment */ - ldoveride = getenv("BINUTILS_CONFIG_LD"); - if (ldoveride != NULL && *ldoveride != '\0') { + ldoverride = getenv("BINUTILS_CONFIG_LD"); + if (ldoverride != NULL && *ldoverride != '\0') { if (verbose) fprintf(stdout, "%s: using BINUTILS_CONFIG_LD=%s " - "from environment\n", wrapper, ldoveride); - return ldoveride; + "from environment\n", wrapper, ldoverride); + snprintf(*ld, ldlen, "%s", ldoverride); + return 0; } if (verbose) fprintf(stdout, "%s: BINUTILS_CONFIG_LD not found in environment\n", wrapper); - ret = malloc(sizeof(char) * ESIZ); - if (ret == 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. strdup it because - * modifying it would otherwise corrupt the actual PATH environment - * variable which we might need to be intact later on to call - * binutils-config via popen. */ - path = strdup(getenv("PATH")); + /* Find ld in PATH, allowing easy PATH overrides. + * Remember NOT to modify the from getenv returned string, as we need + * an untampered PATH for popen calls later. */ + path = getenv("PATH"); if (path != NULL && *path != '\0') { char *p; char *q; - char *match; - const char *match_anchor = "/binutils-bin/"; - size_t matchlen = 1 + strlen(ctarget) + - strlen(match_anchor) + 1; - - match = malloc(sizeof(char) * matchlen); - if (match == NULL) { - fprintf(stderr, "%s: out of memory allocating " - "buffer for path matching\n", - wrapper); - exit(1); + char match[ESIZ]; + + /* construct /CTARGET/binutils-bin/ for matching against PATH */ + snprintf(match, sizeof(match), "/%s/binutils-bin/", ctarget); + + for (; (p = strstr(path, match)) != NULL; path = q) { + q = p; + /* find start of PATH component */ + for (; p >= path && *p != ':'; p--) + ; + p++; + /* now see to the end */ + for (q += strlen(match); *q != '\0' && *q != ':'; q++) + ; + if (*q == ':') + q--; + + /* glue it together */ + snprintf(*ld, ldlen, "%.*s/%s", (int)(q - p), p, wrapper); + if (verbose) + fprintf(stdout, "%s: trying from PATH: %s\n", + wrapper, *ld); + if (stat(*ld, &lde) == 0) + return 0; } - - /* construct /CTARGET/binutils-bin/ for matchin against PATH */ - snprintf(match, matchlen, "/%s%s", ctarget, match_anchor); - - for (p = path; (q = strchr(p, ':')) != NULL; p = q + 1) { - if (q) - *q = '\0'; - if (strstr(p, match) != NULL) { - snprintf(ret, ESIZ, "%s/%s", p, wrapper); - if (stat(ret, &lde) == 0) { - free(match); - return ret; - } - } - if (!q) - break; - } - - free(match); } if (verbose) fprintf(stdout, "%s: linker not found in PATH\n", wrapper); @@ -130,125 +106,115 @@ find_real_ld(const char verbose, const char *wrapper, const char *ctarget) /* parse EPREFIX/etc/env.d/binutils/config-CTARGET to get CURRENT, then * consider $EPREFIX/usr/CTARGET/binutils-bin/CURRENT where we should * be able to find ld */ - config_prefix = EPREFIX "/etc/env.d/binutils/config-"; - configlen = strlen(config_prefix) + strlen(ctarget) + 1; - config = malloc(sizeof(char) * configlen); - if (config == NULL) { - fprintf(stderr, "%s: out of memory allocating " - "buffer for configuration file name\n", - wrapper); - exit(1); - } - - snprintf(config, configlen, "%s%s", config_prefix, ctarget); + snprintf(config, sizeof(config), EPREFIX "/etc/env.d/binutils/config-%s", + ctarget); if ((f = fopen(config, "r")) != NULL) { char p[ESIZ]; char *q; while (fgets(p, ESIZ, f) != NULL) { - if (strncmp(p, "CURRENT=", strlen("CURRENT=")) != 0) + len = strlen("CURRENT="); + if (strncmp(p, "CURRENT=", len) != 0) continue; q = p + strlen(p); - /* strip trailing whitespace (fgets at least includes - * the \n) */ + /* strip trailing whitespace (fgets at least includes the \n) */ for (q--; isspace(*q); q--) *q = '\0'; - q = p + strlen("CURRENT="); - if (is_cross(ctarget)) { - snprintf(ret, ESIZ, EPREFIX "/usr/" CHOST "/%s/binutils-bin/%s/%s", + q = p + len; + if (verbose) + fprintf(stdout, "%s: %s defines CURRENT=%s\n", + wrapper, config, q); + if (is_cross) { + snprintf(*ld, ldlen, + EPREFIX "/usr/" CHOST "/%s/binutils-bin/%s/%s", ctarget, q, wrapper); } else { - snprintf(ret, ESIZ, EPREFIX "/usr/" CHOST "/binutils-bin/%s/%s", + snprintf(*ld, ldlen, + EPREFIX "/usr/" CHOST "/binutils-bin/%s/%s", q, wrapper); } break; } fclose(f); - if (stat(ret, &lde) == 0) { - free(config); - return ret; - } + if (verbose) + fprintf(stdout, "%s: trying from %s: %s\n", + wrapper, config, *ld); + if (stat(*ld, &lde) == 0) + return 0; } if (verbose) fprintf(stdout, "%s: linker not found via %s\n", wrapper, config); - free(config); - - /* last try, call binutils-config to tell us what the linker is - * supposed to be */ - config_prefix = "binutils-config -c "; - configlen = strlen(config_prefix) + strlen(ctarget) + 1; - config = malloc(sizeof(char) * configlen); - if (config == NULL) { - fprintf(stderr, "%s: out of memory allocating " - "buffer for binutils-config command\n", - wrapper); - exit(1); - } - snprintf(config, configlen, "%s%s", config_prefix, ctarget); + /* last try, shell out to binutils-config to tell us what the linker + * is supposed to be */ + snprintf(config, sizeof(config), "binutils-config -c %s", ctarget); if ((f = popen(config, "r")) != NULL) { char p[ESIZ]; char *q = fgets(p, ESIZ, f); fclose(f); if (q != NULL) { - size_t ctargetlen = strlen(ctarget); + len = strlen(ctarget); /* binutils-config should report CTARGET-<version> */ - if (strncmp(p, ctarget, ctargetlen) == 0 && - strlen(p) > ctargetlen && - p[ctargetlen] == '-') { + if (strncmp(p, ctarget, len) == 0 && + strlen(p) > len && p[len] == '-') + { /* strip trailing whitespace (fgets at least includes * the \n) */ q = p + strlen(p); for (q--; isspace(*q); q--) *q = '\0'; - q = p + ctargetlen + 1; - if (is_cross(ctarget)) { - snprintf(ret, ESIZ, EPREFIX "/usr/" CHOST - "/%s/binutils-bin/%s/%s", + q = p + len + 1; + if (is_cross) { + snprintf(*ld, ldlen, + EPREFIX "/usr/" CHOST "/%s/binutils-bin/%s/%s", ctarget, q, wrapper); } else { - snprintf(ret, ESIZ, EPREFIX "/usr/" CHOST - "/binutils-bin/%s/%s", + snprintf(*ld, ldlen, + EPREFIX "/usr/" CHOST "/binutils-bin/%s/%s", q, wrapper); } - if (stat(ret, &lde) == 0) { - free(config); - return ret; - } + if (verbose) + fprintf(stdout, "%s: trying from %s: %s\n", + wrapper, config, *ld); + if (stat(*ld, &lde) == 0) + return 0; } } } if (verbose) fprintf(stdout, "%s: linker not found via %s\n", wrapper, config); - free(config); /* we didn't succeed finding the linker */ - return NULL; + return 1; } int main(int argc, char *argv[]) { - char *ld = NULL; int newargc = 0; char **newargv = NULL; - char *wrapper = argc > 0 ? argv[0] : "ld-wrapper"; - char *wrapperdir = NULL; + char *wrapper = argv[0]; + char *wrapperctarget = NULL; char verbose = getenv("BINUTILS_CONFIG_VERBOSE") != NULL; char *builddir = getenv("PORTAGE_BUILDDIR"); - size_t builddirlen; + char ldbuf[ESIZ]; + char *ld = ldbuf; + char ctarget[128]; + char is_cross = 0; + char is_darwin = 0; + char is_aix = 0; char *p; + size_t len; int i; int j; int k; - glob_t m; - char *ctarget = CHOST; - size_t ctargetlen; + DIR *dirp; + struct dirent *dp; /* two ways to determine CTARGET from argv[0]: * 1. called as <CTARGET>-ld (manually) @@ -258,61 +224,59 @@ main(int argc, char *argv[]) * work when added to PATH (which shouldn't happen in the wild, but * eh!?). */ if ((p = strrchr(wrapper, '/')) != NULL) { - /* cannonicanise wrapper step 1: strip path */ - wrapper = p + 1; + char *q; - /* remember directory to see if it's CTARGET but only - * if parent is /gcc/ */ + /* see to case 2 first */ *p = '\0'; - if ((p = strrchr(argv[0], '/')) != NULL) { - char *q; - - *p = '\0'; - if ((q = strrchr(argv[0], '/')) != NULL && - strncmp(q + 1, "gcc", strlen("gcc")) == 0) { - wrapperdir = p + 1; - } + if ((q = strrchr(p - 1, '/')) != NULL) { + /* q points to "/<CTARGET>" now */ + len = strlen("/gcc"); + if (q - len > wrapper && strncmp(q - len, "/gcc", len)) + wrapperctarget = q + 1; } + + /* cannonicanise wrapper step 1: strip path */ + wrapper = p + 1; } + /* default to "ld" when called directly */ + if (strcmp(wrapper, "ldwrapper") == 0) + wrapper = "ld"; + /* see if we have a known CTARGET prefix */ - i = glob(EPREFIX "/etc/env.d/binutils/config-*", GLOB_NOSORT, NULL, &m); - if (i == GLOB_NOSPACE) { - fprintf(stderr, "%s: out of memory when inspecting " - "binutils configuration\n", wrapper); - exit(1); - } - if (i == 0) { - for (i = 0; i < m.gl_pathc; i++) { - p = strrchr(m.gl_pathv[i], '/'); - if (p == NULL || strncmp(p, "/config-", strlen("/config-")) != 0) + ctarget[0] = '\0'; + if ((dirp = opendir(EPREFIX "/etc/env.d/binutils")) != NULL) { + while ((dp = readdir(dirp)) != NULL) { + len = strlen("config-"); + if (strncmp(dp->d_name, "config-", len) != 0) continue; - - /* EPREFIX/etc/env.d/binutils/config-arm-something-or-other - * move here ^ */ - p += strlen("/config-"); - if (strncmp(wrapper, p, strlen(p)) == 0 || - (wrapperdir != NULL && strcmp(wrapperdir, p) == 0)) { - /* this is us! (MEMLEAK) */ - ctarget = strdup(p); + p = dp->d_name + len; + if (strncmp(p, wrapper, strlen(p)) == 0 || + (wrapperctarget != NULL && + strcmp(p, wrapperctarget) == 0)) + { + /* this is us! */ + snprintf(ctarget, sizeof(ctarget), "%s", p); + is_cross = strcmp(ctarget, CHOST) != 0; break; } } } - /* ignore GLOB_NOMATCH and (possibly) GLOB_ABORTED */ - globfree(&m); - - /* cannonicanise wrapper step2: strip CTARGET */ - ctargetlen = strlen(ctarget); - if (strncmp(wrapper, ctarget, ctargetlen) == 0 && - wrapper[ctargetlen] == '-') { - wrapper += ctargetlen + 1; - } + if (ctarget[0] == '\0') + snprintf(ctarget, sizeof(ctarget), "%s", CHOST); + + is_darwin = strstr(ctarget, "-darwin") != NULL; + is_aix = strstr(ctarget, "-aix") != NULL; + + /* cannonicanise wrapper step2: strip CTARGET from wrapper */ + len = strlen(ctarget); + if (strncmp(wrapper, ctarget, len) == 0 && wrapper[len] == '-') + wrapper += len + 1; /* ensure builddir is something useful */ if (builddir != NULL && *builddir != '/') builddir = NULL; - builddirlen = builddir == NULL ? 0 : strlen(builddir); + len = builddir == NULL ? 0 : strlen(builddir); /* walk over the arguments to see if there's anything interesting * for us and calculate the final number of arguments */ @@ -326,14 +290,15 @@ main(int argc, char *argv[]) } } /* account the original arguments */ - newargc += argc > 0 ? argc : 1; - /* we always add a null-terminator */ - newargc ++; + newargc += argc; + /* we always add a sentinel */ + newargc++; + /* If a package being cross-compiled injects standard directories, it's * non-cross-compilable on any platform, prefix or no prefix. So no * need to add PREFIX- or CTARGET-aware libdirs. */ - if (!is_cross(ctarget)) { - if (is_darwin(ctarget)) { + if (!is_cross) { + if (is_darwin) { /* add the 2 prefix paths (-L) and -search_paths_first */ newargc += 2 + 1; } else { @@ -341,15 +306,16 @@ main(int argc, char *argv[]) newargc += 8; } - if (is_aix(ctarget)) { + if (is_aix) { /* AIX ld accepts -R only with -bsvr4 */ newargc++; /* -bsvr4 */ } } /* let's first try to find the real ld */ - ld = find_real_ld(verbose, wrapper, ctarget); - if (ld == NULL) { + if (find_real_ld(&ld, sizeof(ldbuf), verbose, is_cross, + wrapper, ctarget) != 0) + { fprintf(stderr, "%s: failed to locate the real ld!\n", wrapper); exit(1); } @@ -369,7 +335,7 @@ main(int argc, char *argv[]) * own call path derived from its argv[0] */ newargv[j++] = ld; - if (!is_cross(ctarget) && is_darwin(ctarget)) { + if (!is_cross && is_darwin) { /* inject this first to make the intention clear */ newargv[j++] = "-search_paths_first"; } @@ -377,7 +343,7 @@ main(int argc, char *argv[]) /* position k right after the original arguments */ k = j - 1 + argc; for (i = 1; i < argc; i++, j++) { - if (is_aix(ctarget)) { + if (is_aix) { /* AIX ld has this problem: * $ /usr/ccs/bin/ld -bsvr4 -bE:xx.exp -bnoentry xx.o * ld: 0706-005 Cannot find or open file: l @@ -392,13 +358,13 @@ main(int argc, char *argv[]) newargv[j] = argv[i]; - if (is_cross(ctarget) || is_darwin(ctarget)) + if (is_cross || is_darwin) continue; /* on ELF targets we add runpaths for all found search paths */ if (argv[i][0] == '-' && argv[i][1] == 'L') { char *path; - size_t len; + size_t sze; /* arguments can be in many ways here: * -L<path> @@ -421,23 +387,23 @@ main(int argc, char *argv[]) continue; /* does it refer to the build directory? skip */ - if (builddir != NULL && strncmp(builddir, path, builddirlen) != 0) + if (builddir != NULL && strncmp(builddir, path, len) != 0) continue; - len = 2 + strlen(path) + 1; - newargv[k] = malloc(sizeof(char) * len); + sze = 2 + strlen(path) + 1; + newargv[k] = malloc(sizeof(char) * sze); if (newargv[k] == NULL) { fprintf(stderr, "%s: failed to allocate memory for " "'%s' -R argument\n", wrapper, argv[i]); exit(1); } - snprintf(newargv[k], len, "-R%s", path); + snprintf(newargv[k], sze, "-R%s", path); k++; } } /* add the custom paths */ - if (!is_cross(ctarget)) { - if (is_darwin(ctarget)) { + if (!is_cross) { + if (is_darwin) { /* FIXME: no support for cross-compiling *to* Darwin */ newargv[k++] = "-L" EPREFIX "/usr/lib"; newargv[k++] = "-L" EPREFIX "/lib"; @@ -452,7 +418,7 @@ main(int argc, char *argv[]) newargv[k++] = "-R" EPREFIX "/lib"; } - if (is_aix(ctarget)) + if (is_aix) newargv[k++] = "-bsvr4"; /* last one, see above */ } newargv[k] = NULL; |