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

Properties

Name Value
svn:executable

  ViewVC Help
Powered by ViewVC 1.1.20