1# ex:ts=8 sw=4: 2# $OpenBSD: Link.pm,v 1.19 2012/07/13 13:25:12 espie Exp $ 3# 4# Copyright (c) 2007-2010 Steven Mestdagh <steven@openbsd.org> 5# Copyright (c) 2012 Marc Espie <espie@openbsd.org> 6# 7# Permission to use, copy, modify, and distribute this software for any 8# purpose with or without fee is hereby granted, provided that the above 9# copyright notice and this permission notice appear in all copies. 10# 11# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18use strict; 19use warnings; 20use feature qw(say); 21 22# supplement OSConfig with stuff needed. 23package LT::OSConfig; 24 25my ($search_dir_hash, $search_dir_list); 26sub fillup_search_dirs 27{ 28 return if defined $search_dir_list; 29 $search_dir_list = []; 30 $search_dir_hash = {}; 31 open(my $fh, '-|', '/sbin/ldconfig -r'); 32 if (!defined $fh) { 33 die "Can't run ldconfig\n"; 34 } 35 while (<$fh>) { 36 if (m/^\s*search directories:\s*(.*?)\s*$/o) { 37 foreach my $d (split(/\:/o, $1)) { 38 push @$search_dir_list, $d; 39 $search_dir_hash->{$d} = 1; 40 } 41 last; 42 } 43 } 44 close($fh); 45} 46 47sub search_dirs 48{ 49 my $self = shift; 50 $self->fillup_search_dirs; 51 return @$search_dir_list; 52} 53 54sub is_search_dir 55{ 56 my ($self, $dir) = @_; 57 $self->fillup_search_dirs; 58 return $search_dir_hash->{$dir}; 59} 60 61 62# let's add the libsearchdirs and -R options there 63package LT::Options; 64 65sub add_libsearchdir 66{ 67 my $self = shift; 68 push(@{$self->{libsearchdir}}, @_); 69} 70 71sub libsearchdirs 72{ 73 my $self = shift; 74 return @{$self->{libsearchdir}}; 75} 76 77# -R options originating from .la resolution 78sub add_R 79{ 80 my $self = shift; 81 push(@{$self->{Rresolved}}, @_); 82} 83 84sub Rresolved 85{ 86 my $self = shift; 87 $self->{Rresolved} //= []; 88 return @{$self->{Rresolved}}; 89} 90 91package LT::Mode::Link; 92our @ISA = qw(LT::Mode); 93 94use LT::Util; 95use LT::Trace; 96use LT::Library; 97use File::Basename; 98 99use constant { 100 OBJECT => 0, # unused ? 101 LIBRARY => 1, 102 PROGRAM => 2, 103}; 104 105sub help 106{ 107 print <<"EOH"; 108 109Usage: $0 --mode=link LINK-COMMAND ... 110Link object files and libraries into a library or a program 111EOH 112} 113 114my $shared = 0; 115my $static = 1; 116 117sub run 118{ 119 my ($class, $ltprog, $gp, $ltconfig) = @_; 120 121 my $noshared = $ltconfig->noshared; 122 my $cmd; 123 my $libdirs = []; # list of libdirs 124 my $libs = LT::Library::Stash->new; # libraries 125 my $dirs = {}; # paths to find libraries 126 # put a priority in the dir hash 127 # always look here 128 $dirs->{'/usr/lib'} = 3; 129 130 $gp->handle_permuted_options( 131 'all-static', 132 'allow-undefined', # we don't care about THAT one 133 'avoid-version', 134 'dlopen:', 135 'dlpreopen:', 136 'export-dynamic', 137 'export-symbols:', 138 'export-symbols-regex:', 139 'module', 140 'no-fast-install', 141 'no-install', 142 'no-undefined', 143 'o:!@', 144 'objectlist:', 145 'precious-files-regex:', 146 'prefer-pic', 147 'prefer-non-pic', 148 'release:', 149 'rpath:@', 150 'L:!', sub { shortdie "libtool does not allow spaces in -L dir\n"}, 151 'R:@', 152 'shrext:', 153 'static', 154 'thread-safe', # XXX and --thread-safe ? 155 'version-info:', 156 'version-number:'); 157 158 # XXX options ignored: dlopen, dlpreopen, no-fast-install, 159 # no-install, no-undefined, precious-files-regex, 160 # shrext, thread-safe, prefer-pic, prefer-non-pic 161 162 my @RPopts = $gp->rpath; # -rpath options 163 my @Ropts = $gp->R; # -R options on the command line 164 165 # add the .libs dir as well in case people try to link directly 166 # with the real library instead of the .la library 167 $gp->add_libsearchdir(LT::OSConfig->search_dirs, './.libs'); 168 169 if (!$gp->o) { 170 shortdie "No output file given.\n"; 171 } 172 if ($gp->o > 1) { 173 shortdie "Multiple output files given.\n"; 174 } 175 176 my $outfile = ($gp->o)[0]; 177 tsay {"outfile = $outfile"}; 178 my $odir = dirname($outfile); 179 my $ofile = basename($outfile); 180 181 # what are we linking? 182 my $linkmode = PROGRAM; 183 if ($ofile =~ m/\.l?a$/) { 184 $linkmode = LIBRARY; 185 $gp->handle_permuted_options('x:!'); 186 } 187 tsay {"linkmode: $linkmode"}; 188 189 # eat multiple version-info arguments, we only accept the first. 190 map { $_ = '' if ($_ =~ m/\d+:\d+:\d+/); } @ARGV; 191 192 my @objs; 193 my @sobjs; 194 if ($gp->objectlist) { 195 my $objectlist = $gp->objectlist; 196 open(my $ol, '<', $objectlist) or die "Cannot open $objectlist: $!\n"; 197 my @objlist = <$ol>; 198 for (@objlist) { chomp; } 199 generate_objlist(\@objs, \@sobjs, \@objlist); 200 } else { 201 generate_objlist(\@objs, \@sobjs, \@ARGV); 202 } 203 tsay {"objs = @objs"}; 204 tsay {"sobjs = @sobjs"}; 205 206 my $deplibs = []; # list of dependent libraries (both -L and -l flags) 207 my $parser = LT::Parser->new(\@ARGV); 208 209 if ($linkmode == PROGRAM) { 210 require LT::Mode::Link::Program; 211 my $program = LT::Program->new; 212 $program->{outfilepath} = $outfile; 213 # XXX give higher priority to dirs of not installed libs 214 if ($gp->export_dynamic) { 215 push(@{$parser->{args}}, "-Wl,-E"); 216 } 217 218 $parser->parse_linkargs1($deplibs, $gp, $dirs, $libs); 219 tsay {"end parse_linkargs1"}; 220 tsay {"deplibs = @$deplibs"}; 221 222 $program->{objlist} = \@objs; 223 if (@objs == 0) { 224 if (@sobjs > 0) { 225 tsay {"no non-pic libtool objects found, trying pic objects..."}; 226 $program->{objlist} = \@sobjs; 227 } elsif (@sobjs == 0) { 228 tsay {"no libtool objects of any kind found"}; 229 tsay {"hoping for real objects in ARGV..."}; 230 } 231 } 232 my $RPdirs = []; 233 @$RPdirs = (@Ropts, @RPopts, $gp->Rresolved); 234 $program->{RPdirs} = $RPdirs; 235 236 $program->link($ltprog, $ltconfig, $dirs, $libs, $deplibs, $libdirs, $parser, $gp); 237 } elsif ($linkmode == LIBRARY) { 238 my $convenience = 0; 239 require LT::Mode::Link::Library; 240 my $lainfo = LT::LaFile->new; 241 242 $shared = 1 if ($gp->version_info || 243 $gp->avoid_version || 244 $gp->module); 245 if (!@RPopts) { 246 $convenience = 1; 247 $noshared = 1; 248 $static = 1; 249 $shared = 0; 250 } else { 251 $shared = 1; 252 } 253 if ($ofile =~ m/\.a$/ && !$convenience) { 254 $ofile =~ s/\.a$/.la/; 255 $outfile =~ s/\.a$/.la/; 256 } 257 (my $libname = $ofile) =~ s/\.l?a$//; # remove extension 258 my $staticlib = $libname.'.a'; 259 my $sharedlib = $libname.'.so'; 260 my $sharedlib_symlink; 261 262 if ($gp->static || $gp->all_static) { 263 $shared = 0; 264 $static = 1; 265 } 266 $shared = 0 if $noshared; 267 268 $parser->parse_linkargs1($deplibs, $gp, $dirs, $libs); 269 tsay {"end parse_linkargs1"}; 270 tsay {"deplibs = @$deplibs"}; 271 272 my $sover = '0.0'; 273 my $origver = 'unknown'; 274 # environment overrides -version-info 275 (my $envlibname = $libname) =~ s/[.+-]/_/g; 276 my ($current, $revision, $age) = (0, 0, 0); 277 if ($gp->version_info) { 278 ($current, $revision, $age) = parse_version_info($gp->version_info); 279 $origver = "$current.$revision"; 280 $sover = $origver; 281 } 282 if ($ENV{"${envlibname}_ltversion"}) { 283 # this takes priority over the previous 284 $sover = $ENV{"${envlibname}_ltversion"}; 285 ($current, $revision) = split /\./, $sover; 286 $age = 0; 287 } 288 if (defined $gp->release) { 289 $sharedlib_symlink = $sharedlib; 290 $sharedlib = $libname.'-'.$gp->release.'.so'; 291 } 292 if ($gp->avoid_version || 293 (defined $gp->release && !$gp->version_info)) { 294 # don't add a version in these cases 295 } else { 296 $sharedlib .= ".$sover"; 297 if (defined $gp->release) { 298 $sharedlib_symlink .= ".$sover"; 299 } 300 } 301 302 # XXX add error condition somewhere... 303 $static = 0 if $shared && $gp->has_tag('disable-static'); 304 $shared = 0 if $static && $gp->has_tag('disable-shared'); 305 306 tsay {"SHARED: $shared\nSTATIC: $static"}; 307 308 $lainfo->{'libname'} = $libname; 309 if ($shared) { 310 $lainfo->{'dlname'} = $sharedlib; 311 $lainfo->{'library_names'} = $sharedlib; 312 $lainfo->{'library_names'} .= " $sharedlib_symlink" 313 if defined $gp->release; 314 $lainfo->link($ltprog, $ltconfig, $ofile, $sharedlib, $odir, 1, \@sobjs, $dirs, $libs, $deplibs, $libdirs, $parser, $gp); 315 tsay {"sharedlib: $sharedlib"}; 316 $lainfo->{'current'} = $current; 317 $lainfo->{'revision'} = $revision; 318 $lainfo->{'age'} = $age; 319 } 320 if ($static) { 321 $lainfo->{'old_library'} = $staticlib; 322 $lainfo->link($ltprog, $ltconfig, $ofile, $staticlib, $odir, 0, ($convenience && @sobjs > 0) ? \@sobjs : \@objs, $dirs, $libs, $deplibs, $libdirs, $parser, $gp); 323 tsay {($convenience ? "convenience" : "static"), 324 " lib: $staticlib"}; 325 } 326 $lainfo->{installed} = 'no'; 327 $lainfo->{shouldnotlink} = $gp->module ? 'yes' : 'no'; 328 map { $_ = "-R$_" } @Ropts; 329 unshift @$deplibs, @Ropts if @Ropts; 330 tsay {"deplibs = @$deplibs"}; 331 my $finaldeplibs = reverse_zap_duplicates_ref($deplibs); 332 tsay {"finaldeplibs = @$finaldeplibs"}; 333 $lainfo->set('dependency_libs', "@$finaldeplibs"); 334 if (@RPopts) { 335 if (@RPopts > 1) { 336 tsay {"more than 1 -rpath option given, ", 337 "taking the first: ", $RPopts[0]}; 338 } 339 $lainfo->{'libdir'} = $RPopts[0]; 340 } 341 if (!($convenience && $ofile =~ m/\.a$/)) { 342 $lainfo->write($outfile, $ofile); 343 unlink("$odir/$ltdir/$ofile"); 344 symlink("../$ofile", "$odir/$ltdir/$ofile"); 345 } 346 my $lai = "$odir/$ltdir/$ofile".'i'; 347 if ($shared) { 348 my $pdeplibs = process_deplibs($finaldeplibs); 349 if (defined $pdeplibs) { 350 $lainfo->set('dependency_libs', "@$pdeplibs"); 351 } 352 if (! $gp->module) { 353 $lainfo->write_shared_libs_log($origver); 354 } 355 } 356 $lainfo->{'installed'} = 'yes'; 357 # write .lai file (.la file that will be installed) 358 $lainfo->write($lai, $ofile); 359 } 360} 361 362# populate arrays of non-pic and pic objects and remove these from @ARGV 363sub generate_objlist 364{ 365 my $objs = shift; 366 my $sobjs = shift; 367 my $objsource = shift; 368 369 my $result = []; 370 foreach my $a (@$objsource) { 371 if ($a =~ m/\S+\.lo$/) { 372 require LT::LoFile; 373 my $ofile = basename($a); 374 my $odir = dirname($a); 375 my $loinfo = LT::LoFile->parse($a); 376 if ($loinfo->{'non_pic_object'}) { 377 my $o; 378 $o .= "$odir/" if ($odir ne '.'); 379 $o .= $loinfo->{'non_pic_object'}; 380 push @$objs, $o; 381 } 382 if ($loinfo->{'pic_object'}) { 383 my $o; 384 $o .= "$odir/" if ($odir ne '.'); 385 $o .= $loinfo->{'pic_object'}; 386 push @$sobjs, $o; 387 } 388 } elsif ($a =~ m/\S+\.o$/) { 389 push @$objs, $a; 390 } else { 391 push @$result, $a; 392 } 393 } 394 @$objsource = @$result; 395} 396 397# convert 4:5:8 into a list of numbers 398sub parse_version_info 399{ 400 my $vinfo = shift; 401 402 if ($vinfo =~ m/^(\d+):(\d+):(\d+)$/) { 403 return ($1, $2, $3); 404 } elsif ($vinfo =~ m/^(\d+):(\d+)$/) { 405 return ($1, $2, 0); 406 } elsif ($vinfo =~ m/^(\d+)$/) { 407 return ($1, 0, 0); 408 } else { 409 die "Error parsing -version-info $vinfo\n"; 410 } 411} 412 413# prepare dependency_libs information for the .la file which is installed 414# i.e. remove any .libs directories and use the final libdir for all the 415# .la files 416sub process_deplibs 417{ 418 my $linkflags = shift; 419 420 my $result; 421 422 foreach my $lf (@$linkflags) { 423 if ($lf =~ m/-L\S+\Q$ltdir\E$/) { 424 } elsif ($lf =~ m/-L\./) { 425 } elsif ($lf =~ m/\/\S+\/(\S+\.la)/) { 426 my $lafile = $1; 427 require LT::LaFile; 428 my $libdir = LT::LaFile->parse($lf)->{'libdir'}; 429 if ($libdir eq '') { 430 # this drops libraries which will not be 431 # installed 432 # XXX improve checks when adding to deplibs 433 say "warning: $lf dropped from deplibs"; 434 } else { 435 $lf = $libdir.'/'.$lafile; 436 push @$result, $lf; 437 } 438 } else { 439 push @$result, $lf; 440 } 441 } 442 return $result; 443} 444 445package LT::Parser; 446use File::Basename; 447use Cwd qw(abs_path); 448use LT::Util; 449use LT::Trace; 450 451my $calls = 0; 452 453sub build_cache 454{ 455 my ($self, $lainfo, $level) = @_; 456 my $o = $lainfo->{cached} = { 457 deplibs => [], libdirs => [], result => []}; 458 $self->internal_resolve_la($o, $lainfo->deplib_list, 459 $level+1); 460 push(@{$o->{deplibs}}, @{$lainfo->deplib_list}); 461 if ($lainfo->{libdir} ne '') { 462 push(@{$o->{libdirs}}, $lainfo->{libdir}); 463 } 464 for my $e (qw(deplibs libdirs result)) { 465 if (@{$o->{$e}} > 50) { 466 $o->{$e} = reverse_zap_duplicates_ref($o->{$e}); 467 } 468 } 469} 470 471sub internal_resolve_la 472{ 473 my ($self, $o, $args, $level) = @_; 474 $level //= 0; 475 tsay {"resolve level: $level"}; 476 $o->{pthread} = 0; 477 foreach my $_ (@$args) { 478 if ($_ eq '-pthread') { 479 $o->{pthread}++; 480 next; 481 } 482 push(@{$o->{result}}, $_); 483 next unless m/\.la$/; 484 require LT::LaFile; 485 my $lainfo = LT::LaFile->parse($_); 486 if (!exists $lainfo->{cached}) { 487 $self->build_cache($lainfo, $level+1); 488 } 489 $o->{pthread} += $lainfo->{cached}{pthread}; 490 for my $e (qw(deplibs libdirs result)) { 491 push(@{$o->{$e}}, @{$lainfo->{cached}{$e}}); 492 } 493 } 494 $calls++; 495} 496 497END 498{ 499 LT::Trace::print { "Calls to resolve_la: $calls\n" } if $calls; 500} 501 502# resolve .la files until a level with empty dependency_libs is reached. 503sub resolve_la 504{ 505 my ($self, $deplibs, $libdirs) = @_; 506 507 tsay {"argvstring (pre resolve_la): @{$self->{args}}"}; 508 my $o = { result => [], deplibs => $deplibs, libdirs => $libdirs}; 509 510 $self->internal_resolve_la($o, $self->{args}); 511 if ($o->{pthread}) { 512 unshift(@{$o->{result}}, '-pthread'); 513 unshift(@{$o->{deplibs}}, '-pthread'); 514 } 515 516 tsay {"argvstring (post resolve_la): @{$self->{args}}"}; 517 $self->{args} = $o->{result}; 518} 519 520# parse link flags and arguments 521# eliminate all -L and -l flags in the argument string and add the 522# corresponding directories and library names to the dirs/libs hashes. 523# fill deplibs, to be taken up as dependencies in the resulting .la file... 524# set up a hash for library files which haven't been found yet. 525# deplibs are formed by collecting the original -L/-l flags, plus 526# any .la files passed on the command line, EXCEPT when the .la file 527# does not point to a shared library. 528# pass 1 529# -Lfoo, -lfoo, foo.a, foo.la 530# recursively find .la files corresponding to -l flags; if there is no .la 531# file, just inspect the library file itself for any dependencies. 532sub internal_parse_linkargs1 533{ 534 my ($self, $deplibs, $gp, $dirs, $libs, $args, $level) = @_; 535 536 $level //= 0; 537 tsay {"parse_linkargs1, level: $level"}; 538 tsay {" args: @$args"}; 539 my $result = $self->{result}; 540 541 # first read all directories where we can search libraries 542 foreach my $_ (@$args) { 543 if (m/^-L(.*)/) { 544 if (!exists $dirs->{$1}) { 545 $dirs->{$1} = 1; 546 tsay {" adding $_ to deplibs"} 547 if $level == 0; 548 push @$deplibs, $_; 549 } 550 } 551 } 552 foreach my $_ (@$args) { 553 tsay {" processing $_"}; 554 if (!$_ || $_ eq '' || m/^\s+$/) { 555 # skip empty arguments 556 } elsif ($_ eq '-pthread') { 557 $self->{pthread} = 1; 558 } elsif (m/^-L(.*)/) { 559 # already read earlier, do nothing 560 } elsif (m/^-R(.*)/) { 561 # -R options originating from .la resolution 562 # those from @ARGV are in @Ropts 563 $gp->add_R($1); 564 } elsif (m/^-l(\S+)/) { 565 my @largs = (); 566 my $key = $1; 567 if (!exists $libs->{$key}) { 568 $libs->create($key); 569 require LT::LaFile; 570 my $lafile = LT::LaFile->find($key, $dirs); 571 if ($lafile) { 572 $libs->{$key}->{lafile} = $lafile; 573 my $absla = abs_path($lafile); 574 tsay {" adding $absla to deplibs"} 575 if $level == 0; 576 push @$deplibs, $absla; 577 push @$result, $lafile; 578 next; 579 } else { 580 $libs->{$key}->resolve_library($dirs, 1, 0, 'notyet', $gp); 581 my @deps = $libs->{$key}->inspect; 582 foreach my $d (@deps) { 583 my $k = basename($d); 584 $k =~ s/^(\S+)\.so.*$/$1/; 585 $k =~ s/^lib//; 586 push(@largs, "-l$k"); 587 } 588 } 589 } 590 tsay {" adding $_ to deplibs"} if $level == 0; 591 push @$deplibs, $_; 592 push(@$result, $_); 593 my $dummy = []; # no need to add deplibs recursively 594 $self->internal_parse_linkargs1($dummy, $gp, $dirs, 595 $libs, \@largs, $level+1) if @largs; 596 } elsif (m/(\S+\/)*(\S+)\.a$/) { 597 (my $key = $2) =~ s/^lib//; 598 $dirs->{abs_dir($_)} = 1; 599 $libs->create($key)->{fullpath} = $_; 600 push(@$result, $_); 601 } elsif (m/(\S+\/)*(\S+)\.la$/) { 602 (my $key = $2) =~ s/^lib//; 603 $dirs->{abs_dir($_)} = 1; 604 my $fulla = abs_path($_); 605 require LT::LaFile; 606 my $lainfo = LT::LaFile->parse($fulla); 607 my $dlname = $lainfo->{dlname}; 608 my $oldlib = $lainfo->{old_library}; 609 my $libdir = $lainfo->{libdir}; 610 if ($dlname ne '') { 611 if (!exists $libs->{$key}) { 612 $libs->create($key)->{lafile} = $fulla; 613 } 614 } 615 push(@$result, $_); 616 push(@$deplibs, $fulla) if $libdir ne ''; 617 } elsif (m/(\S+\/)*(\S+)\.so(\.\d+){2}/) { 618 (my $key = $2) =~ s/^lib//; 619 $dirs->{abs_dir($_)} = 1; 620 $libs->create($key); 621 # not really normal argument 622 # -lfoo should be used instead, so convert it 623 push(@$result, "-l$key"); 624 } else { 625 push(@$result, $_); 626 } 627 } 628} 629 630sub parse_linkargs1 631{ 632 my ($self, $deplibs, $gp, $dirs, $libs, $args) = @_; 633 $self->{result} = []; 634 $self->internal_parse_linkargs1($deplibs, $gp, $dirs, $libs, 635 $self->{args}); 636 push(@$deplibs, '-pthread') if $self->{pthread}; 637 $self->{args} = $self->{result}; 638} 639 640# pass 2 641# -Lfoo, -lfoo, foo.a 642# no recursion in pass 2 643# fill orderedlibs array, which is the sequence of shared libraries 644# after resolving all .la 645# (this list may contain duplicates) 646# fill staticlibs array, which is the sequence of static and convenience 647# libraries 648# XXX the variable $parser->{seen_la_shared} will register whether or not 649# a .la file is found which refers to a shared library and which is not 650# yet installed 651# this is used to decide where to link executables and create wrappers 652sub parse_linkargs2 653{ 654 my ($self, $gp, $orderedlibs, $staticlibs, $dirs, $libs) = @_; 655 tsay {"parse_linkargs2"}; 656 tsay {" args: @{$self->{args}}"}; 657 my $result = []; 658 659 foreach my $_ (@{$self->{args}}) { 660 tsay {" processing $_"}; 661 if (!$_ || $_ eq '' || m/^\s+$/) { 662 # skip empty arguments 663 } elsif ($_ eq '-lc') { 664 # don't link explicitly with libc (just remove -lc) 665 } elsif ($_ eq '-pthread') { 666 $self->{pthread} = 1; 667 } elsif (m/^-L(.*)/) { 668 if (!exists $dirs->{$1}) { 669 $dirs->{$1} = 1; 670 } 671 } elsif (m/^-R(.*)/) { 672 # -R options originating from .la resolution 673 # those from @ARGV are in @Ropts 674 $gp->add_R($1); 675 } elsif (m/^-l(.*)/) { 676 my @largs = (); 677 my $key = $1; 678 $libs->create($key); 679 push @$orderedlibs, $key; 680 } elsif (m/(\S+\/)*(\S+)\.a$/) { 681 (my $key = $2) =~ s/^lib//; 682 $libs->create($key)->{fullpath} = $_; 683 push(@$staticlibs, $_); 684 } elsif (m/(\S+\/)*(\S+)\.la$/) { 685 (my $key = $2) =~ s/^lib//; 686 my $d = abs_dir($_); 687 $dirs->{$d} = 1; 688 my $fulla = abs_path($_); 689 require LT::LaFile; 690 my $lainfo = LT::LaFile->parse($fulla); 691 my $dlname = $lainfo->stringize('dlname'); 692 my $oldlib = $lainfo->stringize('old_library'); 693 my $installed = $lainfo->stringize('installed'); 694 if ($dlname ne '' && $installed eq 'no') { 695 tsay {"seen uninstalled la shared in $_"}; 696 $self->{seen_la_shared} = 1; 697 } 698 if ($dlname eq '' && -f "$d/$ltdir/$oldlib") { 699 push @$staticlibs, "$d/$ltdir/$oldlib"; 700 } else { 701 if (!exists $libs->{$key}) { 702 $libs->create($key)->{lafile} = $fulla; 703 } 704 push @$orderedlibs, $key; 705 } 706 } elsif (m/^-Wl,(\S+)$/) { 707 # libtool accepts a list of -Wl options separated 708 # by commas, and possibly with a trailing comma 709 # which is not accepted by the linker 710 my @Wlflags = split(/,/, $1); 711 foreach my $f (@Wlflags) { 712 push(@$result, "-Wl,$f"); 713 } 714 } else { 715 push(@$result, $_); 716 } 717 } 718 tsay {"end parse_linkargs2"}; 719 return $result; 720} 721 722sub new 723{ 724 my ($class, $args) = @_; 725 bless { args => $args, pthread => 0 }, $class; 726} 727 728package LT::Linker; 729use LT::Trace; 730use LT::Util; 731use File::Basename; 732use Cwd qw(abs_path); 733 734sub new 735{ 736 my $class = shift; 737 bless {}, $class; 738} 739 740sub create_symlinks 741{ 742 my ($self, $dir, $libs) = @_; 743 if (! -d $dir) { 744 mkdir($dir) or die "Cannot mkdir($dir) : $!\n"; 745 } 746 747 foreach my $l (values %$libs) { 748 my $f = $l->{fullpath}; 749 next if !defined $f; 750 next if $f =~ m/\.a$/; 751 my $libnames = []; 752 if (defined $l->{lafile}) { 753 require LT::LaFile; 754 my $lainfo = LT::LaFile->parse($l->{lafile}); 755 my $librarynames = $lainfo->stringize('library_names'); 756 @$libnames = split /\s/, $librarynames; 757 $libnames = reverse_zap_duplicates_ref($libnames); 758 } else { 759 push @$libnames, basename($f); 760 } 761 foreach my $libfile (@$libnames) { 762 my $link = "$dir/$libfile"; 763 tsay {"ln -s $f $link"}; 764 next if -f $link; 765 my $p = abs_path($f); 766 if (!symlink($p, $link)) { 767 die "Cannot create symlink($p, $link): $!\n" 768 unless $!{EEXIST}; 769 } 770 } 771 } 772 return $dir; 773} 774 775sub common1 776{ 777 my ($self, $parser, $gp, $deplibs, $libdirs, $dirs, $libs) = @_; 778 779 $parser->resolve_la($deplibs, $libdirs); 780 my $orderedlibs = []; 781 my $staticlibs = []; 782 my $args = $parser->parse_linkargs2($gp, $orderedlibs, $staticlibs, $dirs, 783 $libs); 784 tsay {"staticlibs = \n", join("\n", @$staticlibs)}; 785 tsay {"orderedlibs = @$orderedlibs"}; 786 $orderedlibs = reverse_zap_duplicates_ref($orderedlibs); 787 tsay {"final orderedlibs = @$orderedlibs"}; 788 return ($staticlibs, $orderedlibs, $args); 789} 790 791sub infer_libparameter 792{ 793 my ($self, $a, $k) = @_; 794 my $lib = basename($a); 795 if ($lib =~ m/^lib(.*)\.so(\.\d+){2}$/) { 796 $lib = $1; 797 } elsif ($lib =~ m/^lib(.*)\.so$/) { 798 say "warning: library filename $a has no version number"; 799 $lib = $1; 800 } else { 801 say "warning: cannot derive -l flag from library filename $a, assuming hash key -l$k"; 802 $lib = $k; 803 } 804 return "-l$lib"; 805} 806 8071; 808 809