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