xref: /openbsd/usr.bin/libtool/LT/Mode/Link/Library.pm (revision 0a6aab58)
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