xref: /openbsd/usr.bin/libtool/LT/Mode/Link/Library.pm (revision a6445c1d)
1# $OpenBSD: Library.pm,v 1.5 2014/04/16 14:39:06 zhuk 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 $RPdirs = $self->{RPdirs};
46
47	my @libflags;
48	my @cmd;
49	my $dst = ($odir eq '.') ? "$ltdir/$fname" : "$odir/$ltdir/$fname";
50	if ($la =~ m/\.a$/) {
51		# probably just a convenience library
52		$dst = ($odir eq '.') ? "$fname" : "$odir/$fname";
53	}
54	my $symlinkdir = $ltdir;
55	if ($odir ne '.') {
56		$symlinkdir = "$odir/$ltdir";
57	}
58	mkdir $symlinkdir if ! -d $symlinkdir;
59
60	my ($staticlibs, $finalorderedlibs, $args) =
61	    $linker->common1($parser, $gp, $deplibs, $libdirs, $dirs, $libs);
62
63	# static linking
64	if (!$shared) {
65		@cmd = ('ar', 'cru', $dst);
66		foreach my $a (@$staticlibs) {
67			if ($a =~ m/\.a$/ && $a !~ m/_pic\.a/) {
68				# extract objects from archive
69				my $libfile = basename($a);
70				my $xdir = "$odir/$ltdir/${la}x/$libfile";
71				LT::Archive->extract($xdir, $a);
72				my @kobjs = LT::Archive->get_objlist($a);
73				map { $_ = "$xdir/$_"; } @kobjs;
74				push @libflags, @kobjs;
75			}
76		}
77		foreach my $k (@$finalorderedlibs) {
78			my $l = $libs->{$k};
79			# XXX improve test
80			# this has to be done probably only with
81			# convenience libraries
82			next if !defined $l->{lafile};
83			my $lainfo = LT::LaFile->parse($l->{lafile});
84			next if ($lainfo->stringize('dlname') ne '');
85			$l->resolve_library($dirs, 0, 0, ref($self));
86			my $a = $l->{fullpath};
87			if ($a =~ m/\.a$/ && $a !~ m/_pic\.a/) {
88				# extract objects from archive
89				my $libfile = basename $a;
90				my $xdir = "$odir/$ltdir/${la}x/$libfile";
91				LT::Archive->extract($xdir, $a);
92				my @kobjs = LT::Archive->get_objlist($a);
93				map { $_ = "$xdir/$_"; } @kobjs;
94				push @libflags, @kobjs;
95			}
96		}
97		push @cmd, @libflags if @libflags;
98		push @cmd, @$objs if @$objs;
99		LT::Exec->link(@cmd);
100		LT::Exec->link('ranlib', $dst);
101		return;
102	}
103
104	my $tmp = [];
105	while (my $k = shift @$finalorderedlibs) {
106		my $l = $libs->{$k};
107		$l->resolve_library($dirs, 1, $gp->static, ref($self));
108		if ($l->{dropped}) {
109			# remove library if dependency on it has been dropped
110			delete $libs->{$k};
111		} else {
112			push(@$tmp, $k);
113		}
114	}
115	$finalorderedlibs = $tmp;
116
117	my @libobjects = values %$libs;
118	tsay {"libs:\n", join("\n", (keys %$libs))};
119	tsay {"libfiles:\n",
120	    join("\n", map { $_->{fullpath}//'UNDEF' } @libobjects) };
121
122	$linker->create_symlinks($symlinkdir, $libs);
123	my $prev_was_archive = 0;
124	my $libcounter = 0;
125	foreach my $k (@$finalorderedlibs) {
126		my $a = $libs->{$k}->{fullpath} || die "Link error: $k not found in \$libs\n";
127		if ($a =~ m/\.a$/) {
128			# don't make a -lfoo out of a static library
129			push @libflags, '-Wl,-whole-archive' unless $prev_was_archive;
130			push @libflags, $a;
131			if ($libcounter == @$finalorderedlibs - 1) {
132				push @libflags, '-Wl,-no-whole-archive';
133			}
134			$prev_was_archive = 1;
135		} else {
136			push @libflags, '-Wl,-no-whole-archive' if $prev_was_archive;
137			$prev_was_archive = 0;
138			push @libflags, $linker->infer_libparameter($a, $k);
139		}
140		$libcounter++;
141	}
142
143	# add libdirs to rpath if they are not in standard lib path
144	for my $l (@$libdirs) {
145		if (!LT::OSConfig->is_search_dir($l)) {
146			push @$RPdirs, $l;
147		}
148	}
149
150	my @linkeropts = ();
151	if (!$ltconfig->noshared) {
152		for my $d (@$RPdirs) {
153			push(@linkeropts, '-rpath', $d);
154		}
155	}
156
157	@cmd = @$ltprog;
158	push @cmd, $ltconfig->sharedflag, @{$ltconfig->picflags};
159	push @cmd, '-o', $dst;
160	push @cmd, '-pthread' if $parser->{pthread};
161	push @cmd, @$args if $args;
162	push @cmd, @$objs if @$objs;
163	push @cmd, '-Wl,-whole-archive', @$staticlibs, '-Wl,-no-whole-archive'
164	    if @$staticlibs;
165	push @cmd, "-L$symlinkdir", @libflags if @libflags;
166
167	my @e = $linker->export_symbols($ltconfig,
168	    "$odir/$ltdir/$la", $gp, @$objs, @$staticlibs);
169	push(@cmd, join(',', "-Wl", @e)) if @e;
170	push @cmd, join(',', "-Wl", @linkeropts) if @linkeropts;
171	LT::Exec->link(@cmd);
172}
173
1741;
175