xref: /openbsd-src/usr.bin/libtool/LT/Library.pm (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1# $OpenBSD: Library.pm,v 1.8 2012/07/13 11:56:12 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 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		# otherwise, search the filesystem
99		# sort dir search order by priority
100		# XXX not fully correct yet
101		my @sdirs = sort { $dirs->{$b} <=> $dirs->{$a} } keys %$dirs;
102		# search in .libs when priority is high
103		map { $_ = "$_/$ltdir" if (exists $dirs->{$_} && $dirs->{$_} > 3) } @sdirs;
104		push @sdirs, $gp->libsearchdirs if $gp;
105		tsay {"searching for $libtofind"};
106		tsay {"search path= ", join(':', @sdirs)};
107		tsay {"search type= ", $shared ? 'shared' : 'static'};
108		foreach my $sd (@sdirs) {
109		       if ($shared) {
110				# select correct library by sorting by version number only
111				my $bestlib = $self->findbest($sd, $libtofind);
112				if ($bestlib) {
113					tsay {"found $libtofind in $sd"};
114					$libfile = $bestlib;
115					last;
116				} else {
117					# XXX find static library instead?
118					my $spath = "$sd/lib$libtofind$pic.a";
119					if (-f $spath) {
120						tsay {"found static $libtofind in $sd"};
121						$libfile = $spath;
122						last;
123					}
124				}
125		       } else {
126				# look for a static library
127				my $spath = "$sd/lib$libtofind.a";
128				if (-f $spath) {
129					tsay {"found static $libtofind in $sd"};
130					$libfile = $spath;
131					last;
132				}
133		       }
134		}
135	}
136	if (!$libfile) {
137		delete $self->{fullpath};
138		if ($linkmode eq 'LT::LaFile') {
139			say "warning: dependency on $libtofind dropped";
140			$self->{dropped} = 1;
141		} elsif ($linkmode eq 'LT::Program') {
142			die "Link error: $libtofind not found!\n";
143		}
144	} else {
145		$self->{fullpath} = $libfile;
146		tsay {"\$libs->{$self->{key}}->{fullpath} = ",
147		    $self->{fullpath}};
148	}
149}
150
151sub findbest
152{
153	my ($self, $sd, $name) = @_;
154	my $best = undef;
155	if (opendir(my $dir, $sd)) {
156		my ($major, $minor) = (-1, -1);
157		while (my $_ = readdir($dir)) {
158			next unless m/^lib\Q$name\E\.so\.(\d+)\.(\d+)$/;
159			if ($1 > $major || ($1 == $major && $2 > $minor)) {
160				($major, $minor) = ($1, $2);
161				$best = "$sd/$_";
162			}
163		}
164		closedir($dir);
165	}
166	return $best;
167}
168
169# give a list of library dependencies found in the actual shared library
170sub inspect
171{
172	my $self = shift;
173
174	my $filename = $self->{fullpath};
175	my @deps;
176
177	if (!defined($filename)){
178		say "warning: library was specified that could not be found: $self->{key}";
179		return;
180	}
181	tsay {"inspecting $filename for library dependencies..."};
182	open(my $fh, '-|', "objdump", "-p", "--", $filename);
183	while (<$fh>) {
184		if (m/\s+NEEDED\s+(\S+)\s*$/) {
185			push @deps, $1;
186		}
187	}
188	tsay {"found ", (@deps == 0) ? 'no ' : '',
189		"deps for $filename\n@deps"};
190	return @deps;
191}
192
193sub new
194{
195	my ($class, $key) = @_;
196	bless { key => $key }, $class;
197}
198
1991;
200