1# $OpenBSD: Library.pm,v 1.8 2023/07/08 08:15:32 espie Exp $ 2 3# Copyright (c) 2007-2010 Steven Mestdagh <steven@openbsd.org> 4# Copyright (c) 2012 Marc Espie <espie@openbsd.org> 5# 6# Permission to use, copy, modify, and distribute this software for any 7# purpose with or without fee is hereby granted, provided that the above 8# copyright notice and this permission notice appear in all copies. 9# 10# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 18use v5.36; 19use feature qw(say); 20 21use LT::LaFile; 22 23package LT::LaFile; 24sub link(@p) 25{ 26 return LT::Linker::LaFile->new->link(@p); 27} 28 29package LT::Linker::LaFile; 30our @ISA = qw(LT::Linker); 31 32use LT::Util; 33use LT::Trace; 34use File::Basename; 35 36sub link 37{ 38 my ($linker, $self, $ltprog, $ltconfig, $la, $fname, $odir, $shared, 39 $objs, $dirs, $libs, $deplibs, $libdirs, $parser, $gp) = @_; 40 41 tsay {"creating link command for library (linked ", 42 ($shared) ? "dynamically" : "statically", ")"}; 43 44 my $RPdirs = $self->{RPdirs}; 45 46 my @libflags; 47 my @cmd; 48 my $dst = ($odir eq '.') ? "$ltdir/$fname" : "$odir/$ltdir/$fname"; 49 if ($la =~ m/\.a$/) { 50 # probably just a convenience library 51 $dst = ($odir eq '.') ? "$fname" : "$odir/$fname"; 52 } 53 my $symlinkdir = $ltdir; 54 if ($odir ne '.') { 55 $symlinkdir = "$odir/$ltdir"; 56 } 57 mkdir $symlinkdir if ! -d $symlinkdir; 58 59 my ($staticlibs, $finalorderedlibs, $args) = 60 $linker->common1($parser, $gp, $deplibs, $libdirs, $dirs, $libs); 61 62 # static linking 63 if (!$shared) { 64 @cmd = ('ar', 'cru', $dst); 65 foreach my $a (@$staticlibs) { 66 if ($a =~ m/\.a$/ && $a !~ m/_pic\.a/) { 67 # extract objects from archive 68 my $libfile = basename($a); 69 my $xdir = "$odir/$ltdir/${la}x/$libfile"; 70 LT::Archive->extract($xdir, $a); 71 my @kobjs = LT::Archive->get_objlist($a); 72 map { $_ = "$xdir/$_"; } @kobjs; 73 push @libflags, @kobjs; 74 } 75 } 76 foreach my $k (@$finalorderedlibs) { 77 my $l = $libs->{$k}; 78 # XXX improve test 79 # this has to be done probably only with 80 # convenience libraries 81 next if !defined $l->{lafile}; 82 my $lainfo = LT::LaFile->parse($l->{lafile}); 83 next if ($lainfo->stringize('dlname') ne ''); 84 $l->resolve_library($dirs, 0, 0, ref($self)); 85 my $a = $l->{fullpath}; 86 if ($a =~ m/\.a$/ && $a !~ m/_pic\.a/) { 87 # extract objects from archive 88 my $libfile = basename $a; 89 my $xdir = "$odir/$ltdir/${la}x/$libfile"; 90 LT::Archive->extract($xdir, $a); 91 my @kobjs = LT::Archive->get_objlist($a); 92 map { $_ = "$xdir/$_"; } @kobjs; 93 push @libflags, @kobjs; 94 } 95 } 96 push @cmd, @libflags if @libflags; 97 push @cmd, @$objs if @$objs; 98 my ($fh, $file); 99 100 if (@cmd > 512) { 101 use OpenBSD::MkTemp qw(mkstemp); 102 my @extra = splice(@cmd, 512); 103 ($fh, $file) = mkstemp("/tmp/arargs.XXXXXXXXXXXX"); 104 print $fh map {"$_\n"} @extra; 105 close $fh; 106 push @cmd, "\@$file"; 107 } 108 LT::Exec->link(@cmd); 109 unlink($file) if defined $file; 110 111 LT::Exec->link('ranlib', $dst); 112 return; 113 } 114 115 my $tmp = []; 116 while (my $k = shift @$finalorderedlibs) { 117 my $l = $libs->{$k}; 118 $l->resolve_library($dirs, 1, $gp->static, ref($self)); 119 if ($l->{dropped}) { 120 # remove library if dependency on it has been dropped 121 delete $libs->{$k}; 122 } else { 123 push(@$tmp, $k); 124 } 125 } 126 $finalorderedlibs = $tmp; 127 128 my @libobjects = values %$libs; 129 tsay {"libs:\n", join("\n", (keys %$libs))}; 130 tsay {"libfiles:\n", 131 join("\n", map { $_->{fullpath}//'UNDEF' } @libobjects) }; 132 133 $linker->create_symlinks($symlinkdir, $libs); 134 my $prev_was_archive = 0; 135 my $libcounter = 0; 136 foreach my $k (@$finalorderedlibs) { 137 my $a = $libs->{$k}->{fullpath} || die "Link error: $k not found in \$libs\n"; 138 if ($a =~ m/\.a$/) { 139 # don't make a -lfoo out of a static library 140 push @libflags, '-Wl,-whole-archive' unless $prev_was_archive; 141 push @libflags, $a; 142 if ($libcounter == @$finalorderedlibs - 1) { 143 push @libflags, '-Wl,-no-whole-archive'; 144 } 145 $prev_was_archive = 1; 146 } else { 147 push @libflags, '-Wl,-no-whole-archive' if $prev_was_archive; 148 $prev_was_archive = 0; 149 push @libflags, $linker->infer_libparameter($a, $k); 150 } 151 $libcounter++; 152 } 153 154 # add libdirs to rpath if they are not in standard lib path 155 for my $l (@$libdirs) { 156 if (!LT::OSConfig->is_search_dir($l)) { 157 push @$RPdirs, $l; 158 } 159 } 160 161 my @linkeropts = (); 162 if (!$ltconfig->noshared) { 163 push(@linkeropts, '-soname', $fname); 164 for my $d (@$RPdirs) { 165 push(@linkeropts, '-rpath', $d); 166 } 167 } 168 169 @cmd = @$ltprog; 170 push @cmd, $ltconfig->sharedflag, @{$ltconfig->picflags}; 171 push @cmd, '-o', $dst; 172 push @cmd, '-pthread' if $parser->{pthread}; 173 push @cmd, @$args if $args; 174 push @cmd, @$objs if @$objs; 175 push @cmd, '-Wl,-whole-archive', @$staticlibs, '-Wl,-no-whole-archive' 176 if @$staticlibs; 177 push @cmd, "-L$symlinkdir", @libflags if @libflags; 178 179 my @e = $linker->export_symbols($ltconfig, 180 "$odir/$ltdir/$la", $gp, @$objs, @$staticlibs); 181 push(@cmd, join(',', "-Wl", @e)) if @e; 182 push @cmd, join(',', "-Wl", @linkeropts) if @linkeropts; 183 LT::Exec->link(@cmd); 184} 185 1861; 187