197
197
main (int argc , char * argv [])
198
198
{
199
199
int newargc = 0 ;
200
+ int rpathcnt = 0 ;
200
201
char * * newargv = NULL ;
202
+ char * * rpaths = NULL ;
203
+ char * * lpaths = NULL ;
201
204
char * wrapper = argv [0 ];
202
205
char * wrapperctarget = NULL ;
203
206
char verbose = getenv ("BINUTILS_CONFIG_VERBOSE" ) != NULL ;
@@ -214,7 +217,6 @@ main(int argc, char *argv[])
214
217
size_t len ;
215
218
int i ;
216
219
int j ;
217
- int k ;
218
220
DIR * dirp ;
219
221
struct dirent * dp ;
220
222
@@ -287,10 +289,12 @@ main(int argc, char *argv[])
287
289
/* walk over the arguments to see if there's anything interesting
288
290
* for us and calculate the final number of arguments */
289
291
for (i = 1 ; i < argc ; i ++ ) {
290
- /* -L: account space for the matching -R */
291
292
if (argv [i ][0 ] == '-' ) {
293
+ /* -L: account space for the matching -R */
292
294
if (argv [i ][1 ] == 'L' )
293
295
newargc ++ ;
296
+ if (argv [i ][1 ] == 'R' || strcmp (argv [i ], "-rpath" ) == 0 )
297
+ rpathcnt ++ ;
294
298
if (argv [i ][1 ] == 'v' || argv [i ][1 ] == 'V' )
295
299
verbose = 1 ;
296
300
if ((strcmp (argv [i ], "-macosx_version_min" ) == 0 ||
@@ -316,8 +320,6 @@ main(int argc, char *argv[])
316
320
darwin_dt_ver += (int )strtol (p + 1 , & p , 10 );
317
321
}
318
322
319
- /* Note: Code below assumes that newargc is the count of -L arguments. */
320
-
321
323
/* If a package being cross-compiled injects standard directories, it's
322
324
* non-cross-compilable on any platform, prefix or no prefix. So no
323
325
* need to add PREFIX- or CTARGET-aware libdirs. */
@@ -341,13 +343,15 @@ main(int argc, char *argv[])
341
343
* -rpath and the path itself */
342
344
newargc *= 2 ;
343
345
344
- /* and we will be adding two for the each of
345
- * the two system paths as well */
346
- newargc += 4 ;
346
+ /* PREFIX rpaths */
347
+ newargc += 2 * 2 ;
347
348
}
348
349
349
- /* add the 2 prefix paths (-L) and -search_paths_first */
350
- newargc += 2 + 1 ;
350
+ /* PREFIX paths */
351
+ newargc += 3 ;
352
+
353
+ /* add -search_paths_first */
354
+ newargc += 1 ;
351
355
352
356
/* add -syslibroot <path> -platform_version macos <ver> 0.0 */
353
357
newargc += 6 ;
@@ -357,6 +361,27 @@ main(int argc, char *argv[])
357
361
}
358
362
}
359
363
364
+ /* Note: Code below assumes that newargc is the count of -L arguments. */
365
+
366
+ /* allocate space for -L lookups/uniqueifying */
367
+ lpaths = malloc (sizeof (lpaths [0 ]) * (newargc + 1 ));
368
+ if (lpaths == NULL ) {
369
+ fprintf (stderr , "%s: failed to allocate memory for new arguments\n" ,
370
+ wrapper );
371
+ exit (1 );
372
+ }
373
+ lpaths [0 ] = NULL ;
374
+
375
+ if (!is_darwin || darwin_use_rpath ) {
376
+ rpaths = malloc (sizeof (rpaths [0 ]) * (rpathcnt + 1 ));
377
+ if (rpaths == NULL ) {
378
+ fprintf (stderr , "%s: failed to allocate memory for new arguments\n" ,
379
+ wrapper );
380
+ exit (1 );
381
+ }
382
+ rpaths [0 ] = NULL ;
383
+ }
384
+
360
385
/* account the original arguments */
361
386
newargc += argc ;
362
387
/* we always add a sentinel */
@@ -476,8 +501,6 @@ main(int argc, char *argv[])
476
501
newargv [j ++ ] = "-search_paths_first" ;
477
502
}
478
503
479
- /* position k right after the original arguments */
480
- k = j - 1 + argc ;
481
504
for (i = 1 ; i < argc ; i ++ , j ++ ) {
482
505
if (is_darwin ) {
483
506
/* skip platform version stuff, we already pushed it out */
@@ -486,15 +509,13 @@ main(int argc, char *argv[])
486
509
{
487
510
i ++ ;
488
511
j -- ;
489
- k -= 2 ;
490
512
continue ;
491
513
}
492
514
if (strcmp (argv [i ], "-platform_version" ) == 0 &&
493
515
i < argc - 3 && strcmp (argv [i + 1 ], "macos" ) == 0 )
494
516
{
495
517
i += 3 ;
496
518
j -- ;
497
- k -= 4 ;
498
519
continue ;
499
520
}
500
521
}
@@ -504,10 +525,12 @@ main(int argc, char *argv[])
504
525
if (is_cross || (is_darwin && !darwin_use_rpath ))
505
526
continue ;
506
527
507
- /* on ELF targets we add runpaths for all found search paths */
508
- if (argv [i ][0 ] == '-' && argv [i ][1 ] == 'L' ) {
528
+ /* on ELF/Mach-O targets we add runpaths for all found search paths */
529
+ if (argv [i ][0 ] == '-' && ( argv [i ][1 ] == 'L' || argv [ i ][ 1 ] == 'R' ) ) {
509
530
char * path ;
510
- size_t sze ;
531
+ int pth ;
532
+ char duplicate ;
533
+ int before = j - 1 ;
511
534
512
535
/* arguments can be in many ways here:
513
536
* -L<path>
@@ -533,50 +556,129 @@ main(int argc, char *argv[])
533
556
if (builddir != NULL && strncmp (builddir , path , len ) == 0 )
534
557
continue ;
535
558
536
- if (is_darwin ) {
537
- newargv [k ] = "-rpath" ;
538
- newargv [++ k ] = path ;
539
- } else {
540
- sze = 2 + strlen (path ) + 1 ;
541
- newargv [k ] = malloc (sizeof (char ) * sze );
542
- if (newargv [k ] == NULL ) {
543
- fprintf (stderr , "%s: failed to allocate memory for "
544
- "'%s' -R argument\n" , wrapper , argv [i ]);
545
- exit (1 );
559
+ /* loop-search for this path, if it was emitted already,
560
+ * suppress it -- this is not just some fancy beautification!
561
+ * CLT15.3 on macOS warns about duplicate paths, and
562
+ * any project that triggers on these warnings causes
563
+ * problems, such as Ruby claiming the linker is broken */
564
+ duplicate = 0 ;
565
+ if (argv [i ][1 ] == 'L' ) {
566
+ for (pth = 0 ; lpaths [pth ] != NULL ; pth ++ ) {
567
+ if (strcmp (lpaths [pth ], path ) == 0 ) {
568
+ duplicate = 1 ;
569
+ break ;
570
+ }
546
571
}
547
-
548
- snprintf (newargv [k ], sze , "-R%s" , path );
572
+ if (duplicate ) {
573
+ j = before ;
574
+ continue ;
575
+ }
576
+ /* record path */
577
+ lpaths [pth ++ ] = path ;
578
+ lpaths [pth ] = NULL ;
579
+ } else if (!is_darwin || darwin_use_rpath ) {
580
+ for (pth = 0 ; rpaths [pth ] != NULL ; pth ++ ) {
581
+ if (strcmp (rpaths [pth ], path ) == 0 ) {
582
+ duplicate = 1 ;
583
+ break ;
584
+ }
585
+ }
586
+ if (duplicate ) {
587
+ j = before ;
588
+ continue ;
589
+ }
590
+ /* record path */
591
+ rpaths [pth ++ ] = path ;
592
+ rpaths [pth ] = NULL ;
549
593
}
594
+ } else if ((!is_darwin || darwin_use_rpath ) &&
595
+ strcmp (argv [i ], "-rpath" ) == 0 )
596
+ {
597
+ char * path ;
598
+ int pth ;
599
+ char duplicate ;
550
600
551
- k ++ ;
601
+ path = argv [i + 1 ];
602
+ while (* path != '\0' && isspace (* path ))
603
+ path ++ ;
604
+ /* not absolute (or empty)?!? skip */
605
+ if (* path != '/' )
606
+ continue ;
607
+
608
+ /* does it refer to the build directory? skip */
609
+ if (builddir != NULL && strncmp (builddir , path , len ) == 0 )
610
+ continue ;
611
+
612
+ duplicate = 0 ;
613
+ for (pth = 0 ; rpaths [pth ] != NULL ; pth ++ ) {
614
+ if (strcmp (rpaths [pth ], path ) == 0 ) {
615
+ duplicate = 1 ;
616
+ break ;
617
+ }
618
+ }
619
+ if (duplicate ) {
620
+ j -= 2 ;
621
+ continue ;
622
+ }
623
+ /* record path */
624
+ rpaths [pth ++ ] = path ;
625
+ rpaths [pth ] = NULL ;
552
626
}
553
627
}
554
628
/* add the custom paths */
555
629
if (!is_cross ) {
630
+ int pth ;
631
+ #define path_not_exists (W ,P ) \
632
+ for (pth = 0; W[pth] != NULL; pth++) { \
633
+ if (strcmp(W[pth], P) == 0) \
634
+ break; \
635
+ } \
636
+ if (W[pth] == NULL)
637
+ #define add_path (P ) \
638
+ path_not_exists(lpaths, P) newargv[j++] = "-L" P
639
+ #define add_path_rpath (P ) \
640
+ path_not_exists(lpaths, P) { \
641
+ lpaths[pth++] = P; \
642
+ lpaths[pth] = NULL; \
643
+ newargv[j++] = "-L" P; \
644
+ }
645
+
556
646
if (is_darwin ) {
557
647
/* FIXME: no support for cross-compiling *to* Darwin */
558
- newargv [k ++ ] = "-L" EPREFIX "/usr/" CHOST "/lib/gcc" ;
559
- newargv [k ++ ] = "-L" EPREFIX "/usr/lib" ;
560
- newargv [k ++ ] = "-L" EPREFIX "/lib" ;
561
-
562
- if (darwin_use_rpath ) {
563
- newargv [k ++ ] = "-rpath" ;
564
- newargv [k ++ ] = EPREFIX "/usr/lib" ;
565
- newargv [k ++ ] = "-rpath" ;
566
- newargv [k ++ ] = EPREFIX "/lib" ;
567
- }
648
+ add_path (EPREFIX "/usr/" CHOST "/lib/gcc" );
649
+ add_path_rpath (EPREFIX "/usr/lib" );
650
+ add_path_rpath (EPREFIX "/lib" );
568
651
} else {
569
- newargv [k ++ ] = "-L" EPREFIX "/usr/" CHOST "/lib/gcc" ;
570
- newargv [k ++ ] = "-R" EPREFIX "/usr/" CHOST "/lib/gcc" ;
571
- newargv [k ++ ] = "-L" EPREFIX "/usr/" CHOST "/lib" ;
572
- newargv [k ++ ] = "-R" EPREFIX "/usr/" CHOST "/lib" ;
573
- newargv [k ++ ] = "-L" EPREFIX "/usr/lib" ;
574
- newargv [k ++ ] = "-R" EPREFIX "/usr/lib" ;
575
- newargv [k ++ ] = "-L" EPREFIX "/lib" ;
576
- newargv [k ++ ] = "-R" EPREFIX "/lib" ;
652
+ add_path_rpath (EPREFIX "/usr/" CHOST "/lib/gcc" );
653
+ add_path_rpath (EPREFIX "/usr/" CHOST "/lib" );
654
+ add_path_rpath (EPREFIX "/usr/lib" );
655
+ add_path_rpath (EPREFIX "/lib" );
656
+ }
657
+ }
658
+ /* add rpaths for -L entries */
659
+ if (!is_darwin || darwin_use_rpath ) {
660
+ for (i = 0 ; lpaths [i ] != NULL ; i ++ ) {
661
+ int pth ;
662
+ path_not_exists (rpaths , lpaths [i ]) {
663
+ size_t sze ;
664
+ if (is_darwin && darwin_use_rpath ) {
665
+ newargv [j ++ ] = "-rpath" ;
666
+ newargv [j ++ ] = lpaths [i ];
667
+ } else if (!is_darwin ) {
668
+ sze = 2 + strlen (lpaths [i ]) + 1 ;
669
+ newargv [j ] = malloc (sizeof (char ) * sze );
670
+ if (newargv [j ] == NULL ) {
671
+ fprintf (stderr , "%s: failed to allocate memory for "
672
+ "'%s' -R argument\n" , wrapper , argv [i ]);
673
+ exit (1 );
674
+ }
675
+
676
+ snprintf (newargv [j ++ ], sze , "-R%s" , lpaths [i ]);
677
+ }
678
+ }
577
679
}
578
680
}
579
- newargv [k ] = NULL ;
681
+ newargv [j ] = NULL ;
580
682
581
683
if (verbose ) {
582
684
fprintf (stderr , "%s: invoking %s with arguments:\n" , wrapper , ld );
0 commit comments