/[gentoo-alt]/trunk/toolchain-prefix-wrapper/ld/ldwrapper.c
Gentoo

Contents of /trunk/toolchain-prefix-wrapper/ld/ldwrapper.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1723 - (show annotations) (download) (as text)
Thu Jan 10 15:50:37 2013 UTC (19 months, 2 weeks ago) by grobian
File MIME type: text/x-csrc
File size: 30785 byte(s)
add_host_toolchain_libpath: usr/CHOST/lib/gcc no longer needs to exist (on Darwin)
1 /*
2 * Copyright 1999-2013 Gentoo Foundation
3 * Distributed under the terms of the GNU General Public License v2
4 * Authors: Fabian Groffen <grobian@gentoo.org>
5 * Michael Haubenwallner <haubi@gentoo.org>
6 * based on the work of gcc wrapper done by:
7 * Martin Schlemmer <azarah@gentoo.org>
8 * Mike Frysinger <vapier@gentoo.org>
9 */
10
11 #include <config.h>
12 #include <stringutil.h>
13 #include <textfile.h>
14
15 #include "binutils-config.h"
16 #include "ldplugin.h"
17 #include "aixplugin.h"
18 #include "gnuplugin.h"
19 #include "hpuxplugin.h"
20 #include "darwinplugin.h"
21 #include "solarisplugin.h"
22
23 #define _REENTRANT
24 #if !defined(_GNU_SOURCE)
25 #define _GNU_SOURCE
26 #endif
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/param.h>
33 #include <unistd.h>
34 #include <sys/wait.h>
35 #include <libgen.h>
36 #include <string.h>
37 #include <stdarg.h>
38 #include <errno.h>
39
40 #define BINUTILS_CONFIG GENTOO_PORTAGE_EPREFIX "/usr/bin/binutils-config" /* host */
41 #define ENVD_BASE_BINUTILS GENTOO_PORTAGE_EPREFIX "/etc/env.d/binutils/" /* host */
42
43 #define dprintf if (DEBUG()) fprintf
44
45 typedef struct _LdWrapperData {
46 String* name; /* basename(argv[0]), mainly for diagnostics */
47 struct stat arg0stat; /* stat(argv[0]) */
48
49 String* bin; /* the target binary to be executed (on host) */
50
51 StringList* envpath;
52 String* _ctarget_binutilsbin_; /* cached string "/${CTARGET}/binutils-bin/" */
53
54 LdPluginIn pluginIn;
55 } LdWrapperData;
56
57 static inline void wrapper_exit(char *msg, ...)
58 {
59 va_list args;
60 fprintf(stderr, "binutils-config error: ");
61 va_start(args, msg);
62 vfprintf(stderr, msg, args);
63 va_end(args);
64 exit(1);
65 }
66
67 /* create the string "/${CTARGET}/binutils-bin/",
68 * as this is used a few times.
69 */
70 static inline void setup_ctarget_binutilsbin(LdWrapperData *data)
71 {
72 if (data->_ctarget_binutilsbin_ == NULL) {
73 /* cache the string "/${CTARGET}/binutils-bin/" */
74 data->_ctarget_binutilsbin_ = StringCreateConcat("/", 1
75 , StringGetBuffer(data->pluginIn.target.triplet)
76 , StringGetLength(data->pluginIn.target.triplet)
77 , "/binutils-bin/", strlen("/binutils-bin/")
78 , NULL);
79 if (data->_ctarget_binutilsbin_ == NULL) {
80 wrapper_exit("%s wrapper: %s\n",
81 StringGetBuffer(data->name), strerror(errno));
82 }
83 }
84 return;
85 }
86
87 /* check_for_binutils checks in path for the file we are seeking
88 * it returns 1 if found (with data->bin setup), 0 if not
89 */
90 static inline int check_for_binutils(String const * path, LdWrapperData *data)
91 {
92 struct stat sbuf;
93 int result;
94 String* search;
95 char const *str;
96 char const *path_buffer;
97 int path_len;
98
99 /* check possible binary in path that
100 * 1) it is in a "/${CTARGET}/binutils-bin/" directory
101 * ...
102 */
103 path_buffer = StringGetBuffer(path);
104 path_len = StringGetLength(path);
105 str = strstr(path_buffer, StringGetBuffer(data->_ctarget_binutilsbin_));
106 if (str == NULL
107 || (path_len >= 0
108 && (str + StringGetLength(data->_ctarget_binutilsbin_)) > (path_buffer + path_len)
109 )
110 ) {
111 /* not found, or found behind end of path indicated by path_len */
112 return 0;
113 }
114
115 search = StringCreateConcat(path_buffer, path_len
116 , "/", 1
117 , StringGetBuffer(data->name), StringGetLength(data->name)
118 , NULL);
119 if (search == NULL) {
120 wrapper_exit("%s wrapper: %s\n",
121 StringGetBuffer(data->name), strerror(errno));
122 }
123
124 str = StringGetBuffer(search);
125
126 /* ...
127 * 2) and it exist and is a regular file,
128 * 3) and it is not the wrapper itself by filesystem
129 */
130 result = stat(str, &sbuf);
131 if ((result == 0)
132 && ((sbuf.st_mode & S_IFREG) || (sbuf.st_mode & S_IFLNK))
133 && ((sbuf.st_dev != data->arg0stat.st_dev) || (sbuf.st_ino != data->arg0stat.st_ino))
134 ) {
135 data->bin = search;
136 search = NULL;
137 return 1;
138 }
139
140 search = StringDestroy(search);
141 return 0;
142 }
143
144 static inline int find_binutils_in_path(LdWrapperData *data)
145 {
146 int i, pathcount;
147
148 if (data->envpath == NULL) return 0;
149
150 /* Find the first file with suitable name in PATH. The idea here is
151 * that we do not want to bind ourselfs to something static like the
152 * default profile, or some odd environment variable, but want to be
153 * able to build something with a non default binutils by just tweaking
154 * the PATH ... */
155 pathcount = StringListGetSize(data->envpath);
156 for(i = 0; i < pathcount; i++) {
157 String const * token = StringListGetString(data->envpath, i);
158 if (token == NULL || StringGetLength(token) <= 0) {
159 continue;
160 }
161 if (check_for_binutils(token, data)) {
162 return 1;
163 }
164 }
165
166 return 0;
167 }
168
169 /* read the value from some shell line setting a specific variable,
170 * drop leading and trailing whitespaces and quotation marks.
171 * returns NULL if line does not set expected variable.
172 * returns String containing the value for expected variable.
173 */
174 static inline String* parseline_shellvariable(LdWrapperData* data,
175 char const *variable, int varlen, char const *line, int linelen)
176 {
177 String* rv;
178
179 if (linelen < 0) linelen = strlen(line);
180 if (varlen < 0) varlen = strlen(variable);
181
182 /* skip leading blanks */
183 while(linelen > 0 && (*line == ' ' || *line == '\t' || *line == '\n')) {
184 line++;
185 linelen--;
186 }
187
188 if (linelen <= varlen
189 || strncmp(line, variable, varlen) != 0
190 || line[varlen] != '='
191 ) {
192 /* this line does not set expected variable */
193 return NULL;
194 }
195
196 line += varlen+1;
197 linelen -= varlen+1;
198
199 /* skip string delimiters */
200 while(linelen > 0 && (*line == '\'' || *line == '\"')) {
201 line++;
202 linelen--;
203 }
204
205 /* skip string end delimiters and trailing blanks */
206 while(linelen > 0
207 && (line[linelen-1] == '\''
208 || line[linelen-1] == '\"'
209 || line[linelen-1] == ' '
210 || line[linelen-1] == '\t'
211 || line[linelen-1] == '\n'
212 )
213 ) {
214 linelen--;
215 }
216
217 rv = StringCreateConcat(line, linelen, NULL);
218 if (rv == NULL) {
219 wrapper_exit("%s wrapper: %s\n",
220 StringGetBuffer(data->name), strerror(errno));
221 }
222 return rv;
223 }
224
225 /* find_binutils_in_envd parses /etc/env.d/binutils/config-${CTARGET} to get
226 * current BVER, then tries to parse /etc/env.d/binutils/${CTARGET}-${BVER}
227 * to extract PATH, which is set to the current binutils' bin directory ...
228 */
229 static inline int find_binutils_in_envd(LdWrapperData *data)
230 {
231 Textfile* envfile = NULL;
232 String const * thisline;
233 String* currentBVER = NULL;
234 String* bindir = NULL;
235 int rv = 0;
236
237 envfile = TextfileOpenConcatName(ENVD_BASE_BINUTILS, strlen(ENVD_BASE_BINUTILS),
238 "config-", strlen("config-"),
239 StringGetBuffer(data->pluginIn.target.triplet),
240 StringGetLength(data->pluginIn.target.triplet),
241 NULL);
242 if (envfile == NULL && errno != ENOENT) {
243 wrapper_exit("%s wrapper: %s\n",
244 StringGetBuffer(data->name), strerror(errno));
245 }
246 if (envfile == NULL) {
247 return 0;
248 }
249
250 /* read current binutils version:
251 * /etc/env.d/binutils/config-${CTARGET} must contain this line:
252 * CURRENT=${BVER}
253 */
254 while(TextfileReadLine(envfile) > 0) {
255 thisline = TextfileGetCurrentLine(envfile);
256 currentBVER = parseline_shellvariable(data, "CURRENT", strlen("CURRENT"),
257 StringGetBuffer(thisline), StringGetLength(thisline));
258 if (currentBVER != NULL) {
259 break;
260 }
261 }
262
263 envfile = TextfileClose(envfile);
264 if (currentBVER == NULL) {
265 /* /etc/env.d/binutils/config-${CTARGET} does not contain any CURRENT= */
266 return 0;
267 }
268
269 /* construct path to binutils:
270 * CHOST == CTARGET: PATH=/gentoo/portage/host.eprefix/usr/${CHOST}/binutils-bin/${BVER}
271 * CHOST != CTARGET: PATH=/gentoo/portage/host.eprefix/usr/${CHOST}/${CTARGET}/binutils-bin/${BVER}
272 */
273 if (data->pluginIn.isCrossTriplet) {
274 bindir = StringCreateConcat(
275 GENTOO_PORTAGE_EPREFIX, strlen(GENTOO_PORTAGE_EPREFIX),
276 "/usr/", strlen("/usr/"),
277 StringGetBuffer(data->pluginIn.host.triplet),
278 StringGetLength(data->pluginIn.host.triplet),
279 StringGetBuffer(data->_ctarget_binutilsbin_),
280 StringGetLength(data->_ctarget_binutilsbin_),
281 StringGetBuffer(currentBVER), StringGetLength(currentBVER),
282 NULL);
283 } else {
284 bindir = StringCreateConcat(
285 GENTOO_PORTAGE_EPREFIX, strlen(GENTOO_PORTAGE_EPREFIX),
286 "/usr", strlen("/usr"),
287 StringGetBuffer(data->_ctarget_binutilsbin_),
288 StringGetLength(data->_ctarget_binutilsbin_),
289 StringGetBuffer(currentBVER), StringGetLength(currentBVER),
290 NULL);
291 }
292 if (bindir == NULL) {
293 wrapper_exit("%s wrapper: %s\n",
294 StringGetBuffer(data->name), strerror(errno));
295 }
296 StringDestroy(currentBVER);
297
298 if (check_for_binutils(bindir, data)) {
299 rv = 1;
300 }
301
302 StringDestroy(bindir);
303
304 return rv;
305 }
306
307 static inline void find_wrapper_binutils(LdWrapperData *data)
308 {
309 FILE *inpipe = NULL;
310 String* binpath_command;
311 char str[MAXPATHLEN + 1];
312 char const* env = getenv("BINUTILS_CONFIG_LD");
313
314 if (env != NULL && *env != '\0') {
315 /* as we do linking during binutils-config,
316 * we need some working ld-wrapper for gcc,
317 * but the old one may be configured for the now unmerged ld.
318 */
319 data->bin = StringCreateConcat(env, -1, NULL);
320 if (data->bin == NULL) {
321 wrapper_exit("%s wrapper: %s\n",
322 StringGetBuffer(data->name), strerror(errno));
323 }
324 return;
325 }
326
327 setup_ctarget_binutilsbin(data);
328
329 if (find_binutils_in_path(data))
330 return;
331
332 if (find_binutils_in_envd(data))
333 return;
334
335 /* Only our wrapper is in PATH, so
336 get the CC path using binutils-config and
337 execute the real binary in there... */
338 binpath_command = StringCreateConcat(BINUTILS_CONFIG, strlen(BINUTILS_CONFIG),
339 " --get-bin-path ", strlen(" --get-bin-path "),
340 StringGetBuffer(data->pluginIn.target.triplet),
341 StringGetLength(data->pluginIn.target.triplet),
342 NULL);
343 if (binpath_command == NULL) {
344 wrapper_exit("%s wrapper: %s\n",
345 StringGetBuffer(data->name), strerror(errno));
346 }
347 inpipe = popen(StringGetBuffer(binpath_command), "r");
348 if (inpipe == NULL) {
349 wrapper_exit("%s wrapper: could not open pipe: %s\n",
350 StringGetBuffer(data->name), strerror(errno));
351 }
352
353 if (fgets(str, MAXPATHLEN, inpipe) == 0) {
354 wrapper_exit("%s wrapper: could not get linker binary path: %s\n",
355 StringGetBuffer(data->name), strerror(errno));
356 }
357
358 data->bin = StringCreateConcat(str, -1
359 , "/", 1
360 , StringGetBuffer(data->name), StringGetLength(data->name)
361 , NULL);
362
363 pclose(inpipe);
364 }
365
366 static inline void abspath(char * const path, int * const plen)
367 {
368 char *pos;
369 char *current;
370 char *end;
371 int drop;
372 int last = *plen;
373
374 /* drop double "//" */
375 current = path;
376 while((pos = strstr(current, "//")) != NULL) {
377 for(end = ++pos; *end == '/' && *end != '\0'; ++end);
378 drop = end - pos;
379 memmove(pos, end, *plen - (end - path) + 1);
380 *plen -= drop;
381 current = pos;
382 }
383
384 /* drop "/." */
385 current = path;
386 while((pos = strstr(current, "/.")) != NULL) {
387 end = pos + 2;
388 if (*end != '\0' && *end != '/') {
389 /* is not pure "/." */
390 current = end;
391 continue;
392 }
393 if (pos == path && *end == '\0') {
394 /* keep leading slash, if any */
395 ++pos;
396 }
397 drop = end - pos;
398 memmove(pos, end, *plen - (end - path) + 1);
399 *plen -= drop;
400 current = pos;
401 }
402
403 /* drop "/previous/.." */
404 current = path;
405 while((pos = strstr(current, "/..")) != NULL) {
406 end = pos + 3;
407 if (*end != '\0' && *end != '/') {
408 current = end;
409 continue;
410 }
411 current = pos;
412 /* find previous "/" */
413 while(--current >= path && *current != '/');
414 if (strncmp(current+1, "../", 3) == 0) {
415 /* keep leading "../", or it would have been dropped */
416 current = end;
417 continue;
418 }
419 if (current < path) {
420 /* there is no leading slash */
421 ++current;
422 if (pos > current) {
423 /* this is not leading "/.." */
424 if (*end == '\0') {
425 /* keep at least one ".", take the one at the end */
426 --end;
427 } else {
428 /* do not add a leading slash */
429 ++end;
430 }
431 } else {
432 /* keep leading slash */
433 ++current;
434 }
435 }
436 if (current >= end) {
437 /* nothing to drop */
438 current = end;
439 continue;
440 }
441 drop = end - current;
442 memmove(current, end, *plen - (end - path) + 1);
443 *plen -= drop;
444 }
445
446 if (strncmp(path, "./", 2) == 0 && *plen > 2) {
447 /* drop leading "./" if not alone */
448 memmove(path, path+2, *plen - 2 + 1);
449 *plen -= 2;
450 }
451 if (*plen > 1 && path[*plen-1] == '/') {
452 /* drop trailing "/" if not alone */
453 path[--*plen] = '\0';
454 }
455 return;
456 }
457
458 static inline int filterSysLibpath(LdPluginData* pluginData)
459 {
460 int argc;
461 String const *argString;
462 char const *argBuffer;
463 int argLength;
464 char *abspathBuffer;
465 int abspathLength;
466
467 for(argc = 1; argc < StringListGetSize(pluginData->in->argList); argc++) {
468 argString = StringListGetString(pluginData->in->argList, argc);
469 argBuffer = StringGetBuffer(argString);
470 argLength = StringGetLength(argString);
471
472 if (strncmp(argBuffer, "-L", 2) == 0) {
473 argBuffer += 2;
474 argLength -= 2;
475
476 if (*argBuffer == 0) {
477 if (argc+1 == StringListGetSize(pluginData->in->argList)) {
478 /* no more arguments */
479 continue;
480 }
481 argString = StringListGetString(pluginData->in->argList, ++argc);
482 argBuffer = StringGetBuffer(argString);
483 argLength = StringGetLength(argString);
484 }
485
486 /* need a dup to be changed by abspathpath() */
487 abspathBuffer = malloc(argLength+1);
488 if (abspathBuffer == NULL) {
489 break;
490 }
491 memcpy(abspathBuffer, argBuffer, argLength+1);
492 abspathLength = argLength;
493
494 abspath(abspathBuffer, &abspathLength);
495
496 /* add to user libpath list */
497 if (StringListAppendConcat(pluginData->in->userLibpath, argBuffer, argLength, NULL) < 0)
498 break;
499
500 /* keep user libpath on commandline */
501 if (StringListAppendConcat(pluginData->out->argList, "-L", 2, argBuffer, argLength, NULL) < 0)
502 break;
503
504 /* end -L handling */
505 continue;
506 }
507
508 /* keep other arguments on commandline */
509 if (StringListAppendString(pluginData->out->argList, argString) < 0)
510 break;
511 }
512
513 if (argc < StringListGetSize(pluginData->in->argList)) {
514 return -1;
515 }
516
517 return 0;
518 }
519
520 typedef enum _AddLibpathType {
521 AddLibpath,
522 TestAndAddLibpath,
523 TestLibpath
524 } AddLibpathType;
525
526 static inline int add_libpath(LdWrapperData* data, StringList* list, AddLibpathType type,
527 char const *diagnostics,
528 char const *path, int len,
529 ...)
530 {
531 va_list args;
532 int rv = 1;
533 String* tmp;
534 struct stat statbuf;
535
536 va_start(args, len);
537 tmp = StringCreateVaConcat(path, len, args);
538 va_end(args);
539 if (tmp == NULL) {
540 wrapper_exit("%s wrapper: %s: %s\n",
541 StringGetBuffer(data->name), diagnostics, strerror(errno));
542 }
543
544 switch(type) {
545 case TestAndAddLibpath:
546 case TestLibpath:
547 if (stat(StringGetBuffer(tmp), &statbuf) != 0 || !(statbuf.st_mode & S_IFDIR)) {
548 rv = 0;
549 }
550 break;
551 default:
552 break;
553 }
554 switch(type) {
555 case AddLibpath:
556 case TestAndAddLibpath:
557 if (rv && StringListAppendString(list, tmp) < 0) {
558 wrapper_exit("%s wrapper: %s: %s\n",
559 StringGetBuffer(data->name), diagnostics, strerror(errno));
560 }
561 break;
562 default:
563 break;
564 }
565 if (rv == 0) {
566 dprintf(stderr, "%s wrapper: %s: '%s': skipped.\n",
567 StringGetBuffer(data->name), diagnostics, StringGetBuffer(tmp));
568 } else {
569 dprintf(stderr, "%s wrapper: %s: '%s': done.\n",
570 StringGetBuffer(data->name), diagnostics, StringGetBuffer(tmp));
571 }
572 tmp = StringDestroy(tmp);
573 return rv;
574 }
575
576 /* Append target's toolchain to runpath.
577 * This needs to be done when whe do
578 * cross-prefix or cross-triplet.
579 */
580 static inline void add_target_toolchain_runpath(LdWrapperData* data)
581 {
582 if (data->pluginIn.isCrossTriplet
583 || data->pluginIn.isCrossEprefix
584 ) {
585 add_libpath(data, data->pluginIn.sysRunpath, TestAndAddLibpath,
586 "append target toolchain to runpath",
587 StringGetBuffer(data->pluginIn.target.eprefix),
588 StringGetLength(data->pluginIn.target.eprefix),
589 "/usr/", strlen("/usr/"),
590 StringGetBuffer(data->pluginIn.target.triplet),
591 StringGetLength(data->pluginIn.target.triplet),
592 "/lib/gcc", strlen("/lib/gcc"),
593 NULL);
594 add_libpath(data, data->pluginIn.sysRunpath, AddLibpath,
595 "append target toolchain to runpath",
596 StringGetBuffer(data->pluginIn.target.eprefix),
597 StringGetLength(data->pluginIn.target.eprefix),
598 "/usr/", strlen("/usr/"),
599 StringGetBuffer(data->pluginIn.target.triplet),
600 StringGetLength(data->pluginIn.target.triplet),
601 "/lib", strlen("/lib"),
602 NULL);
603 }
604 }
605
606 static inline void add_target_toolchain_libpath(LdWrapperData* data)
607 {
608 }
609
610 /* Append host's cross-toolchain to libpath.
611 * This needs to be done when we do
612 * cross-triplet only.
613 */
614 static inline void add_cross_toolchain_runpath(LdWrapperData* data)
615 {
616 }
617
618 static inline void add_cross_toolchain_libpath(LdWrapperData* data)
619 {
620 if (data->pluginIn.isCrossTriplet) {
621 add_libpath(data, data->pluginIn.sysLibpath, AddLibpath,
622 "append cross toolchain to libpath",
623 StringGetBuffer(data->pluginIn.host.eprefix),
624 StringGetLength(data->pluginIn.host.eprefix),
625 "/usr/", strlen("/usr/"),
626 StringGetBuffer(data->pluginIn.host.triplet),
627 StringGetLength(data->pluginIn.host.triplet),
628 "/", strlen("/"),
629 StringGetBuffer(data->pluginIn.target.triplet),
630 StringGetLength(data->pluginIn.target.triplet),
631 "/lib/gcc", strlen("/lib/gcc"),
632 NULL);
633 add_libpath(data, data->pluginIn.sysLibpath, AddLibpath,
634 "append cross toolchain to libpath",
635 StringGetBuffer(data->pluginIn.host.eprefix),
636 StringGetLength(data->pluginIn.host.eprefix),
637 "/usr/", strlen("/usr/"),
638 StringGetBuffer(data->pluginIn.host.triplet),
639 StringGetLength(data->pluginIn.host.triplet),
640 "/", strlen("/"),
641 StringGetBuffer(data->pluginIn.target.triplet),
642 StringGetLength(data->pluginIn.target.triplet),
643 "/lib", strlen("/lib"),
644 NULL);
645 }
646 }
647
648 /* Append host's toolchain.
649 * This only needs to be done when we do a native triplet build.
650 *
651 * Add to libpath always.
652 *
653 * Add to runpath only if this is a native prefix build,
654 * or we are not using ROOT, as the target binary should be able
655 * to run even if there are dependencies missing in target eprefix,
656 * as during bootstrap.
657 */
658 static inline void add_host_toolchain_runpath(LdWrapperData* data)
659 {
660 if (data->pluginIn.isCrossTriplet) {
661 return;
662 }
663
664 if (! data->pluginIn.haveRoot
665 || ! data->pluginIn.isCrossEprefix
666 ) {
667 add_libpath(data, data->pluginIn.sysRunpath, AddLibpath,
668 "append host toolchain to runpath",
669 StringGetBuffer(data->pluginIn.host.eprefix),
670 StringGetLength(data->pluginIn.host.eprefix),
671 "/usr/", strlen("/usr/"),
672 StringGetBuffer(data->pluginIn.host.triplet),
673 StringGetLength(data->pluginIn.host.triplet),
674 "/lib/gcc", strlen("/lib/gcc"),
675 NULL);
676 add_libpath(data, data->pluginIn.sysRunpath, AddLibpath,
677 "append host toolchain to runpath",
678 StringGetBuffer(data->pluginIn.host.eprefix),
679 StringGetLength(data->pluginIn.host.eprefix),
680 "/usr/", strlen("/usr/"),
681 StringGetBuffer(data->pluginIn.host.triplet),
682 StringGetLength(data->pluginIn.host.triplet),
683 "/lib", strlen("/lib"),
684 NULL);
685 }
686 }
687
688 static inline void add_host_toolchain_libpath(LdWrapperData* data)
689 {
690 if (data->pluginIn.isCrossTriplet) {
691 return;
692 }
693
694 add_libpath(data, data->pluginIn.sysLibpath, TestAndAddLibpath,
695 "append host toolchain to libpath",
696 StringGetBuffer(data->pluginIn.host.eprefix),
697 StringGetLength(data->pluginIn.host.eprefix),
698 "/usr/", strlen("/usr/"),
699 StringGetBuffer(data->pluginIn.host.triplet),
700 StringGetLength(data->pluginIn.host.triplet),
701 "/lib/gcc", strlen("/lib/gcc"),
702 NULL);
703 add_libpath(data, data->pluginIn.sysLibpath, AddLibpath,
704 "append host toolchain to libpath",
705 StringGetBuffer(data->pluginIn.host.eprefix),
706 StringGetLength(data->pluginIn.host.eprefix),
707 "/usr/", strlen("/usr/"),
708 StringGetBuffer(data->pluginIn.host.triplet),
709 StringGetLength(data->pluginIn.host.triplet),
710 "/lib", strlen("/lib"),
711 NULL);
712 }
713
714 /* Append target system to runpath.
715 *
716 * As they are not read from any target config file, we can check them
717 * for existance, as ${ROOT}${EPREFIX} really should be accessible
718 * from this cross-compiling host.
719 *
720 * This only needs to be done if we do
721 * cross-eprefix or use ROOT.
722 */
723 static inline void add_target_system(LdWrapperData* data)
724 {
725 struct libdir {
726 char const *path; int len;
727 };
728 struct libdir const libdirs[] = {
729 { "/usr/lib", strlen("/usr/lib"), },
730 { "/lib", strlen("/lib"), },
731 { NULL, -1 },
732 };
733 struct libdir const * l = libdirs;
734
735 if (data->pluginIn.isCrossEprefix
736 || data->pluginIn.haveRoot /* cross-triplet must use ROOT */
737 ) {
738 while(l->path != NULL) {
739 if (add_libpath(data, data->pluginIn.sysLibpath, TestAndAddLibpath,
740 "append target system to libpath",
741 StringGetBuffer(data->pluginIn.root),
742 StringGetLength(data->pluginIn.root),
743 StringGetBuffer(data->pluginIn.target.eprefix),
744 StringGetLength(data->pluginIn.target.eprefix),
745 l->path, l->len,
746 NULL)
747 ) {
748 add_libpath(data, data->pluginIn.sysRunpath, AddLibpath,
749 "append target system to runpath",
750 StringGetBuffer(data->pluginIn.target.eprefix),
751 StringGetLength(data->pluginIn.target.eprefix),
752 l->path, l->len,
753 NULL);
754 }
755 l++;
756 }
757 }
758 }
759
760 /* Append host system.
761 *
762 * This needs to be done when we do
763 * |cross-triplet | cross-eprefix | use ROOT |
764 * -------------+--------------+---------------+----------+
765 * cross-triplet| --- | --- | --- |
766 * cross-eprefix| --- | l r | l |
767 * use ROOT | --- | l | l r |
768 * -------------+--------------+---------------+----------+
769 * eprefix, or cross-
770 * *) this is a native build,
771 * *) this is cross-prefix or we have ROOT
772 *
773 * additionally, append the system libdirs from this host to runpath when
774 *
775 * *) this is a cross eprefix build and we do not have ROOT,
776 * because it is likely that the created binaries are executed from the
777 * new prefix, while still can use dependent libs from the old prefix.
778 */
779 static inline void add_host_system(LdWrapperData* data)
780 {
781 struct libdir {
782 char const *path; int len; int exists;
783 };
784 struct libdir libdirs[] = {
785 { "/usr/lib", strlen("/usr/lib"), 0, },
786 { "/lib", strlen("/lib"), 0, },
787 { NULL, -1, 0, },
788 };
789 struct libdir * l = libdirs;
790
791 if (data->pluginIn.isCrossTriplet) {
792 /* native builds only */
793 return;
794 }
795
796 while(l->path != NULL) {
797 if (add_libpath(data, data->pluginIn.sysLibpath, TestAndAddLibpath,
798 "append host system to libpath",
799 StringGetBuffer(data->pluginIn.host.eprefix),
800 StringGetLength(data->pluginIn.host.eprefix),
801 l->path, l->len,
802 NULL)
803 && (data->pluginIn.isCrossEprefix
804 || ! data->pluginIn.haveRoot
805 )
806 ) {
807 l->exists = 1;
808 }
809 l++;
810 }
811
812 /* Add to runpath in reverse order: This is to replace existing shared
813 * libraries without SONAME on AIX with ones that define a SONAME.
814 * The old one can be found as lib/libz.so fex, while linking
815 * against usr/lib/libz.so will record libz.so.1 into the binaries.
816 */
817 while(--l >= libdirs) {
818 if (l->exists) {
819 /* add to runpath only when cross-prefix without ROOT */
820 add_libpath(data, data->pluginIn.sysRunpath, AddLibpath,
821 "append host system to runpath",
822 StringGetBuffer(data->pluginIn.host.eprefix),
823 StringGetLength(data->pluginIn.host.eprefix),
824 l->path, l->len,
825 NULL);
826 }
827 }
828 }
829
830 static inline void callPlugin(LdWrapperData* data, LdPluginFct plugins)
831 {
832 LdPluginData pluginData = {0};
833 LdPluginOut pluginOut = {0};
834
835 pluginData.in = &data->pluginIn;
836 pluginData.out = &pluginOut;
837 pluginData.plugin = *plugins;
838
839 /* keep argv[0] */
840 pluginData.out->argList = StringListCreate(pluginData.in->argList, 0, 1);
841 if (pluginData.out->argList == NULL) {
842 wrapper_exit("%s wrapper: %s\n",
843 StringGetBuffer(data->name), strerror(errno));
844 }
845
846 if ((*plugins)(&pluginData) < 0) {
847 if (pluginData.out->diagnostics == NULL) {
848 wrapper_exit("%s wrapper: %s: %s\n",
849 StringGetBuffer(data->name), pluginData.out->diagnostics, strerror(errno));
850 } else {
851 wrapper_exit("%s wrapper could not run plugin: %s\n",
852 StringGetBuffer(data->name), strerror(errno));
853 }
854 }
855 if (pluginOut.argList != NULL) {
856 StringListDestroy(data->pluginIn.argList);
857 data->pluginIn.argList = pluginOut.argList;
858 }
859 }
860
861 typedef struct _KnownPlugin {
862 int namelen;
863 char const *name;
864 LdPluginFct plugin;
865 } KnownPlugin;
866
867 static inline int compareKnownPluginName(void const *v1, void const *v2)
868 {
869 KnownPlugin const* p1 = (KnownPlugin const*)v1;
870 KnownPlugin const* p2 = (KnownPlugin const*)v2;
871 int rv;
872 rv = p1->namelen - p2->namelen;
873 if (rv) return rv;
874 return strncmp(p1->name, p2->name, p1->namelen);
875 }
876
877 /* call the plugins from comma-separated list of plugin-names */
878 static inline void callPlugins(LdWrapperData* data, char const* plugins)
879 {
880 char const *end;
881 static KnownPlugin const knownPlugins[] = {
882 /* keep sorted on namelen,name */
883 { 3, "aix", aixplugin },
884 { 3, "gnu", gnuplugin },
885 { 4, "hpux", hpuxplugin },
886 { 6, "darwin", darwinplugin },
887 { 7, "solaris", solarisplugin },
888 };
889 KnownPlugin search;
890 KnownPlugin *found;
891
892 if (plugins == NULL) {
893 return;
894 }
895
896 while(plugins != NULL && *plugins != '\0') {
897 end = strchr(plugins, ',');
898 if (end == NULL) {
899 end = plugins + strlen(plugins);
900 }
901 search.name = plugins;
902 search.namelen = end - plugins;
903 found = bsearch(&search, knownPlugins,
904 sizeof(knownPlugins) / sizeof(knownPlugins[0]),
905 sizeof(knownPlugins[0]),
906 compareKnownPluginName);
907 if (found != NULL) {
908 callPlugin(data, found->plugin);
909 }
910 while (*end == ',') end++;
911 plugins = end;
912 }
913
914 return;
915 }
916
917 int main(int argc, char *argv[])
918 {
919 String *tmpString = NULL;
920 LdWrapperData data;
921 int len;
922 char **newargv = argv;
923 char const *found;
924 char const *tmp;
925
926 memset(&data, 0, sizeof(data));
927
928 dprintf(stderr, "ld-wrapper called as: %s\n", argv[0]);
929
930 /* What should we find? */
931 tmp = basename(argv[0]);
932 found = strrchr(tmp, '-');
933 if (found != NULL) {
934 found++;
935 } else {
936 found = tmp;
937 }
938 data.name = StringCreateConcat(found, -1, NULL);
939 if (data.name == NULL) {
940 wrapper_exit("%s wrapper: %s\n", argv[0], strerror(errno));
941 }
942
943 found = getenv("PATH");
944 if (found) {
945 data.envpath = StringListFromSeparated(found, -1, ":", 1);
946 if (data.envpath == NULL) {
947 wrapper_exit("%s wrapper: %s\n",
948 StringGetBuffer(data.name), strerror(errno));
949 }
950 }
951
952 /* builtins */
953 data.pluginIn.host.triplet = StringCreateConcat(CHOST, strlen(CHOST), NULL);
954 if (data.pluginIn.host.triplet == NULL) {
955 wrapper_exit("%s wrapper: %s\n",
956 StringGetBuffer(data.name), strerror(errno));
957 }
958
959 data.pluginIn.host.eprefix = StringCreateConcat(
960 GENTOO_PORTAGE_EPREFIX, strlen(GENTOO_PORTAGE_EPREFIX),
961 NULL);
962 if (data.pluginIn.host.eprefix == NULL) {
963 wrapper_exit("%s wrapper: %s\n",
964 StringGetBuffer(data.name), strerror(errno));
965 }
966
967 if (stat(argv[0], &data.arg0stat) != 0) {
968 tmpString = StringCreateConcat(
969 StringGetBuffer(data.pluginIn.host.eprefix),
970 StringGetLength(data.pluginIn.host.eprefix),
971 "/usr/bin/", strlen("/usr/bin/"),
972 StringGetBuffer(data.name), StringGetLength(data.name),
973 NULL);
974 if (tmpString == NULL) {
975 wrapper_exit("%s wrapper: %s\n",
976 StringGetBuffer(data.name), strerror(errno));
977 }
978 if (stat(StringGetBuffer(tmpString), &data.arg0stat) != 0) {
979 wrapper_exit("%s wrapper: \"%s\": %s\n",
980 StringGetBuffer(data.name),
981 StringGetBuffer(tmpString),
982 strerror(errno));
983 }
984 }
985
986 /* environments with fallbacks to builtins */
987 found = getenv("ROOT");
988 if (!found) {
989 found = "/";
990 }
991 len = strlen(found);
992 while (len > 0 && found[len-1] == '/')
993 len--;
994 data.pluginIn.root = StringCreateConcat(found, len, NULL);
995 if (data.pluginIn.root == NULL) {
996 wrapper_exit("%s wrapper: %s\n",
997 StringGetBuffer(data.name), strerror(errno));
998 }
999 data.pluginIn.haveRoot = StringGetLength(data.pluginIn.root) > 0 ? 1 : 0;
1000
1001 found = getenv("EPREFIX");
1002 if (found && !StringIsEqual(data.pluginIn.host.eprefix, 0, found, -1)) {
1003 data.pluginIn.target.eprefix = StringCreateConcat(found, -1, NULL);
1004 data.pluginIn.isCrossEprefix = 1;
1005 } else {
1006 data.pluginIn.target.eprefix = StringDup(data.pluginIn.host.eprefix);
1007 data.pluginIn.isCrossEprefix = 0;
1008 }
1009 if (data.pluginIn.target.eprefix == NULL) {
1010 wrapper_exit("%s wrapper: %s\n",
1011 StringGetBuffer(data.name), strerror(errno));
1012 }
1013
1014 found = getenv("BINUTILS_CONFIG_LDTARGET");
1015 if (found == NULL) {
1016 found = CTARGET();
1017 }
1018 data.pluginIn.target.triplet = StringCreateConcat(found, -1, NULL);
1019 if (data.pluginIn.target.triplet == NULL) {
1020 wrapper_exit("%s wrapper: %s\n",
1021 StringGetBuffer(data.name), strerror(errno));
1022 }
1023
1024 dprintf(stderr, "%s wrapper: chost '%s'\n",
1025 StringGetBuffer(data.name), StringGetBuffer(data.pluginIn.host.triplet));
1026 dprintf(stderr, "%s wrapper: ctarget '%s'\n",
1027 StringGetBuffer(data.name), StringGetBuffer(data.pluginIn.target.triplet));
1028 dprintf(stderr, "%s wrapper: host eprefix '%s'\n",
1029 StringGetBuffer(data.name), StringGetBuffer(data.pluginIn.host.eprefix));
1030 dprintf(stderr, "%s wrapper: target eprefix '%s'\n",
1031 StringGetBuffer(data.name), StringGetBuffer(data.pluginIn.target.eprefix));
1032
1033 data.pluginIn.isCrossTriplet = StringIsEqualString(
1034 data.pluginIn.host.triplet, data.pluginIn.target.triplet
1035 ) ? 0 : 1;
1036
1037 find_wrapper_binutils(&data);
1038
1039 if (data.envpath) {
1040 data.envpath = StringListDestroy(data.envpath);
1041 }
1042
1043 data.pluginIn.argList = StringListFromArgv(argc, argv);
1044 if (data.pluginIn.argList == NULL) {
1045 wrapper_exit("%s wrapper: %s\n",
1046 StringGetBuffer(data.name), strerror(errno));
1047 }
1048
1049 data.pluginIn.userLibpath = StringListCreate(NULL, 0, 0);
1050 if (data.pluginIn.userLibpath == NULL) {
1051 wrapper_exit("cannot create user libpath list: %s\n", strerror(errno));
1052 }
1053
1054 data.pluginIn.sysLibpath = StringListCreate(NULL, 0, 0);
1055 if (data.pluginIn.sysLibpath == NULL) {
1056 wrapper_exit("cannot create sys libpath list: %s\n", strerror(errno));
1057 }
1058
1059 data.pluginIn.sysRunpath = StringListCreate(NULL, 0, 0);
1060 if (data.pluginIn.sysRunpath == NULL) {
1061 wrapper_exit("cannot create sys runpath list: %s\n", strerror(errno));
1062 }
1063
1064 add_target_toolchain_libpath(&data);
1065 add_cross_toolchain_libpath(&data);
1066 add_host_toolchain_libpath(&data);
1067
1068 add_target_toolchain_runpath(&data);
1069 add_cross_toolchain_runpath(&data);
1070
1071 add_target_system(&data);
1072
1073 add_host_toolchain_runpath(&data);
1074 add_host_system(&data);
1075
1076 /* filter out sys libpath's passed with "-L" */
1077 callPlugin(&data, filterSysLibpath);
1078
1079 found = getenv("BINUTILS_CONFIG_LDPLUGINS");
1080 if (found == NULL) {
1081 found = LDPLUGINS();
1082 }
1083 /* call the target specific plugin */
1084 callPlugins(&data, found);
1085
1086 newargv = StringListToArgv(data.pluginIn.argList);
1087 if (newargv == NULL) {
1088 wrapper_exit("cannot create argument array: %s\n", strerror(errno));
1089 }
1090
1091 if (DEBUG() || getenv("BINUTILS_CONFIG_VERBOSE") != NULL) {
1092 int i;
1093 fprintf(stderr, "'%s'", StringGetBuffer(data.bin));
1094 for (i = 0; newargv[i] != NULL; i++) {
1095 fprintf(stderr, " \\\n '%s'", newargv[i]);
1096 }
1097 fprintf(stderr, "\n");
1098 }
1099
1100 /* Ok, lets do it one more time ... */
1101 if (execv(StringGetBuffer(data.bin), newargv) < 0)
1102 wrapper_exit("Could not run/locate \"%s/%s\" (%s)\n",
1103 StringGetBuffer(data.pluginIn.target.triplet),
1104 StringGetBuffer(data.name),
1105 StringGetBuffer(data.bin));
1106
1107 return 0;
1108 }

Properties

Name Value
svn:executable

  ViewVC Help
Powered by ViewVC 1.1.20