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