move most of libtool code around.

This commit is contained in:
espie 2010-12-05 16:37:50 +00:00
parent d4a6a13505
commit 9ed0d9cd66
10 changed files with 1446 additions and 0 deletions

View File

@ -0,0 +1,78 @@
# $OpenBSD: Archive.pm,v 1.1 2010/12/05 16:37:50 espie Exp $
# Copyright (c) 2007-2010 Steven Mestdagh <steven@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use strict;
use warnings;
use feature qw(say switch state);
package Archive;
use Trace;
use Exec;
use Util;
sub extract
{
my ($self, $dir, $archive) = @_;
if (! -d $dir) {
Trace::debug {"mkdir -p $dir\n"};
File::Path::mkpath($dir);
}
Exec->chdir($dir)->command('ar', 'x', $archive);
}
sub get_objlist
{
my ($self, $a) = @_;
open(my $arh, '-|', 'ar', 't', $a);
my @o = <$arh>;
close $arh;
map { chomp; } @o;
return @o;
}
sub get_symbollist
{
my ($self, $filepath, $regex, $objlist) = @_;
if (@$objlist == 0) {
die "get_symbollist: object list is empty\n";
}
Trace::debug {"generating symbol list in file: $filepath\n"};
my $symbols = [];
open(my $sh, '-|', 'nm', @$objlist) or die "Error running nm on object list\n";
my $c = 0;
while (my $line = <$sh>) {
chomp $line;
Trace::debug {"$c: $line\n"};
if ($line =~ m/\S+\s+[BCDEGRST]\s+(.*)/) {
my $s = $1;
if ($s =~ m/$regex/) {
push @$symbols, $s;
Trace::debug {"matched\n"};
}
}
$c++;
}
$symbols = reverse_zap_duplicates_ref($symbols);
@$symbols = sort @$symbols;
open(my $fh, '>', $filepath) or die "Cannot open $filepath\n";
print $fh join("\n", @$symbols), "\n";
}
1;

View File

@ -0,0 +1,115 @@
# $OpenBSD: Exec.pm,v 1.1 2010/12/05 16:37:50 espie Exp $
# Copyright (c) 2007-2010 Steven Mestdagh <steven@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use strict;
use warnings;
use feature qw(say switch state);
package Exec;
my $dry = 0;
my $verbose = 0;
my $performed = 0;
sub performed
{
return $performed;
}
sub dry_run
{
$dry = 1;
}
sub verbose_run
{
$verbose = 1;
}
sub silent_run
{
$verbose = 0;
}
sub new
{
my $class = shift;
bless {}, $class;
}
sub chdir
{
my ($self, $dir) = @_;
my $class = ref($self) || $self;
bless {dir => $dir}, $class;
}
sub command_run
{
my ($self, @l) = @_;
if ($self->{dir}) {
Trace::print {"cd $self->{dir} && "};
}
Trace::print { "@l\n" };
my $pid = fork();
if ($pid == -1) {
die "Couldn't fork while running @l\n";
}
if ($pid == 0) {
if ($self->{dir}) {
CORE::chdir($self->{dir}) or die "Can't chdir to $self->{dir}\n";
}
exec(@l);
die "Exec failed @l\n";
} else {
my $kid = waitpid($pid, 0);
if ($? != 0) {
die "Error while executing @l\n";
}
}
}
sub shell
{
my ($self, @cmds) = @_;
# create an object "on the run"
if (!ref($self)) {
$self = $self->new;
}
for my $c (@cmds) {
say $c if $verbose || $dry;
if (!$dry) {
$self->command_run($c);
}
}
$performed++;
}
sub command
{
my ($self, @l) = @_;
# create an object "on the run"
if (!ref($self)) {
$self = $self->new;
}
say "@l" if $verbose || $dry;
if (!$dry) {
$self->command_run(@l);
}
$performed++;
}
1;

View File

