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