openbsd-ports/infrastructure/lib/LibTool/Program.pm
2010-12-05 16:37:50 +00:00

189 lines
5.4 KiB
Perl

# $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;