xref: /openbsd-src/usr.bin/libtool/LT/Library.pm (revision 0a6aab58a9ecdd9d26650fde0b817a724ac8dbc6)
1*0a6aab58Sespie# $OpenBSD: Library.pm,v 1.14 2023/07/08 08:15:32 espie Exp $
2dd9b5fdeSespie
3dd9b5fdeSespie# Copyright (c) 2007-2010 Steven Mestdagh <steven@openbsd.org>
4b8664c47Sespie# Copyright (c) 2012 Marc Espie <espie@openbsd.org>
5dd9b5fdeSespie#
6dd9b5fdeSespie# Permission to use, copy, modify, and distribute this software for any
7dd9b5fdeSespie# purpose with or without fee is hereby granted, provided that the above
8dd9b5fdeSespie# copyright notice and this permission notice appear in all copies.
9dd9b5fdeSespie#
10dd9b5fdeSespie# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11dd9b5fdeSespie# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12dd9b5fdeSespie# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13dd9b5fdeSespie# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14dd9b5fdeSespie# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15dd9b5fdeSespie# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16dd9b5fdeSespie# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17dd9b5fdeSespie
18*0a6aab58Sespieuse v5.36;
19dd9b5fdeSespie
20ce8e7994Sespiepackage LT::Library::Stash;
21ce8e7994Sespie
22*0a6aab58Sespiesub new($class)
23ce8e7994Sespie{
24ce8e7994Sespie	bless {}, $class;
25ce8e7994Sespie}
26ce8e7994Sespie
27*0a6aab58Sespiesub create($self, $key)
28ce8e7994Sespie{
29ce8e7994Sespie	if (!exists $self->{$key}) {
30ce8e7994Sespie		$self->{$key} = LT::Library->new($key);
31ce8e7994Sespie	}
32ce8e7994Sespie	return $self->{$key};
33ce8e7994Sespie}
34ce8e7994Sespie
35dd9b5fdeSespiepackage LT::Library;
36dd9b5fdeSespie
37dd9b5fdeSespieuse LT::Util;
38f98ddbc5Sespieuse LT::Trace;
39dd9b5fdeSespie
40dd9b5fdeSespie# find actual library filename
41dd9b5fdeSespie# XXX pick the right one if multiple are found!
42*0a6aab58Sespiesub resolve_library($self, $dirs, $shared, $staticflag, $linkmode, $gp = undef)
43dd9b5fdeSespie{
44dd9b5fdeSespie
45dd9b5fdeSespie	my $libtofind = $self->{key};
46dd9b5fdeSespie	my $libfile = 0;
47dd9b5fdeSespie	my @globbedlib;
48dd9b5fdeSespie
49dd9b5fdeSespie	my $pic = '';	# used when finding static libraries
502417ebc9Sespie	if ($linkmode eq 'LT::LaFile') {
51dd9b5fdeSespie		$pic = '_pic';
52dd9b5fdeSespie	}
53dd9b5fdeSespie
54dd9b5fdeSespie	if (defined $self->{lafile}) {
55dd9b5fdeSespie		require LT::LaFile;
56dd9b5fdeSespie		# if there is a .la file, use the info from there
57f98ddbc5Sespie		tsay {"found .la file $self->{lafile} for library key: ",
58f98ddbc5Sespie		    $self->{key}};
59dd9b5fdeSespie		my $lainfo = LT::LaFile->parse($self->{lafile});
6083989ecdSespie		my $dlname = $lainfo->{dlname};
6183989ecdSespie		my $oldlib = $lainfo->{old_library};
6283989ecdSespie		my $libdir = $lainfo->{libdir};
6383989ecdSespie		my $installed = $lainfo->{installed};
64dd9b5fdeSespie		my $d = abs_dir($self->{lafile});
65dd9b5fdeSespie		# get the name we need (this may include a -release)
66dd9b5fdeSespie		if (!$dlname && !$oldlib) {
67dd9b5fdeSespie			die "Link error: neither static nor shared library found in $self->{lafile}\n";
68dd9b5fdeSespie		}
69dd9b5fdeSespie		if ($d !~ m/\Q$ltdir\E$/ && $installed eq 'no') {
70dd9b5fdeSespie			$d .= "/$ltdir";
71dd9b5fdeSespie		}
72dd9b5fdeSespie		if ($shared) {
73dd9b5fdeSespie			if ($dlname) {
74dd9b5fdeSespie				$libfile = "$d/$dlname";
75dd9b5fdeSespie			} else {
76dd9b5fdeSespie				# fall back to static
77dd9b5fdeSespie				$libfile = "$d/$oldlib";
78dd9b5fdeSespie			}
79dd9b5fdeSespie			# if -static has been passed, don't link dynamically
80dd9b5fdeSespie			# against not-installed libraries
81dd9b5fdeSespie			if ($staticflag && $installed eq 'no') {
82dd9b5fdeSespie				$libfile = "$d/$oldlib";
83dd9b5fdeSespie			}
84dd9b5fdeSespie		} else {
85dd9b5fdeSespie			$libfile = "$d/$oldlib";
86dd9b5fdeSespie		}
87dd9b5fdeSespie		if (! -f $libfile) {
88f98ddbc5Sespie			tsay {".la file ", $self->{lafile},
89f98ddbc5Sespie			    "points to nonexistent file ", $libfile, " !"};
90dd9b5fdeSespie		}
91dd9b5fdeSespie	} else {
92dd9b5fdeSespie		# search in .libs when priority is high
93*0a6aab58Sespie		push @$dirs, $gp->libsearchdirs if defined $gp;
94f98ddbc5Sespie		tsay {"searching for $libtofind"};
95807ec17aSzhuk		tsay {"search path= ", join(':', @$dirs)};
96f98ddbc5Sespie		tsay {"search type= ", $shared ? 'shared' : 'static'};
97807ec17aSzhuk		foreach my $sd (@$dirs) {
98dd9b5fdeSespie			if ($shared) {
99dd9b5fdeSespie				# select correct library by sorting by version number only
10083989ecdSespie				my $bestlib = $self->findbest($sd, $libtofind);
10183989ecdSespie				if ($bestlib) {
102f98ddbc5Sespie					tsay {"found $libtofind in $sd"};
10383989ecdSespie					$libfile = $bestlib;
104dd9b5fdeSespie					last;
10583989ecdSespie				} else {
10683989ecdSespie					# XXX find static library instead?
107dd9b5fdeSespie					my $spath = "$sd/lib$libtofind$pic.a";
108dd9b5fdeSespie					if (-f $spath) {
109f98ddbc5Sespie						tsay {"found static $libtofind in $sd"};
110dd9b5fdeSespie						$libfile = $spath;
111dd9b5fdeSespie						last;
112dd9b5fdeSespie					}
113dd9b5fdeSespie				}
114dd9b5fdeSespie			} else {
115dd9b5fdeSespie				# look for a static library
116dd9b5fdeSespie				my $spath = "$sd/lib$libtofind.a";
117dd9b5fdeSespie				if (-f $spath) {
118f98ddbc5Sespie					tsay {"found static $libtofind in $sd"};
119dd9b5fdeSespie					$libfile = $spath;
120dd9b5fdeSespie					last;
121dd9b5fdeSespie				}
122dd9b5fdeSespie			}
123dd9b5fdeSespie		}
124dd9b5fdeSespie	}
125dd9b5fdeSespie	if (!$libfile) {
12683989ecdSespie		delete $self->{fullpath};
1272417ebc9Sespie		if ($linkmode eq 'LT::LaFile') {
128dd9b5fdeSespie			say "warning: dependency on $libtofind dropped";
129dd9b5fdeSespie			$self->{dropped} = 1;
1302417ebc9Sespie		} elsif ($linkmode eq 'LT::Program') {
131dd9b5fdeSespie			die "Link error: $libtofind not found!\n";
132dd9b5fdeSespie		}
133dd9b5fdeSespie	} else {
134dd9b5fdeSespie		$self->{fullpath} = $libfile;
135f98ddbc5Sespie		tsay {"\$libs->{$self->{key}}->{fullpath} = ",
136f98ddbc5Sespie		    $self->{fullpath}};
137dd9b5fdeSespie	}
138dd9b5fdeSespie}
139dd9b5fdeSespie
140*0a6aab58Sespiesub findbest($self, $sd, $name)
14183989ecdSespie{
14283989ecdSespie	my $best = undef;
14383989ecdSespie	if (opendir(my $dir, $sd)) {
14483989ecdSespie		my ($major, $minor) = (-1, -1);
14528252c27Safresh1		while (my $e = readdir($dir)) {
14628252c27Safresh1			next unless $e =~ m/^lib\Q$name\E\.so\.(\d+)\.(\d+)$/;
14783989ecdSespie			if ($1 > $major || ($1 == $major && $2 > $minor)) {
14883989ecdSespie				($major, $minor) = ($1, $2);
14928252c27Safresh1				$best = "$sd/$e";
15083989ecdSespie			}
15183989ecdSespie		}
15283989ecdSespie		closedir($dir);
15383989ecdSespie	}
154f60f8b41Sajacoutot	if (!defined $best) {
155f60f8b41Sajacoutot		my $cand = "$sd/lib$name.so";
156f60f8b41Sajacoutot		if (-e $cand) {
157f60f8b41Sajacoutot			$best = $cand;
158f60f8b41Sajacoutot		}
159f60f8b41Sajacoutot	}
16083989ecdSespie	return $best;
16183989ecdSespie}
16283989ecdSespie
163dd9b5fdeSespie# give a list of library dependencies found in the actual shared library
164*0a6aab58Sespiesub inspect($self)
165dd9b5fdeSespie{
166dd9b5fdeSespie	my $filename = $self->{fullpath};
167dd9b5fdeSespie	my @deps;
168dd9b5fdeSespie
169dd9b5fdeSespie	if (!defined($filename)){
170dd9b5fdeSespie		say "warning: library was specified that could not be found: $self->{key}";
171dd9b5fdeSespie		return;
172dd9b5fdeSespie	}
173f98ddbc5Sespie	tsay {"inspecting $filename for library dependencies..."};
1743c6e63d9Sespie	open(my $fh, '-|', "objdump", "-p", "--", $filename);
175dd9b5fdeSespie	while (<$fh>) {
176dd9b5fdeSespie		if (m/\s+NEEDED\s+(\S+)\s*$/) {
177dd9b5fdeSespie			push @deps, $1;
178dd9b5fdeSespie		}
179dd9b5fdeSespie	}
180f98ddbc5Sespie	tsay {"found ", (@deps == 0) ? 'no ' : '',
181f98ddbc5Sespie		"deps for $filename\n@deps"};
182dd9b5fdeSespie	return @deps;
183dd9b5fdeSespie}
184dd9b5fdeSespie
18534dd3883Snaddy# give the list of RPATH/RUNPATH directories
186*0a6aab58Sespiesub findrpaths($self)
187f60f8b41Sajacoutot{
188f60f8b41Sajacoutot	my $filename = $self->{fullpath};
189f60f8b41Sajacoutot	my @dirs;
190f60f8b41Sajacoutot
191f60f8b41Sajacoutot	if (!defined($filename)){
192f60f8b41Sajacoutot		say "warning: library was specified that could not be found: $self->{key}";
193f60f8b41Sajacoutot		return;
194f60f8b41Sajacoutot	}
19534dd3883Snaddy	tsay {"inspecting $filename for non standard RPATH/RUNPATH..."};
196f60f8b41Sajacoutot	open(my $fh, '-|', "objdump", "-p", "--", $filename);
197f60f8b41Sajacoutot	while (<$fh>) {
19834dd3883Snaddy		if (m/R(?:UN)?PATH\s+(.*)$/) {
199f60f8b41Sajacoutot			@dirs = split(":", $1);
200f60f8b41Sajacoutot			last;
201f60f8b41Sajacoutot		}
202f60f8b41Sajacoutot	}
203f60f8b41Sajacoutot	tsay {"found ", (@dirs == 0) ? 'none ' : '',
20434dd3883Snaddy		"RPATH/RUNPATH for $filename\n@dirs"};
205f60f8b41Sajacoutot	return @dirs;
206f60f8b41Sajacoutot}
207f60f8b41Sajacoutot
208*0a6aab58Sespiesub new($class, $key)
209dd9b5fdeSespie{
210dd9b5fdeSespie	bless { key => $key }, $class;
211dd9b5fdeSespie}
212dd9b5fdeSespie
213dd9b5fdeSespie1;
214