move most of libtool code around.
This commit is contained in:
parent
d4a6a13505
commit
9ed0d9cd66
78
infrastructure/lib/LibTool/Archive.pm
Normal file
78
infrastructure/lib/LibTool/Archive.pm
Normal 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;
|
115
infrastructure/lib/LibTool/Exec.pm
Normal file
115
infrastructure/lib/LibTool/Exec.pm
Normal 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;
|
340
infrastructure/lib/LibTool/LaFile.pm
Normal file
340
infrastructure/lib/LibTool/LaFile.pm
Normal 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;
|
88
infrastructure/lib/LibTool/LaLoFile.pm
Normal file
88
infrastructure/lib/LibTool/LaLoFile.pm
Normal 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;
|
154
infrastructure/lib/LibTool/Library.pm
Normal file
154
infrastructure/lib/LibTool/Library.pm
Normal 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;
|
72
infrastructure/lib/LibTool/LoFile.pm
Normal file
72
infrastructure/lib/LibTool/LoFile.pm
Normal 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;
|
310
infrastructure/lib/LibTool/Parser.pm
Normal file
310
infrastructure/lib/LibTool/Parser.pm
Normal 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;
|
188
infrastructure/lib/LibTool/Program.pm
Normal file
188
infrastructure/lib/LibTool/Program.pm
Normal 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;
|
48
infrastructure/lib/LibTool/Trace.pm
Normal file
48
infrastructure/lib/LibTool/Trace.pm
Normal 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;
|
53
infrastructure/lib/LibTool/Util.pm
Normal file
53
infrastructure/lib/LibTool/Util.pm
Normal 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;
|
Loading…
x
Reference in New Issue
Block a user