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