xref: /openbsd-src/usr.bin/libtool/LT/Library.pm (revision 46035553bfdd96e63c94e32da0210227ec2e3cf1)
1# $OpenBSD: Library.pm,v 1.13 2018/10/28 15:21:49 naddy 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 switch state);
21
22package LT::Library::Stash;
23
24sub new
25{
26	my $class = shift;
27
28	bless {}, $class;
29}
30
31sub create
32{
33	my ($self, $key) = @_;
34	if (!exists $self->{$key}) {
35		$self->{$key} = LT::Library->new($key);
36	}
37	return $self->{$key};
38}
39
40package LT::Library;
41
42use LT::Util;
43use LT::Trace;
44
45# find actual library filename
46# XXX pick the right one if multiple are found!
47sub resolve_library
48{
49	my ($self, $dirs, $shared, $staticflag, $linkmode, $gp) = @_;
50
51	my $libtofind = $self->{key};
52	my $libfile = 0;
53	my @globbedlib;
54
55	my $pic = '';	# used when finding static libraries
56	if ($linkmode eq 'LT::LaFile') {
57		$pic = '_pic';
58	}
59
60	if (defined $self->{lafile}) {
61		require LT::LaFile;
62		# if there is a .la file, use the info from there
63		tsay {"found .la file $self->{lafile} for library key: ",
64		    $self->{key}};
65		my $lainfo = LT::LaFile->parse($self->{lafile});
66		my $dlname = $lainfo->{dlname};
67		my $oldlib = $lainfo->{old_library};
68		my $libdir = $lainfo->{libdir};
69		my $installed = $lainfo->{installed};
70		my $d = abs_dir($self->{lafile});
71		# get the name we need (this may include a -release)
72		if (!$dlname && !$oldlib) {
73			die "Link error: neither static nor shared library found in $self->{lafile}\n";
74		}
75		if ($d !~ m/\Q$ltdir\E$/ && $installed eq 'no') {
76			$d .= "/$ltdir";
77		}
78		if ($shared) {
79			if ($dlname) {
80				$libfile = "$d/$dlname";
81			} else {
82				# fall back to static
83				$libfile = "$d/$oldlib";
84			}
85			# if -static has been passed, don't link dynamically
86			# against not-installed libraries
87			if ($staticflag && $installed eq 'no') {
88				$libfile = "$d/$oldlib";
89			}
90		} else {
91			$libfile = "$d/$oldlib";
92		}
93		if (! -f $libfile) {
94			tsay {".la file ", $self->{lafile},
95			    "points to nonexistent file ", $libfile, " !"};
96		}
97	} else {
98		# search in .libs when priority is high
99		push @$dirs, $gp->libsearchdirs if $gp;
100		tsay {"searching for $libtofind"};
101		tsay {"search path= ", join(':', @$dirs)};
102		tsay {"search type= ", $shared ? 'shared' : 'static'};
103		foreach my $sd (@$dirs) {
104			if ($shared) {
105				# select correct library by sorting by version number only
106				my $bestlib = $self->findbest($sd, $libtofind);
107				if ($bestlib) {
108					tsay {"found $libtofind in $sd"};
109					$libfile = $bestlib;
110					last;
111				} else {
112					# XXX find static library instead?
113					my $spath = "$sd/lib$libtofind$pic.a";
114					if (-f $spath) {
115						tsay {"found static $libtofind in $sd"};
116						$libfile = $spath;
117						last;
118					}
119				}
120			} else {
121				# look for a static library
122				my $spath = "$sd/lib$libtofind.a";
123				if (-f $spath) {
124					tsay {"found static $libtofind in $sd"};
125					$libfile = $spath;
126					last;
127				}
128			}
129		}
130	}
131	if (!$libfile) {
132		delete $self->{fullpath};
133		if ($linkmode eq 'LT::LaFile') {
134			say "warning: dependency on $libtofind dropped";
135			$self->{dropped} = 1;
136		} elsif ($linkmode eq 'LT::Program') {
137			die "Link error: $libtofind not found!\n";
138		}
139	} else {
140		$self->{fullpath} = $libfile;
141		tsay {"\$libs->{$self->{key}}->{fullpath} = ",
142		    $self->{fullpath}};
143	}
144}
145
146sub findbest
147{
148	my ($self, $sd, $name) = @_;
149	my $best = undef;
150	if (opendir(my $dir, $sd)) {
151		my ($major, $minor) = (-1, -1);
152		while (my $e = readdir($dir)) {
153			next unless $e =~ m/^lib\Q$name\E\.so\.(\d+)\.(\d+)$/;
154			if ($1 > $major || ($1 == $major && $2 > $minor)) {
155				($major, $minor) = ($1, $2);
156				$best = "$sd/$e";
157			}
158		}
159		closedir($dir);
160	}
161	if (!defined $best) {
162		my $cand = "$sd/lib$name.so";
163		if (-e $cand) {
164			$best = $cand;
165		}
166	}
167	return $best;
168}
169
170# give a list of library dependencies found in the actual shared library
171sub inspect
172{
173	my $self = shift;
174
175	my $filename = $self->{fullpath};
176	my @deps;
177
178	if (!defined($filename)){
179		say "warning: library was specified that could not be found: $self->{key}";
180		return;
181	}
182	tsay {"inspecting $filename for library dependencies..."};
183	open(my $fh, '-|', "objdump", "-p", "--", $filename);
184	while (<$fh>) {
185		if (m/\s+NEEDED\s+(\S+)\s*$/) {
186			push @deps, $1;
187		}
188	}
189	tsay {"found ", (@deps == 0) ? 'no ' : '',
190		"deps for $filename\n@deps"};
191	return @deps;
192}
193
194# give the list of RPATH/RUNPATH directories
195sub findrpaths
196{
197	my $self = shift;
198
199	my $filename = $self->{fullpath};
200	my @dirs;
201
202	if (!defined($filename)){
203		say "warning: library was specified that could not be found: $self->{key}";
204		return;
205	}
206	tsay {"inspecting $filename for non standard RPATH/RUNPATH..."};
207	open(my $fh, '-|', "objdump", "-p", "--", $filename);
208	while (<$fh>) {
209		if (m/R(?:UN)?PATH\s+(.*)$/) {
210			@dirs = split(":", $1);
211			last;
212		}
213	}
214	tsay {"found ", (@dirs == 0) ? 'none ' : '',
215		"RPATH/RUNPATH for $filename\n@dirs"};
216	return @dirs;
217}
218
219sub new
220{
221	my ($class, $key) = @_;
222	bless { key => $key }, $class;
223}
224
2251;
226