xref: /openbsd/usr.bin/libtool/LT/Mode/Link/Library.pm (revision 898184e3)
1# $OpenBSD: Library.pm,v 1.2 2012/11/09 10:55:01 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 strict;
19use warnings;
20use feature qw(say);
21
22use LT::LaFile;
23
24package LT::LaFile;
25sub link
26{
27	return LT::Linker::LaFile->new->link(@_);
28}
29
30package LT::Linker::LaFile;
31our @ISA = qw(LT::Linker);
32
33use LT::Util;
34use LT::Trace;
35use File::Basename;
36
37sub link
38{
39	my ($linker, $self, $ltprog, $ltconfig, $la, $fname, $odir, $shared,
40	    $objs, $dirs, $libs, $deplibs, $libdirs, $parser, $gp) = @_;
41
42	tsay {"creating link command for library (linked ",
43		($shared) ? "dynamically" : "statically", ")"};
44
45	my @libflags;
46	my @cmd;
47	my $dst = ($odir eq '.') ? "$ltdir/$fname" : "$odir/$ltdir/$fname";
48	if ($la =~ m/\.a$/) {
49		# probably just a convenience library
50		$dst = ($odir eq '.') ? "$fname" : "$odir/$fname";
51	}
52	my $symlinkdir = $ltdir;
53	if ($odir ne '.') {
54		$symlinkdir = "$odir/$ltdir";
55	}
56	mkdir $symlinkdir if ! -d $symlinkdir;
57
58	my ($staticlibs, $finalorderedlibs, $args) =
59	    $linker->common1($parser, $gp, $deplibs, $libdirs, $dirs, $libs);
60
61	# static linking
62	if (!$shared) {
63		@cmd = ('ar', 'cru', $dst);
64		foreach my $a (@$staticlibs) {
65			if ($a =~ m/\.a$/ && $a !~ m/_pic\.a/) {
66				# extract objects from archive
67				my $libfile = basename($a);
68				my $xdir = "$odir/$ltdir/${la}x/$libfile";
69				LT::Archive->extract($xdir, $a);
70				my @kobjs = LT::Archive->get_objlist($a);
71				map { $_ = "$xdir/$_"; } @kobjs;
72				push @libflags, @kobjs;
73			}
74		}
75		foreach my $k (@$finalorderedlibs) {
76			my $l = $libs->{$k};
77			# XXX improve test
78			# this has to be done probably only with
79			# convenience libraries
80			next if !defined $l->{lafile};
81			my $lainfo = LT::LaFile->parse($l->{lafile});
82			next if ($lainfo->stringize('dlname') ne '');
83			$l->resolve_library($dirs, 0, 0, ref($self));
84			my $a = $l->{fullpath};
85			if ($a =~ m/\.a$/ && $a !~ m/_pic\.a/) {
86				# extract objects from archive
87				my $libfile = basename $a;
88				my $xdir = "$odir/$ltdir/${la}x/$libfile";
89				LT::Archive->extract($xdir, $a);
90				my @kobjs = LT::Archive->get_objlist($a);
91				map { $_ = "$xdir/$_"; } @kobjs;
92				push @libflags, @kobjs;
93			}
94		}
95		push @cmd, @libflags if @libflags;
96		push @cmd, @$objs if @$objs;
97		LT::Exec->link(@cmd);
98		LT::Exec->link('ranlib', $dst);
99		return;
100	}
101
102	my $tmp = [];
103	while (my $k = shift @$finalorderedlibs) {
104		my $l = $libs->{$k};
105		$l->resolve_library($dirs, 1, $gp->static, ref($self));
106		if ($l->{dropped}) {
107			# remove library if dependency on it has been dropped
108			delete $libs->{$k};
109		} else {
110			push(@$tmp, $k);
111		}
112	}
113	$finalorderedlibs = $tmp;
114
115	my @libobjects = values %$libs;
116	tsay {"libs:\n", join("\n", (keys %$libs))};
117	tsay {"libfiles:\n",
118	    join("\n", map { $_->{fullpath}//'UNDEF' } @libobjects) };
119
120	$linker->create_symlinks($symlinkdir, $libs);
121	my $prev_was_archive = 0;
122	my $libcounter = 0;
123	foreach my $k (@$finalorderedlibs) {
124		my $a = $libs->{$k}->{fullpath} || die "Link error: $k not found in \$libs\n";
125		if ($a =~ m/\.a$/) {
126			# don't make a -lfoo out of a static library
127			push @libflags, '-Wl,-whole-archive' unless $prev_was_archive;
128			push @libflags, $a;
129			if ($libcounter == @$finalorderedlibs - 1) {
130				push @libflags, '-Wl,-no-whole-archive';
131			}
132			$prev_was_archive = 1;
133		} else {
134			push @libflags, '-Wl,-no-whole-archive' if $prev_was_archive;
135			$prev_was_archive = 0;
136			push @libflags, $linker->infer_libparameter($a, $k);
137		}
138		$libcounter++;
139	}
140
141	@cmd = @$ltprog;
142	push @cmd, $ltconfig->sharedflag, @{$ltconfig->picflags};
143	push @cmd, '-o', $dst;
144	push @cmd, '-pthread' if $parser->{pthread};
145	push @cmd, @$args if $args;
146	push @cmd, @$objs if @$objs;
147	push @cmd, '-Wl,-whole-archive', @$staticlibs, '-Wl,-no-whole-archive'
148       		if @$staticlibs;
149	push @cmd, "-L$symlinkdir", @libflags if @libflags;
150
151	my @e = $linker->export_symbols($ltconfig,
152	    "$odir/$ltdir/$la", $gp, @$objs, @$staticlibs);
153	push(@cmd, join(',', "-Wl", @e)) if @e;
154	LT::Exec->link(@cmd);
155}
156
1571;
158