Gentoo Archives: gentoo-commits

From: Sergei Trofimovich <slyfox@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/gcc-config:master commit in: tests/rw-multi-native-configs/, tests/source/, ...
Date: Fri, 24 Aug 2018 18:19:54
Message-Id: 1535134157.9b907ef80bc421df23515afc4c306e4d96c67649.slyfox@gentoo
1 commit: 9b907ef80bc421df23515afc4c306e4d96c67649
2 Author: Sergei Trofimovich <slyfox <AT> gentoo <DOT> org>
3 AuthorDate: Fri Aug 24 17:36:57 2018 +0000
4 Commit: Sergei Trofimovich <slyfox <AT> gentoo <DOT> org>
5 CommitDate: Fri Aug 24 18:09:17 2018 +0000
6 URL: https://gitweb.gentoo.org/proj/gcc-config.git/commit/?id=9b907ef8
7
8 Convert binary wrapper to a symlink wrapper.
9
10 Before the change:
11 /usr/bin/gcc and friends were a copy of /usr/$(libexecdir)/misc/gcc-config
12 After the change:
13 /usr/bin/gcc is a symlink to a real compiler binary. Examples:
14 /usr/${CTARGET}/gcc-bin/${GCC_VER}/gcc (native)
15 /usr/${CHOST}/${CTARGET}/gcc-bin/${GCC_VER}/gcc (cross)
16
17 gcc-config is a binary wrapper that does (or did) a few things:
18
19 - [removed in 2011] injects additional CFLAGS_${ABI}
20
21 Removed in commit 7ac40f3eb8434961f70485247d883f5b3009dcf2
22 "Stop auto appending CFLAGS_<abi> from the env."
23
24 - traverses PATH for real compiler binary and reexecutes it.
25
26 - reads /etc/env.d/05gcc-${CTARGET} as a fallback if PATH is empty.
27
28 Today binary wrapper does only PATH resolution and re-execution.
29
30 This change has a few minor benefits:
31
32 - PATH will not contain explicit /usr/${CHOST}/${CTARGET}/gcc-bin/${GCC_VER}
33 entry. This will make PATH shorter for those who have mavy cross-compilers
34 installed.
35
36 - compiler switch will not require sourcing '. /etc/profile' as changes are
37 applied as soon an symlink is switched.
38
39 - ccache will see gcc binary changes directly and react accordingly.
40 Previously in default configuration ccache cache depended on state of
41 /usr/$(libexecdir)/misc/gcc-config
42
43 See bug #640958 where ccache did not notice USE=-pie -> USE=pie switch.
44
45 - Reasoning about PATH ordering is straightforward: all available binaries
46 (as symlinks) are in /usr/bin.
47
48 See bug #255695 where PATH ordering changed and bug #626606 where
49 people get confused on what is in /usr/bin/gcc binary.
50
51 Bug: https://bugs.gentoo.org/626606
52 Bug: https://bugs.gentoo.org/255695
53 Bug: https://bugs.gentoo.org/640958
54 Signed-off-by: Sergei Trofimovich <slyfox <AT> gentoo.org>
55
56 .gitignore | 3 -
57 Makefile | 8 +-
58 README | 69 +----
59 gcc-config | 33 +--
60 tests/rw-multi-native-configs/test.select | 4 +-
61 .../usr/lib/gcc-config/wrapper | 0
62 tests/source/test.whitespace | 2 +-
63 wrapper.c | 323 ---------------------
64 8 files changed, 28 insertions(+), 414 deletions(-)
65
66 diff --git a/.gitignore b/.gitignore
67 index 23938ed..b79124b 100644
68 --- a/.gitignore
69 +++ b/.gitignore
70 @@ -1,6 +1,4 @@
71 -a.out
72 *~
73 -*.o
74
75 *.diff
76 *.patch
77 @@ -10,4 +8,3 @@ a.out
78 /gcc-config-*.tar.*
79
80 /.gcc-config
81 -/wrapper
82
83 diff --git a/Makefile b/Makefile
84 index 3cbb915..3e9e5a3 100644
85 --- a/Makefile
86 +++ b/Makefile
87 @@ -13,16 +13,15 @@ BINDIR = $(PREFIX)/bin
88 ESELECTDIR = $(PREFIX)/share/eselect/modules
89 SUBLIBDIR = lib
90 LIBDIR = $(PREFIX)/$(SUBLIBDIR)
91 -LIBEXECDIR = $(LIBDIR)/$(PN)
92
93 MKDIR_P = mkdir -p -m 755
94 INSTALL_EXE = install -m 755
95 INSTALL_DATA = install -m 644
96
97 -all: .gcc-config wrapper
98 +all: .gcc-config
99
100 clean:
101 - rm -f .gcc-config wrapper *.o core
102 + rm -f .gcc-config
103
104 .gcc-config: gcc-config
105 sed \
106 @@ -34,8 +33,7 @@ clean:
107 chmod a+rx $@
108
109 install: all
110 - $(MKDIR_P) $(DESTDIR)$(BINDIR) $(DESTDIR)$(LIBEXECDIR) $(DESTDIR)$(ESELECTDIR)
111 - $(INSTALL_EXE) wrapper $(DESTDIR)$(LIBEXECDIR)/wrapper
112 + $(MKDIR_P) $(DESTDIR)$(BINDIR) $(DESTDIR)$(ESELECTDIR)
113 $(INSTALL_EXE) .gcc-config $(DESTDIR)$(BINDIR)/gcc-config
114 $(INSTALL_DATA) gcc.eselect $(DESTDIR)$(ESELECTDIR)
115
116
117 diff --git a/README b/README
118 index e7933d8..bea5e30 100644
119 --- a/README
120 +++ b/README
121 @@ -6,20 +6,18 @@ Gentoo allows switching gcc as system runs via gcc-config:
122 $ gcc-config x86_64-pc-linux-gnu-7.2.0
123
124 Ideally changes should be visible instantly and atomically
125 -without shell restart. Practically see TODOs and BUGs on PATH/ROOTPATH.
126 +without shell restart.
127
128 Files, variables, things.
129 -------------------------
130
131 -- Wrappers (copies of /usr/$(libexec)/gcc-config/wrapper)
132 - /usr/bin/gcc
133 - /usr/bin/g++
134 - /usr/bin/${CTARGET}-gcc
135 +- Wrappers (symlinks to compiler binary like /usr/${CTARGET}/gcc-bin/${GCC_VERSION}/gcc)
136 + /usr/bin/gcc (native)
137 + /usr/bin/g++ (native)
138 + /usr/bin/${CTARGET}-gcc (native and cross)
139 ...
140 (all files from /usr/${CTARGET}/gcc-bin/$GCC_VERSION/*)
141
142 - Wrapper reads env config and re-execs binary from `GCC_PATH`.
143 -
144 See `gcc-config` script for wrapping details.
145
146 - private gcc configs (provided by `toolchain.eclass`, gcc ebuilds)
147 @@ -39,7 +37,6 @@ Files, variables, things.
148 GCC_PATH="/usr/x86_64-pc-linux-gnu/gcc-bin/8.1.0"
149
150 Used by gcc-config to generate wrappers and 05gcc- env.d files.
151 - Used by wrapper to extract GCC_PATH and re-exec().
152
153 - gcc env.d compiler entries (provided by gcc-config)
154
155 @@ -47,8 +44,6 @@ Files, variables, things.
156
157 Populates paths for native-compilers
158
159 - PATH="/usr/x86_64-pc-linux-gnu/gcc-bin/8.2.0"
160 - ROOTPATH="/usr/x86_64-pc-linux-gnu/gcc-bin/8.2.0"
161 GCC_SPECS=""
162 MANPATH="/usr/share/gcc-data/x86_64-pc-linux-gnu/8.2.0/man"
163 INFOPATH="/usr/share/gcc-data/x86_64-pc-linux-gnu/8.2.0/info"
164 @@ -57,60 +52,16 @@ Files, variables, things.
165
166 /etc/env.d/05gcc-${CTARGET} (cross)
167
168 - Populates paths for cross-compilers
169 -
170 - PATH="/usr/x86_64-pc-linux-gnu/powerpc64le-unknown-linux-gnu/gcc-bin/7.3.0"
171 - ROOTPATH="/usr/x86_64-pc-linux-gnu/powerpc64le-unknown-linux-gnu/gcc-bin/7.3.0"
172 -
173 - Used by wrapper to extract PATH and re-exec().
174 - Used by env-update to populate PATH (TODO: remove PATH population).
175 -
176 -How does gcc-config work?
177 --------------------------
178 -
179 -/usr/bin/gcc (or /usr/bin/<tool>) is a wrapper (wrapper.c).
180 -gcc-config allows runtime gcc switch via level of indirection.
181 -
182 -Tool name is ${CTARGET}-<tool> or <tool>. TODO: doesn't it break
183 -on ${CTARGET}-<tool>-<version>? Doesn't ${CTARGET} get misdetected?
184 -
185 -Today's resolution order is the following:
186 + Empty.
187
188 -1. Searches PATH for <tool> and reexecute if found. Some
189 - target paths are ignored:
190 - - itself (/usr/bin/<tool>) is ignored to avoid recursion
191 - - */gcc-bin/* (/usr/${CHOST}/${CTARGET}/gcc-bin/7.3.0) is ignored
192 - as those should precede in PATH to avoid wrapping entirely or be
193 - selected via gcc-config.
194 -2. If [1.] failed search for /etc/env.d/: /etc/env.d/gcc/.NATIVE (native compiler),
195 - /etc/env.d/05gcc-${CTARGET} (cross-compiler).
196 -
197 - There GCC_PATH= (native) or PATH= (cross) directory entry is searched.
198 -
199 - Usually it's GCC_PATH="${EPREFIX}/usr/${CHOST}/gcc-bin/<gcc-version>" (native)
200 - or GCC_PATH="${EPREFIX}/usr/${CHOST}/${CTARGET}/gcc-bin/<gcc-version>" (cross)
201 -
202 -3. If [2.] failed run 'ROOT= gcc-config --get-bin-path' and use it's output.
203 -
204 -4. Prepend path fetched from above to PATH environment variable and re-exec().
205 -
206 -5. Done
207 -
208 -`gcc-config` script maintains binaries in `/usr/bin/` to make the above model work.
209 -
210 -To make compiler switchable in active shell `/usr/bin/` path must precede
211 -'/usr/${CHOST}/gcc-bin/<gcc-version>'. Otherwise wrapper is skipped.
212 + Until Aug 2018 used to contain paths for cross-compilers.
213 + To be removed eventually.
214
215 TODOs
216 -----
217
218 - Write proper `gcc-config` manpage off this readme to be more discoverable.
219
220 -- Make /usr/bin/<tool> a symlink of /usr/$(libexec)/gcc-config/wrapper,
221 - not a file copy. This will make the fact that Gentoo uses wrappers more obvious.
222 - It's essential to know for people using ccache cache or similar.
223 -
224 -- Move /etc/env.d/05gcc-${CTARGET} and /etc/env.d/04gcc-${CTARGET} after
225 - /usr/bin PATH injection to restore gcc-config wrapping.
226 +- Figure out symlink ownership story. Today symlinks don't belong to any package.
227
228 - See https://bugs.gentoo.org/255695 for some details.
229 + See https://bugs.gentoo.org/626606
230
231 diff --git a/gcc-config b/gcc-config
232 index 521e3ba..e7f3fb9 100755
233 --- a/gcc-config
234 +++ b/gcc-config
235 @@ -167,16 +167,14 @@ convert_profile_paths() {
236 return 0
237 }
238
239 -# Usage: atomic_cp <source file> <destination dir> <destination file name> <reference file (mtimes)>
240 -atomic_cp() {
241 - local src=$1 dst=$2 dstfile=$3 ref=$4 tmp
242 +# Usage: atomic_ln <source file> <destination dir> <destination file name>
243 +atomic_ln() {
244 + local src=$1 dst=$2 dstfile=$3 tmp
245 tmp="${dst}/.gcc.config.${dstfile}"
246 - # We need to do this mv to make the update atomic in case
247 - # someone is compiling at the same time they're running
248 - # gcc-config (which is OK if you're just updating gcc-config
249 - # itself and picking the same profile).
250 - cp -f "${src}" "${tmp}"
251 - touch -r "${ref}" "${tmp}"
252 + # `ln` will expand into unlink();symlink(); which
253 + # is not atomic for a small amount of time, but
254 + # `mv` is a single rename() call
255 + ln -sf "${src}" "${tmp}"
256 mv "${tmp}" "${dst}/${dstfile}"
257 }
258
259 @@ -197,13 +195,6 @@ update_wrappers() {
260 # for new functionality (like a version bump).
261 local x CTARGET=$1
262
263 - # Find the bin wrapper
264 - local libdir wrapper
265 - for libdir in ${GENTOO_LIBDIR} lib lib64 lib32 lib ; do
266 - wrapper="${EROOT}usr/${libdir}/gcc-config/wrapper"
267 - [[ -e ${wrapper} ]] && break
268 - done
269 -
270 # Use the old dir to see what we wrapped up previously.
271 local old_wrappers=( $(
272 [[ -n ${OLD_GCC_PATH} ]] || exit 1
273 @@ -261,9 +252,9 @@ update_wrappers() {
274 fi
275 fi
276
277 - # Now do the actual wrapper copy with paths to the reference binary
278 + # Now do the actual linking to the target binary
279 if [[ -x ${ref} ]] ; then
280 - atomic_cp "${wrapper}" "${EROOT}usr/bin" "${x}" "${ref}"
281 + atomic_ln "${ref#${ROOT}}" "${EROOT}usr/bin" "${x}"
282 else
283 ewarn "double insanity with ${x} and ${ref}"
284 # Make sure we have no stale wrappers
285 @@ -275,7 +266,7 @@ update_wrappers() {
286
287 # install the canonical cpp wrapper
288 if ! is_cross_compiler ; then
289 - atomic_cp "${wrapper}" "${EROOT}lib" "cpp" "${EROOT}usr/bin/cpp"
290 + atomic_ln "${EPREFIX%/}/usr/bin/cpp" "${EROOT}lib" "cpp"
291 fi
292 }
293
294 @@ -619,8 +610,7 @@ switch_profile() {
295 is_cross_compiler && envd_num="05" || envd_num="04"
296 envd="${ENV_D}/${envd_num}gcc-${CTARGET}"
297 cat <<-EOF > "${envd}.tmp"
298 - PATH="${GCC_PATH}"
299 - ROOTPATH="${GCC_PATH}"
300 + # Autogenerated by 'gcc-config'.
301 EOF
302 if ! is_cross_compiler ; then
303 # Only write GCC_SPECS for the native compiler. #420097
304 @@ -724,6 +714,7 @@ switch_profile() {
305
306 eend 0
307
308 + # Not needed since Aug 2018. Can be removed later (say, in a year).
309 if [[ ${envd_changed} -ne 0 ]] ; then
310 echo
311 ewarn "If you intend to use the gcc from the new profile in an already"
312
313 diff --git a/tests/rw-multi-native-configs/test.select b/tests/rw-multi-native-configs/test.select
314 index c6d9daf..a9cc1d1 100644
315 --- a/tests/rw-multi-native-configs/test.select
316 +++ b/tests/rw-multi-native-configs/test.select
317 @@ -18,10 +18,10 @@ for (( i = 1; i < 4; ++i )) ; do
318 esac
319
320 for b in "${do_want[@]}" ; do
321 - [[ -e usr/bin/${b} ]] || exit 1
322 + [[ -L usr/bin/${b} ]] || exit 1
323 done
324 for b in "${dont_want[@]}" ; do
325 - [[ -e usr/bin/${b} ]] && exit 1
326 + [[ -L usr/bin/${b} ]] && exit 1
327 done
328 [[ -e etc/env.d/04gcc-${CHOST} ]] || exit 1
329 done
330
331 diff --git a/tests/rw-multi-native-configs/usr/lib/gcc-config/wrapper b/tests/rw-multi-native-configs/usr/lib/gcc-config/wrapper
332 deleted file mode 100755
333 index e69de29..0000000
334
335 diff --git a/tests/source/test.whitespace b/tests/source/test.whitespace
336 index 28108ae..26d1bdb 100644
337 --- a/tests/source/test.whitespace
338 +++ b/tests/source/test.whitespace
339 @@ -1,2 +1,2 @@
340 #!/bin/bash
341 -! egrep -nH '[[:space:]]+$' "${TROOT}"/../{gcc-config,wrapper.c}
342 +! egrep -nH '[[:space:]]+$' "${TROOT}"/../gcc-config
343
344 diff --git a/wrapper.c b/wrapper.c
345 deleted file mode 100644
346 index c245dbb..0000000
347 --- a/wrapper.c
348 +++ /dev/null
349 @@ -1,323 +0,0 @@
350 -/*
351 - * Copyright 1999-2012 Gentoo Foundation
352 - * Distributed under the terms of the GNU General Public License v2
353 - * Author: Martin Schlemmer <azarah@g.o>
354 - * az's lackey: Mike Frysinger <vapier@g.o>
355 - */
356 -
357 -#ifdef DEBUG
358 -# define USE_DEBUG 1
359 -#else
360 -# define USE_DEBUG 0
361 -#endif
362 -
363 -#ifndef _FILE_OFFSET_BITS
364 -# define _FILE_OFFSET_BITS 64 /* #471024 */
365 -#endif
366 -
367 -#include <errno.h>
368 -#include <libgen.h>
369 -#include <limits.h>
370 -#include <stdio.h>
371 -#include <stdlib.h>
372 -#include <string.h>
373 -#include <unistd.h>
374 -#include <sys/stat.h>
375 -#include <sys/types.h>
376 -
377 -#ifndef EPREFIX
378 -# define EPREFIX ""
379 -#endif
380 -
381 -#define GCC_CONFIG EPREFIX "/usr/bin/gcc-config"
382 -#define ENVD_BASE EPREFIX "/etc/env.d/05gcc"
383 -
384 -#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
385 -
386 -/* basename(3) is allowed to modify memory */
387 -#undef basename
388 -#define basename(path) \
389 -({ \
390 - char *__path = path; \
391 - char *__ret = strrchr(__path, '/'); \
392 - __ret ? __ret + 1 : __path; \
393 -})
394 -
395 -struct wrapper_data {
396 - const char *name;
397 - char *fullname, *bin, *path;
398 -};
399 -
400 -static const struct {
401 - const char *alias;
402 - const char *target;
403 -} wrapper_aliases[] = {
404 - { "cc", "gcc" },
405 - { "f77", "gfortran" },
406 - { "f95", "gfortran" },
407 -};
408 -
409 -#define wrapper_warn(fmt, ...) fprintf(stderr, "%s" fmt "\n", "gcc-config: ", ## __VA_ARGS__)
410 -#define wrapper_err(fmt, ...) ({ wrapper_warn("%s" fmt, "error: ", ## __VA_ARGS__); exit(1); })
411 -#define wrapper_errp(fmt, ...) wrapper_err(fmt ": %s", ## __VA_ARGS__, strerror(errno))
412 -#define wrapper_dbg(fmt, ...) ({ if (USE_DEBUG) wrapper_warn(fmt, ## __VA_ARGS__); })
413 -
414 -#define xmemwrap(func, proto, use) \
415 -static void *x ## func proto \
416 -{ \
417 - void *ret = func use; \
418 - if (!ret) \
419 - wrapper_err(#func "%s", ": out of memory"); \
420 - return ret; \
421 -}
422 -xmemwrap(malloc, (size_t size), (size))
423 -xmemwrap(strdup, (const char *s), (s))
424 -
425 -/* check_for_target checks in path for the file we are seeking
426 - * it returns 1 if found (with data->bin setup), 0 if not and
427 - * negative on error
428 - */
429 -static int check_for_target(char *path, struct wrapper_data *data)
430 -{
431 - struct stat sbuf;
432 - char str[PATH_MAX + 1];
433 - size_t path_len = strlen(path);
434 - size_t len = path_len + strlen(data->name) + 2;
435 -
436 - if (sizeof(str) < len)
437 - wrapper_warn("path too long: %s", path);
438 -
439 - strcpy(str, path);
440 - str[path_len] = '/';
441 - str[path_len+1] = '\0';
442 - strcat(str, data->name);
443 -
444 - /* Stat possible file to check that
445 - * 1) it exist and is a regular file, and
446 - * 2) it is not the wrapper itself, and
447 - * 3) it is in a /gcc-bin/ directory tree
448 - */
449 - if (strcmp(str, data->fullname) != 0 &&
450 - strstr(str, "/gcc-bin/") != NULL &&
451 - stat(str, &sbuf) == 0 &&
452 - (S_ISREG(sbuf.st_mode) || S_ISLNK(sbuf.st_mode)))
453 - {
454 - wrapper_dbg("%s: found in %s", data->name, path);
455 - data->bin = xstrdup(str);
456 - return 1;
457 - }
458 -
459 - wrapper_dbg("%s: did not find in %s", data->name, path);
460 - return 0;
461 -}
462 -
463 -static int find_target_in_path(struct wrapper_data *data)
464 -{
465 - char *token = NULL, *state = NULL;
466 - char *str;
467 -
468 - if (data->path == NULL)
469 - return 0;
470 -
471 - /* Make a copy since strtok_r will modify path */
472 - str = xstrdup(data->path);
473 -
474 - /* Find the first file with suitable name in PATH. The idea here is
475 - * that we do not want to bind ourselfs to something static like the
476 - * default profile, or some odd environment variable, but want to be
477 - * able to build something with a non default gcc by just tweaking
478 - * the PATH ... */
479 - token = strtok_r(str, ":", &state);
480 - while (token != NULL) {
481 - if (check_for_target(token, data))
482 - return 1;
483 - token = strtok_r(NULL, ":", &state);
484 - }
485 -
486 - wrapper_dbg("%s: did not find in PATH", data->name);
487 - return 0;
488 -}
489 -
490 -/* find_target_in_envd parses /etc/env.d/05gcc, and tries to
491 - * extract PATH, which is set to the current profile's bin
492 - * directory ...
493 - */
494 -static int find_target_in_envd(struct wrapper_data *data, int cross_compile)
495 -{
496 - FILE *envfile = NULL;
497 - char *token = NULL, *state;
498 - char str[PATH_MAX + 1];
499 - char *strp = str;
500 - char envd_file[PATH_MAX + 1];
501 -
502 - if (!cross_compile) {
503 - /* for the sake of speed, we'll keep a symlink around for
504 - * the native compiler. #190260
505 - */
506 - snprintf(envd_file, sizeof(envd_file)-1, EPREFIX "/etc/env.d/gcc/.NATIVE");
507 - } else {
508 - char *ctarget, *end = strrchr(data->name, '-');
509 - if (end == NULL)
510 - return 0;
511 - ctarget = xstrdup(data->name);
512 - ctarget[end - data->name] = '\0';
513 - snprintf(envd_file, PATH_MAX, "%s-%s", ENVD_BASE, ctarget);
514 - free(ctarget);
515 - }
516 -
517 - envfile = fopen(envd_file, "r");
518 - if (envfile == NULL)
519 - return 0;
520 -
521 - while (fgets(strp, PATH_MAX, envfile) != NULL) {
522 - /* Keep reading ENVD_FILE until we get a line that
523 - * starts with 'GCC_PATH=' ... keep 'PATH=' around
524 - * for older gcc versions.
525 - */
526 - if (strncmp(strp, "GCC_PATH=", strlen("GCC_PATH=")) &&
527 - strncmp(strp, "PATH=", strlen("PATH=")))
528 - continue;
529 -
530 - token = strtok_r(strp, "=", &state);
531 - if ((token != NULL) && token[0])
532 - /* The second token should be the value of PATH .. */
533 - token = strtok_r(NULL, "=", &state);
534 - else
535 - goto bail;
536 -
537 - if ((token != NULL) && token[0]) {
538 - strp = token;
539 - /* A bash variable may be unquoted, quoted with " or
540 - * quoted with ', so extract the value without those ..
541 - */
542 - token = strtok(strp, "\n\"\'");
543 -
544 - while (token != NULL) {
545 - if (check_for_target(token, data)) {
546 - fclose(envfile);
547 - return 1;
548 - }
549 -
550 - token = strtok(NULL, "\n\"\'");
551 - }
552 - }
553 -
554 - strp = str;
555 - }
556 -
557 - bail:
558 - fclose(envfile);
559 - return (cross_compile ? 0 : find_target_in_envd(data, 1));
560 -}
561 -
562 -static void find_wrapper_target(struct wrapper_data *data)
563 -{
564 - if (find_target_in_path(data))
565 - return;
566 -
567 - if (find_target_in_envd(data, 0))
568 - return;
569 -
570 - /* Only our wrapper is in PATH, so get the CC path using
571 - * gcc-config and execute the real binary in there ...
572 - */
573 - FILE *inpipe = popen("ROOT= " GCC_CONFIG " --get-bin-path", "r");
574 - if (inpipe == NULL)
575 - wrapper_errp("could not open pipe");
576 -
577 - char str[PATH_MAX + 1];
578 - if (fgets(str, PATH_MAX, inpipe) == 0)
579 - wrapper_errp("could not get compiler binary path");
580 -
581 - /* chomp! */
582 - size_t plen = strlen(str);
583 - if (str[plen-1] == '\n')
584 - str[plen-1] = '\0';
585 -
586 - data->bin = xmalloc(plen + 1 + strlen(data->name) + 1);
587 - sprintf(data->bin, "%s/%s", str, data->name);
588 -
589 - pclose(inpipe);
590 -}
591 -
592 -/* This function modifies PATH to have gcc's bin path appended */
593 -static void modify_path(struct wrapper_data *data)
594 -{
595 - char *newpath = NULL, *token = NULL, *state;
596 - char dname_data[PATH_MAX + 1], str[PATH_MAX + 1];
597 - char *str2 = dname_data, *dname = dname_data;
598 - size_t len = 0;
599 -
600 - if (data->bin == NULL)
601 - return;
602 -
603 - if (data->path == NULL)
604 - return;
605 -
606 - snprintf(str2, PATH_MAX + 1, "%s", data->bin);
607 -
608 - if ((dname = dirname(str2)) == NULL)
609 - return;
610 -
611 - /* Make a copy since strtok_r will modify path */
612 - snprintf(str, PATH_MAX + 1, "%s", data->path);
613 -
614 - token = strtok_r(str, ":", &state);
615 -
616 - /* Check if we already appended our bin location to PATH */
617 - if ((token != NULL) && token[0])
618 - if (!strcmp(token, dname))
619 - return;
620 -
621 - len = strlen(dname) + strlen(data->path) + 2 + strlen("PATH") + 1;
622 -
623 - newpath = xmalloc(len);
624 - memset(newpath, 0, len);
625 -
626 - snprintf(newpath, len, "PATH=%s:%s", dname, data->path);
627 - putenv(newpath);
628 -}
629 -
630 -int main(int argc, char *argv[])
631 -{
632 - struct wrapper_data data;
633 - (void)argc; /* unused variable */
634 -
635 - memset(&data, 0, sizeof(data));
636 -
637 - if (getenv("PATH"))
638 - data.path = xstrdup(getenv("PATH"));
639 -
640 - /* What should we find ? */
641 - data.name = basename(argv[0]);
642 -
643 - /* Allow for common compiler names like cc->gcc */
644 - size_t i;
645 - for (i = 0; i < ARRAY_SIZE(wrapper_aliases); ++i)
646 - if (!strcmp(data.name, wrapper_aliases[i].alias))
647 - data.name = wrapper_aliases[i].target;
648 -
649 - /* What is the full name of our wrapper? */
650 - data.fullname = xmalloc(strlen(data.name) + sizeof(EPREFIX "/usr/bin/") + 1);
651 - sprintf(data.fullname, EPREFIX "/usr/bin/%s", data.name);
652 -
653 - find_wrapper_target(&data);
654 -
655 - modify_path(&data);
656 -
657 - free(data.path);
658 - data.path = NULL;
659 -
660 - /* Set argv[0] to the correct binary, else gcc can't find internal headers
661 - * http://bugs.gentoo.org/8132
662 - */
663 - argv[0] = data.bin;
664 -
665 - /* Ok, lets do it one more time ... */
666 - execv(data.bin, argv);
667 -
668 - /* shouldn't have made it here if things worked ... */
669 - wrapper_err("could not run/locate '%s'", data.name);
670 -
671 - return 123;
672 -}