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 |
-} |