@ -0,0 +1,340 @@
# $OpenBSD: LaFile.pm,v 1.1 2010/12/05 16:37:50 espie Exp $
# Copyright (c) 2007-2010 Steven Mestdagh <steven@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use strict;
use warnings;
use feature qw(say switch state);
package LaFile;
use parent qw(LaLoFile);
use File::Basename;
use Archive;
use Util;
# allows special treatment for some keywords
sub set
{
my ($self, $k, $v) = @_;
$self->SUPER::set($k, $v);
if ($k eq 'dependency_libs') {
my @l = split /\s+/, $v;
$self->{deplib_list} = \@l;
}
}
sub deplib_list
{
my $self = shift;
return $self->{deplib_list}
}
# XXX not sure how much of this cruft we need
sub write
{
my ($lainfo, $filename, $name) = @_;
my $libname = $lainfo->stringize('libname');
my $sharedlibname = $lainfo->stringize('dlname');
my $staticlibname = $lainfo->stringize('old_library');
my $librarynames = $lainfo->stringize('library_names');
my $deplibs = $lainfo->stringize('dependency_libs');
my $current = $lainfo->stringize('current');
my $revision = $lainfo->stringize('revision');
my $age = $lainfo->stringize('age');
my $installed = $lainfo->stringize('installed');
my $shouldnotlink = $lainfo->stringize('shouldnotlink');
my $libdir = $lainfo->stringize('libdir');
open(my $la, '>', $filename) or die "Cannot write $filename: $!\n";
say "creating $filename" if $main::verbose || $main::D;
print $la <<EOF
# $name - libtool library file
# Generated by libtool $version
#
# Please DO NOT delete this file!
# It is necessary for linking the library.
# The name that we can dlopen(3).
dlname='$sharedlibname'
# Names of this library.
library_names='$librarynames'
# The name of the static archive.
old_library='$staticlibname'
# Libraries that this one depends upon.
dependency_libs='$deplibs'
# Version information for $libname.
current=$current
age=$age
revision=$revision
# Is this an already installed library?
installed=$installed
# Should we warn about portability when linking against -modules?
shouldnotlink=$shouldnotlink
# Files to dlopen/dlpreopen
dlopen=''
dlpreopen=''
# Directory that this library needs to be installed in:
libdir='$libdir'
EOF
;
}
sub write_shared_libs_log
{
my ($self, $origv) = @_;
my $libname = $self->stringize('libname');
my $v = $self->stringize('current') .'.'. $self->stringize('revision');
if (!defined $ENV{'SHARED_LIBS_LOG'}) {
return;
}
my $logfile = $ENV{'SHARED_LIBS_LOG'};
my $fh;
if (! -f $logfile) {
open ($fh, '>', $logfile);
print $fh "# SHARED_LIBS+= <libname> <obsd version> # <orig version>\n";
close $fh;
}
open ($fh, '>>', $logfile);
# Remove first leading 'lib', we don't want that in SHARED_LIBS_LOG.
$libname =~ s/^lib//;
printf $fh "SHARED_LIBS +=\t%-20s %-8s # %s\n", $libname, $v, $origv;
}
# find .la file associated with a -llib flag
# XXX pick the right one if multiple are found!
sub find
{
my ($self, $l, $dirs) = @_;
# sort dir search order by priority
# XXX not fully correct yet
my @sdirs = sort { $dirs->{$b} <=> $dirs->{$a} } keys %$dirs;
# search in cwd as well
unshift @sdirs, '.';
Trace::debug {"searching .la for $l\n"};
Trace::debug {"search path= ", join(':', @sdirs), "\n"};
foreach my $d (@sdirs) {
foreach my $la_candidate ("$d/lib$l.la", "$d/$l.la") {
if (-f $la_candidate) {
Trace::debug {"found $la_candidate\n"};
return $la_candidate;
}
}
}
Trace::debug {".la for $l not found!\n"};
return 0;
}
sub link
{
my ($self, $ltprog, $la, $fname, $odir, $shared, $objs, $dirs,
$libs, $deplibs, $libdirs, $parser, $opts) = @_;
Trace::debug {"creating link command for library (linked ",
($shared) ? "dynam" : "stat", "ically)\n"};
my $what = ref($self);
my @libflags;
my @cmd;
my $dst = ($odir eq '.') ? "$ltdir/$fname" : "$odir/$ltdir/$fname";
if ($la =~ m/\.a$/) {
# probably just a convenience library
$dst = ($odir eq '.') ? "$fname" : "$odir/$fname";
}
my $symlinkdir = $ltdir;
if ($odir ne '.') {
$symlinkdir = "$odir/$ltdir";
}
mkdir $symlinkdir if (! -d $symlinkdir);
Trace::debug {"argvstring (pre resolve_la): @{$parser->{args}}\n"};
my $args = $parser->resolve_la($deplibs, $libdirs);
Trace::debug {"argvstring (post resolve_la): @{$parser->{args}}\n"};
my $orderedlibs = [];
my $staticlibs = [];
$parser->{args} = $args;
$args = $parser->parse_linkargs2(\@main::Rresolved,
\@main::libsearchdirs, $orderedlibs, $staticlibs, $dirs, $libs);
Trace::debug {"staticlibs = \n", join("\n", @$staticlibs), "\n"};
Trace::debug {"orderedlibs = @$orderedlibs\n"};
my $finalorderedlibs = reverse_zap_duplicates_ref($orderedlibs);
Trace::debug {"final orderedlibs = @$finalorderedlibs\n"};
# static linking
if (!$shared) {
@cmd = ('ar', 'cru', $dst);
foreach my $a (@$staticlibs) {
if ($a =~ m/\.a$/ && $a !~ m/_pic\.a/) {
# extract objects from archive
my $libfile = basename $a;
my $xdir = "$odir/$ltdir/${la}x/$libfile";
Archive->extract($xdir, $a);
my @kobjs = Archive->get_objlist($a);
map { $_ = "$xdir/$_"; } @kobjs;
push @libflags, @kobjs;
}
}
foreach my $k (@$finalorderedlibs) {
my $l = $libs->{$k};
# XXX improve test
# this has to be done probably only with
# convenience libraries
next if !defined $l->{lafile};
my $lainfo = LaFile->parse($l->{lafile});
next if ($lainfo->stringize('dlname') ne '');
$l->find($dirs, 0, 0, $what);
my $a = $l->{fullpath};
if ($a =~ m/\.a$/ && $a !~ m/_pic\.a/) {
# extract objects from archive
my $libfile = basename $a;
my $xdir = "$odir/$ltdir/${la}x/$libfile";
Archive->extract($xdir, $a);
my @kobjs = Archive->get_objlist($a);
map { $_ = "$xdir/$_"; } @kobjs;
push @libflags, @kobjs;
}
}
push @cmd, @libflags if (@libflags);
push @cmd, @$objs if (@$objs);
Exec->command(@cmd);
Exec->command('ranlib', $dst);
return;
}
# dynamic linking
my $symbolsfile;
if ($opts->{'export-symbols'}) {
$symbolsfile = $opts->{'export-symbols'};
} elsif ($opts->{'export-symbols-regex'}) {
($symbolsfile = "$odir/$ltdir/$la") =~ s/\.la$/.exp/;
Archive->get_symbollist($symbolsfile, $opts->{'export-symbols-regex'}, $objs);
}
my $tmp = [];
while (my $k = shift @$finalorderedlibs) {
my $l = $libs->{$k};
$l->find($dirs, 1, $opts->{'static'}, $what);
if ($l->{dropped}) {
# remove library if dependency on it has been dropped
delete $libs->{$k};
} else {
push(@$tmp, $k);
}
}
$finalorderedlibs = $tmp;
my @libobjects = values %$libs;
Trace::debug {"libs:\n", join("\n", (keys %$libs)), "\n"};
Trace::debug {"libfiles:\n", join("\n", map { $_->{fullpath}//'UNDEF' } @libobjects), "\n"};
main::create_symlinks($symlinkdir, $libs);
my $prev_was_archive = 0;
my $libcounter = 0;
foreach my $k (@$finalorderedlibs) {
my $a = $libs->{$k}->{fullpath} || die "Link error: $k not found in \$libs\n";
if ($a =~ m/\.a$/) {
# don't make a -lfoo out of a static library
push @libflags, '-Wl,-whole-archive' unless $prev_was_archive;
push @libflags, $a;
if ($libcounter == @$finalorderedlibs - 1) {
push @libflags, '-Wl,-no-whole-archive';
}
$prev_was_archive = 1;
} else {
push @libflags, '-Wl,-no-whole-archive' if $prev_was_archive;
$prev_was_archive = 0;
my $lib = basename $a;
if ($lib =~ m/^lib(.*)\.so(\.\d+){2}/) {
$lib = $1;
} else {
say "warning: cannot derive -l flag from library filename, assuming hash key";
$lib = $k;
}
push @libflags, "-l$lib";
}
$libcounter++;
}
@cmd = @$ltprog;
push @cmd, $sharedflag, @picflags;
push @cmd, '-o', $dst;
push @cmd, @$args if ($args);
push @cmd, @$objs if (@$objs);
push @cmd, '-Wl,-whole-archive', @$staticlibs, '-Wl,-no-whole-archive'
if (@$staticlibs);
push @cmd, "-L$symlinkdir", @libflags if (@libflags);
push @cmd, "-Wl,-retain-symbols-file,$symbolsfile" if ($symbolsfile);
Exec->command(@cmd);
}
sub install
{
my ($class, $src, $dstdir, $instprog, $instopts, $strip) = @_;
my $srcdir = dirname $src;
my $srcfile = basename $src;
my $dstfile = $srcfile;
my @opts = @$instopts;
my @stripopts = ('--strip-debug');
if ($$instprog[-1] =~ m/install([.-]sh)?$/) {
push @opts, '-m', '644';
}
my $lainfo = $class->parse($src);
my $sharedlib = $lainfo->{'dlname'};
my $staticlib = $lainfo->{'old_library'};
my $laipath = "$srcdir/$ltdir/$srcfile".'i';
if ($staticlib) {
# do not strip static libraries, this is done below
my @realinstopts = @opts;
@realinstopts = grep { $_ ne '-s' } @realinstopts;
my $s = "$srcdir/$ltdir/$staticlib";
my $d = "$dstdir/$staticlib";
Exec->command(@$instprog, @realinstopts, $s, $d);
Exec->command('strip', @stripopts, $d) if ($strip);
}
if ($sharedlib) {
my $s = "$srcdir/$ltdir/$sharedlib";
my $d = "$dstdir/$sharedlib";
Exec->command(@$instprog, @opts, $s, $d);
}
if ($laipath) {
# do not try to strip .la files
my @realinstopts = @opts;
@realinstopts = grep { $_ ne '-s' } @realinstopts;
my $s = $laipath;
my $d = "$dstdir/$dstfile";
Exec->command(@$instprog, @realinstopts, $s, $d);
}
# for libraries with a -release in their name
my @libnames = split /\s+/, $lainfo->{'library_names'};
foreach my $n (@libnames) {
next if ($n eq $sharedlib);
unlink("$dstdir/$n");
symlink($sharedlib, "$dstdir/$n");
}
}
1;

View File

@ -0,0 +1,88 @@
# $OpenBSD: LaLoFile.pm,v 1.1 2010/12/05 16:37:50 espie Exp $
# Copyright (c) 2007-2010 Steven Mestdagh <steven@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use strict;
use warnings;
use feature qw(say switch state);
package LaLoFile;
my %file_cache; # which files have been parsed
my $cache_by_fullname = {};
my $cache_by_inode = {};
# allows special treatment for some keywords
sub set
{
my ($self, $k, $v) = @_;
$self->{$k} = $v;
}
sub stringize
{
my ($self, $k) = @_;
if (defined $self->{$k}) {
return $self->{$k};
}
return '';
}
sub read
{
my ($class, $filename) = @_;
my $info = $class->new;
open(my $fh, '<', $filename) or die "Cannot read $filename: $!\n";
my $_;
while (<$fh>) {
chomp;
next if /^\#/;
next if /^\s*$/;
if (m/^(\S+)\=\'(.*)\'$/) {
$info->set($1, $2);
} elsif (m/^(\S+)\=(\S+)$/) {
$info->set($1, $2);
}
}
return $info;
}
sub parse
{
my ($class, $filename) = @_;
Trace::debug {"parsing $filename"};
if (defined $cache_by_fullname->{$filename}) {
Trace::debug {" (cached)\n"};
return $cache_by_fullname->{$filename};
}
my $key = join("/", (stat $filename)[0,1]);
if (defined $cache_by_inode->{$key}) {
Trace::debug {" (cached)\n"};
return $cache_by_inode->{$key};
}
Trace::debug {"\n"};
return $cache_by_inode->{$key} = $cache_by_fullname->{$filename} =
$class->read($filename);
}
sub new
{
my $class = shift;
bless {}, $class;
}
1;

View File

@ -0,0 +1,154 @@
# $OpenBSD: Library.pm,v 1.1 2010/12/05 16:37:50 espie Exp $
# Copyright (c) 2007-2010 Steven Mestdagh <steven@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use strict;
use warnings;
use feature qw(say switch state);
package Library;
use Util;
# find actual library filename
# XXX pick the right one if multiple are found!
sub find
{
my ($self, $dirs, $shared, $staticflag, $linkmode, $ldconfigdirs) = @_;
my $libtofind = $self->{key};
my $libfile = 0;
my @globbedlib;
my $pic = ''; # used when finding static libraries
if ($linkmode eq 'LaFile') {
$pic = '_pic';
}
if (defined $self->{lafile}) {
require LaFile;
# if there is a .la file, use the info from there
Trace::debug {"found .la file $self->{lafile} for library key: $self->{key}\n"};
my $lainfo = LaFile->parse($self->{lafile});
my $dlname = $lainfo->{'dlname'};
my $oldlib = $lainfo->{'old_library'};
my $libdir = $lainfo->{'libdir'};
my $installed = $lainfo->{'installed'};
my $d = abs_dir($self->{lafile});
# get the name we need (this may include a -release)
if (!$dlname && !$oldlib) {
die "Link error: neither static nor shared library found in $self->{lafile}\n";
}
if ($d !~ m/\Q$ltdir\E$/ && $installed eq 'no') {
$d .= "/$ltdir";
}
if ($shared) {
if ($dlname) {
$libfile = "$d/$dlname";
} else {
# fall back to static
$libfile = "$d/$oldlib";
}
# if -static has been passed, don't link dynamically
# against not-installed libraries
if ($staticflag && $installed eq 'no') {
$libfile = "$d/$oldlib";
}
} else {
$libfile = "$d/$oldlib";
}
if (! -f $libfile) {
Trace::debug {".la file $self->{lafile} points to nonexistent file $libfile !\n"};
}
} else {
# otherwise, search the filesystem
# sort dir search order by priority
# XXX not fully correct yet
my @sdirs = sort { $dirs->{$b} <=> $dirs->{$a} } keys %$dirs;
# search in .libs when priority is high
map { $_ = "$_/$ltdir" if (exists $dirs->{$_} && $dirs->{$_} > 3) } @sdirs;
push @sdirs, @$ldconfigdirs if ($ldconfigdirs);
Trace::debug {"searching for $libtofind\n"};
Trace::debug {"search path= ", join(':', @sdirs), "\n"};
Trace::debug {"search type= ", ($shared) ? 'shared' : 'static', "\n"};
foreach my $sd (@sdirs) {
if ($shared) {
# select correct library by sorting by version number only
@globbedlib = sort { my ($x,$y) =
map { /\.so\.(\d+\.\d+)$/; $1 } ($a,$b); $y <=> $x }
glob "$sd/lib$libtofind.so.*.*";
if ($globbedlib[0]) {
Trace::debug {"found $libtofind in $sd\n"};
$libfile = $globbedlib[0];
last;
} else { # XXX find static library instead?
my $spath = "$sd/lib$libtofind$pic.a";
if (-f $spath) {
Trace::debug {"found static $libtofind in $sd\n"};
$libfile = $spath;
last;
}
}
} else {
# look for a static library
my $spath = "$sd/lib$libtofind.a";
if (-f $spath) {
Trace::debug {"found static $libtofind in $sd\n"};
$libfile = $spath;
last;
}
}
}
}
if (!$libfile) {
if (defined $self->{fullpath}) { delete $self->{fullpath}; }
if ($linkmode eq 'LaFile') {
say "warning: dependency on $libtofind dropped";
$self->{dropped} = 1;
} elsif ($linkmode eq 'Program') {
die "Link error: $libtofind not found!\n";
}
} else {
$self->{fullpath} = $libfile;
Trace::debug {"\$libs->{$self->{key}}->{fullpath} = ", $self->{fullpath}, "\n"};
}
}
# give a list of library dependencies found in the actual shared library
sub inspect
{
my $self = shift;
my $filename = $self->{fullpath};
my @deps;
Trace::debug {"inspecting $filename for library dependencies...\n"};
open(my $fh, '-|', "objdump -p $filename");
while (<$fh>) {
if (m/\s+NEEDED\s+(\S+)\s*$/) {
push @deps, $1;
}
}
Trace::debug {"found ", (@deps == 0) ? 'no ' : '',
"deps for $filename\n@deps\n"};
return @deps;
}
sub new
{
my ($class, $key) = @_;
bless { key => $key }, $class;
}
1;

View File

@ -0,0 +1,72 @@
# $OpenBSD: LoFile.pm,v 1.1 2010/12/05 16:37:50 espie Exp $
# Copyright (c) 2007-2010 Steven Mestdagh <steven@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use strict;
use warnings;
use feature qw(say switch state);
package LoFile;
use parent qw(LaLoFile);
use File::Basename;
use Util;
# write a libtool object file
sub write
{
my ($self, $filename) = @_;
my $picobj = $self->stringize('picobj');
my $nonpicobj = $self->stringize('nonpicobj');
my $name = basename $filename;
open(my $lo, '>', $filename) or die "Cannot write $filename: $!\n";
say "creating $filename" if $main::verbose || $main::D;
print $lo <<EOF
# $name - a libtool object file
# Generated by libtool $main::version
#
pic_object='$picobj'
non_pic_object='$nonpicobj'
EOF
;
}
sub compile
{
my ($self, $compiler, $odir, $args) = @_;
mkdir "$odir/$ltdir" if (! -d "$odir/$ltdir");
if (defined $self->{picobj}) {
my @cmd = @$compiler;
push @cmd, @$args if (@$args);
push @cmd, @main::picflags, '-o';
my $o = ($odir eq '.') ? '' : "$odir/";
$o .= $self->{picobj};
push @cmd, $o;
Exec->command(@cmd);
}
if (defined $self->{nonpicobj}) {
my @cmd = @$compiler;
push @cmd, @$args if (@$args);
push @cmd, '-o';
my $o = ($odir eq '.') ? '' : "$odir/";
$o .= $self->{nonpicobj};
push @cmd, $o;
Exec->command(@cmd);
}
}
1;

View File

@ -0,0 +1,310 @@
# $OpenBSD: Parser.pm,v 1.1 2010/12/05 16:37:50 espie Exp $
# Copyright (c) 2007-2010 Steven Mestdagh <steven@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use strict;
use warnings;
use feature qw(say switch state);
package Parser;
use File::Basename;
use Cwd qw(abs_path);
use Util;
use Library;
my $calls = 0;
sub internal_resolve_la
{
my ($self, $level, $result, $rdeplibs, $rlibdirs, $args) = @_;
Trace::debug {"resolve level: $level\n"};
my $seen_pthread = 0;
foreach my $a (@$args) {
if ($a eq '-pthread') {
$seen_pthread++;
next;
}
push(@$result, $a);
next if $a !~ m/\.la$/;
require LaFile;
my $lainfo = LaFile->parse($a);
if (!exists $lainfo->{'cached_deplibs'}) {
$lainfo->{'cached_deplibs'} = [];
$lainfo->{'cached_result'} = [];
$lainfo->{'cached_libdirs'} = [];
$lainfo->{'cached_pthread'} =
$self->internal_resolve_la($level+1,
$lainfo->{'cached_result'},
$lainfo->{'cached_deplibs'},
$lainfo->{'cached_libdirs'},
$lainfo->deplib_list);
push(@{$lainfo->{'cached_deplibs'}},
@{$lainfo->deplib_list});
if ($lainfo->{'libdir'} ne '') {
push(@{$lainfo->{'cached_libdirs'}},
$lainfo->{'libdir'});
}
if (@{$lainfo->{'cached_deplibs'}} > 50) {
$lainfo->{'cached_deplibs'} = reverse_zap_duplicates_ref($lainfo->{'cached_deplibs'});
}
if (@{$lainfo->{'cached_libdirs'}} > 50) {
$lainfo->{'cached_libdirs'} = reverse_zap_duplicates_ref($lainfo->{'cached_libdirs'});
}
if (@{$lainfo->{'cached_result'}} > 50) {
$lainfo->{'cached_result'} = reverse_zap_duplicates_ref($lainfo->{'cached_result'});
}
}
$seen_pthread += $lainfo->{'cached_pthread'};
push(@$result, @{$lainfo->{'cached_result'}});
push(@$rdeplibs, @{$lainfo->{'cached_deplibs'}});
push(@$rlibdirs, @{$lainfo->{'cached_libdirs'}});
}
$calls++;
return $seen_pthread;
}
END
{
Trace::print { "Calls to resolve_la: $calls\n" } if $calls;
}
# resolve .la files until a level with empty dependency_libs is reached.
sub resolve_la
{
my ($self, $deplibs, $libdirs) = @_;
$self->{result} = [];
if ($self->internal_resolve_la(0, $self->{result}, $deplibs, $libdirs, $self->{args})) {
unshift(@{$self->{result}}, '-pthread');
unshift(@$deplibs, '-pthread');
}
return $self->{result};
}
# parse link flags and arguments
# eliminate all -L and -l flags in the argument string and add the
# corresponding directories and library names to the dirs/libs hashes.
# fill deplibs, to be taken up as dependencies in the resulting .la file...
# set up a hash for library files which haven't been found yet.
# deplibs are formed by collecting the original -L/-l flags, plus
# any .la files passed on the command line, EXCEPT when the .la file
# does not point to a shared library.
# pass 1
# -Lfoo, -lfoo, foo.a, foo.la
# recursively find .la files corresponding to -l flags; if there is no .la
# file, just inspect the library file itself for any dependencies.
sub parse_linkargs1
{
state $seen_pthread = 0;
my ($self, $deplibs, $Rresolved, $libsearchdirs,
$dirs, $libs, $args, $level) = @_;
Trace::debug {"parse_linkargs1, level: $level\n"};
Trace::debug {" args: @$args\n"};
my $result = $self->{result};
# first read all directories where we can search libraries
foreach my $a (@$args) {
if ($a =~ m/^-L(.*)/) {
if (!exists $dirs->{$1}) {
$dirs->{$1} = 1;
Trace::debug {" adding $a to deplibs\n"} if ($level == 0);
push @$deplibs, $a;
}
}
}
foreach my $a (@$args) {
Trace::debug {" processing $a\n"};
if (!$a || $a eq '' || $a =~ m/^\s+$/) {
# skip empty arguments
} elsif ($a eq '-pthread' && !$seen_pthread) {
# XXX special treatment since it's not a -l flag
push @$deplibs, $a;
$seen_pthread = 1;
push(@$result, $a);
} elsif ($a =~ m/^-L(.*)/) {
# already read earlier, do nothing
} elsif ($a =~ m/^-R(.*)/) {
# -R options originating from .la resolution
# those from @ARGV are in @Ropts
push @$Rresolved, $1;
} elsif ($a =~ m/^-l(\S+)/) {
my @largs = ();
my $key = $1;
if (!exists $libs->{$key}) {
$libs->{$key} = Library->new($key);
require LaFile;
my $lafile = LaFile->find($key, $dirs);
if ($lafile) {
$libs->{$key}->{lafile} = $lafile;
my $absla = abs_path($lafile);
Trace::debug {" adding $absla to deplibs\n"} if ($level == 0);
push @$deplibs, $absla;
push @$result, $lafile;
next;
} else {
$libs->{$key}->find($dirs, 1, 0, 'notyet', $libsearchdirs);
my @deps = $libs->{$key}->inspect;
foreach my $d (@deps) {
my $k = basename $d;
$k =~ s/^(\S+)\.so.*$/$1/;
$k =~ s/^lib//;
push(@largs, "-l$k");
}
}
}
Trace::debug {" adding $a to deplibs\n"} if ($level == 0);
push @$deplibs, $a;
push(@$result, $a);
my $dummy = []; # no need to add deplibs recursively
$self->parse_linkargs1($dummy, $Rresolved,
$libsearchdirs, $dirs, $libs,
\@largs, $level+1) if @largs;
} elsif ($a =~ m/(\S+\/)*(\S+)\.a$/) {
(my $key = $2) =~ s/^lib//;
if (!exists $libs->{$key}) {
$libs->{$key} = Library->new($key);
}
$dirs->{abs_dir($a)} = 1;
$libs->{$key}->{fullpath} = $a;
push(@$result, $a);
} elsif ($a =~ m/(\S+\/)*(\S+)\.la$/) {
(my $key = $2) =~ s/^lib//;
$dirs->{abs_dir($a)} = 1;
my $fulla = abs_path($a);
require LaFile;
my $lainfo = LaFile->parse($fulla);
my $dlname = $lainfo->{'dlname'};
my $oldlib = $lainfo->{'old_library'};
my $libdir = $lainfo->{'libdir'};
if ($dlname ne '') {
if (!exists $libs->{$key}) {
$libs->{$key} = Library->new($key);
$libs->{$key}->{lafile} = $fulla;
}
}
push(@$result, $a);
push(@$deplibs, $fulla) if ($libdir ne '');
} elsif ($a =~ m/(\S+\/)*(\S+)\.so(\.\d+){2}/) {
(my $key = $2) =~ s/^lib//;
$dirs->{abs_dir($a)} = 1;
if (!exists $libs->{$key}) {
$libs->{$key} = Library->new($key);
}
# not really normal argument
# -lfoo should be used instead, so convert it
push(@$result, "-l$key");
} else {
push(@$result, $a);
}
}
}
# pass 2
# -Lfoo, -lfoo, foo.a
# no recursion in pass 2
# fill orderedlibs array, which is the sequence of shared libraries
# after resolving all .la
# (this list may contain duplicates)
# fill staticlibs array, which is the sequence of static and convenience
# libraries
# XXX the variable $parser->{seen_la_shared} will register whether or not
# a .la file is found which refers to a shared library and which is not
# yet installed
# this is used to decide where to link executables and create wrappers
sub parse_linkargs2
{
state $seen_pthread = 0;
my ($self, $Rresolved, $libsearchdirs, $orderedlibs, $staticlibs,
$dirs, $libs) = @_;
Trace::debug {"parse_linkargs2\n"};
Trace::debug {" args: @{$self->{args}}\n"};
$self->{result} = [];
my $result = $self->{result};
foreach my $a (@{$self->{args}}) {
Trace::debug {" processing $a\n"};
if (!$a || $a eq '' || $a =~ m/^\s+$/) {
# skip empty arguments
} elsif ($a eq '-lc') {
# don't link explicitly with libc (just remove -lc)
} elsif ($a eq '-pthread' && !$seen_pthread) {
# XXX special treatment since it's not a -l flag
$seen_pthread = 1;
push(@$result, $a);
} elsif ($a =~ m/^-L(.*)/) {
if (!exists $dirs->{$1}) {
$dirs->{$1} = 1;
}
} elsif ($a =~ m/^-R(.*)/) {
# -R options originating from .la resolution
# those from @ARGV are in @Ropts
push @$Rresolved, $1;
} elsif ($a =~ m/^-l(.*)/) {
my @largs = ();
my $key = $1;
if (!exists $libs->{$key}) {
$libs->{$key} = Library->new($key);
}
push @$orderedlibs, $key;
} elsif ($a =~ m/(\S+\/)*(\S+)\.a$/) {
(my $key = $2) =~ s/^lib//;
if (!exists $libs->{$key}) {
$libs->{$key} = Library->new($key);
}
$libs->{$key}->{fullpath} = $a;
push(@$staticlibs, $a);
} elsif ($a =~ m/(\S+\/)*(\S+)\.la$/) {
(my $key = $2) =~ s/^lib//;
my $d = abs_dir($a);
$dirs->{$d} = 1;
my $fulla = abs_path($a);
require LaFile;
my $lainfo = LaFile->parse($fulla);
my $dlname = $lainfo->stringize('dlname');
my $oldlib = $lainfo->stringize('old_library');
my $installed = $lainfo->stringize('installed');
if ($dlname ne '' && $installed eq 'no') {
Trace::debug {"seen uninstalled la shared in $a\n"};
$self->{seen_la_shared} = 1;
}
if ($dlname eq '' && -f "$d/$ltdir/$oldlib") {
push @$staticlibs, "$d/$ltdir/$oldlib";
} else {
if (!exists $libs->{$key}) {
$libs->{$key} = Library->new($key);
$libs->{$key}->{lafile} = $fulla;
}
push @$orderedlibs, $key;
}
} elsif ($a =~ m/^-Wl,(\S+)/) {
# libtool accepts a list of -Wl options separated
# by commas, and possibly with a trailing comma
# which is not accepted by the linker
my @Wlflags = split(/,/, $1);
foreach my $f (@Wlflags) {
push(@$result, "-Wl,$f");
}
} else {
push(@$result, $a);
}
}
Trace::debug {"end parse_linkargs2\n"};
return $self->{result};
}
sub new
{
my ($class, $args) = @_;
bless { args => $args }, $class;
}
1;

View File

@ -0,0 +1,188 @@
# $OpenBSD: Program.pm,v 1.1 2010/12/05 16:37:50 espie Exp $
# Copyright (c) 2007-2010 Steven Mestdagh <steven@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use strict;
use warnings;
use feature qw(say switch state);
package Program;
use File::Basename;
use Archive;
use Util;
sub new
{
my $class = shift;
bless {}, $class;
}
# write a wrapper script for an executable so it can be executed within
# the build directory
sub write_wrapper
{
my $self = shift;
my $program = $self->{outfilepath};
my $pfile = basename $program;
my $realprogram = $ltdir . '/' . $pfile;
open(my $pw, '>', $program) or die "Cannot write $program: $!\n";
print $pw <<EOF
#!/bin/sh
# $program - wrapper for $realprogram
# Generated by libtool $version
argdir=`dirname \$0`
if test -f "\$argdir/$realprogram"; then
# Add our own library path to LD_LIBRARY_PATH
LD_LIBRARY_PATH=\$argdir/$ltdir
export LD_LIBRARY_PATH
# Run the actual program with our arguments.
exec "\$argdir/$realprogram" \${1+"\$\@"}
echo "\$0: cannot exec $program \${1+"\$\@"}"
exit 1
else
echo "\$0: error: \\\`\$argdir/$realprogram' does not exist." 1>&2
exit 1
fi
EOF
;
close($pw);
chmod 0755, $program;
}
sub link
{
my ($self, $ltprog, $dirs, $libs, $deplibs, $libdirs, $parser,
$opts) = @_;
Trace::debug {"linking program (", ($opts->{'static'}) ? "not " : "",
"dynamically linking not-installed libtool libraries)\n"};
my $what = ref($self);
my $fpath = $self->{outfilepath};
my $RPdirs = $self->{RPdirs};
my $odir = dirname $fpath;
my $fname = basename $fpath;
my @libflags;
my @cmd;
my $dst;
Trace::debug {"argvstring (pre resolve_la): @{$parser->{args}}\n"};
my $args = $parser->resolve_la($deplibs, $libdirs);
Trace::debug {"argvstring (post resolve_la): @{$parser->{args}}\n"};
my $orderedlibs = [];
my $staticlibs = [];
$parser->{args} = $args;
$parser->{seen_la_shared} = 0;
$args = $parser->parse_linkargs2(\@main::Rresolved,
\@main::libsearchdirs, $orderedlibs, $staticlibs, $dirs, $libs);
Trace::debug {"staticlibs = \n", join("\n", @$staticlibs), "\n"};
Trace::debug {"orderedlibs = @$orderedlibs\n"};
my $finalorderedlibs = reverse_zap_duplicates_ref($orderedlibs);
Trace::debug {"final orderedlibs = @$finalorderedlibs\n"};
my $symlinkdir = $ltdir;
if ($odir ne '.') {
$symlinkdir = "$odir/$ltdir";
}
mkdir $symlinkdir if ! -d $symlinkdir;
if ($parser->{seen_la_shared}) {
$dst = ($odir eq '.') ? "$ltdir/$fname" : "$odir/$ltdir/$fname";
$self->write_wrapper();
} else {
$dst = ($odir eq '.') ? $fname : "$odir/$fname";
}
my $symbolsfile;
if ($opts->{'export-symbols'}) {
$symbolsfile = $opts->{'export-symbols'};
} elsif ($opts->{'export-symbols-regex'}) {
($symbolsfile = "$odir/$ltdir/$fname") =~ s/\.la$/.exp/;
Archive->get_symbollist($symbolsfile, $opts->{'export-symbols-regex'}, $self->{objlist});
}
$libdirs = reverse_zap_duplicates_ref($libdirs);
# add libdirs to rpath if they are not in standard lib path
for my $l (@$libdirs) {
my $found = 0;
for my $d (@main::libsearchdirs) {
if ($l eq $d) { $found = 1; last; }
}
if (!$found) { push @$RPdirs, $l; }
}
$RPdirs = reverse_zap_duplicates_ref($RPdirs);
map { $_ = "-Wl,-rpath,$_" } @$RPdirs;
foreach my $k (keys %$libs) {
Trace::debug {"key = $k - "};
my $r = ref($libs->{$k});
Trace::debug {"ref = $r\n"};
if (!defined $libs->{$k}) {
Trace::debug {"creating library object for $k\n"};
require Library;
$libs->{$k} = Library->new($k);
}
my $l = $libs->{$k};
$l->find($dirs, 1, $opts->{'static'}, $what);
}
my @libobjects = values %$libs;
Trace::debug {"libs:\n", join("\n", (keys %$libs)), "\n"};
Trace::debug {"libfiles:\n", join("\n", map { $_->{fullpath} } @libobjects), "\n"};
main::create_symlinks($symlinkdir, $libs);
foreach my $k (@$finalorderedlibs) {
my $a = $libs->{$k}->{fullpath} || die "Link error: $k not found in \$libs\n";
if ($a =~ m/\.a$/) {
# don't make a -lfoo out of a static library
push @libflags, $a;
} else {
my $lib = basename $a;
if ($lib =~ m/^lib(.*)\.so(\.\d+){2}/) {
$lib = $1;
} else {
say "warning: cannot derive -l flag from library filename, assuming hash key";
$lib = $k;
}
push @libflags, "-l$lib";
}
}
@cmd = @$ltprog;
push @cmd, '-o', $dst;
push @cmd, @$args if ($args);
push @cmd, @{$self->{objlist}} if (@{$self->{objlist}});
push @cmd, @$staticlibs if (@$staticlibs);
push @cmd, "-L$symlinkdir", @libflags if (@libflags);
push @cmd, @$RPdirs if (@$RPdirs);
push @cmd, "-Wl,-retain-symbols-file,$symbolsfile" if ($symbolsfile);
Exec->command(@cmd);
}
sub install
{
my ($class, $src, $dst, $instprog, $instopts) = @_;
my $srcdir = dirname $src;
my $srcfile = basename $src;
my $realpath = "$srcdir/$ltdir/$srcfile";
Exec->command(@$instprog, @$instopts, $realpath, $dst);
}
1;

View File

@ -0,0 +1,48 @@
# $OpenBSD: Trace.pm,v 1.1 2010/12/05 16:37:50 espie Exp $
# Copyright (c) 2007-2010 Steven Mestdagh <steven@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use strict;
use warnings;
use feature qw(say switch state);
package Trace;
sub print(&)
{
my $val = shift;
if (defined $ENV{'TRACE_LIBTOOL'}) {
state $trace_file;
if (!defined $trace_file) {
open $trace_file, '>>', $ENV{'TRACE_LIBTOOL'};
}
if (defined $trace_file) {
print $trace_file (&$val);
}
}
}
sub debug(&;$)
{
my ($args, $level) = @_;
$level = 1 if !defined $level;
if (defined $main::D && $main::D >= $level) {
print (&$args);
}
}
1;

View File

@ -0,0 +1,53 @@
# $OpenBSD: Util.pm,v 1.1 2010/12/05 16:37:50 espie Exp $
# Copyright (c) 2007-2010 Steven Mestdagh <steven@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use strict;
use warnings;
package Util;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(reverse_zap_duplicates_ref abs_dir $ltdir $version
@picflags $sharedflag);
use File::Basename;
use Cwd;
our $ltdir = '.libs';
our $version = '1.5.26'; # pretend to be this version of libtool
our @picflags = ('-fPIC', '-DPIC');
our $sharedflag = '-shared';
# walk a list from back to front, removing any duplicates
# this should make sure a library's dependencies are behind the library itself
sub reverse_zap_duplicates_ref
{
my $arglist = shift;
my $h = {};
my $r = [];
for my $el (reverse @$arglist) {
next if defined $h->{$el};
unshift @$r, $el;
$h->{$el} = 1;
}
return $r;
}
sub abs_dir
{
my $a = shift;
return dirname(Cwd::abs_path($a));
}
1;