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