diff --git a/infrastructure/build/libtool b/infrastructure/build/libtool deleted file mode 100755 index 6d590a1e31b..00000000000 --- a/infrastructure/build/libtool +++ /dev/null @@ -1,1855 +0,0 @@ -#!/usr/bin/perl -# $OpenBSD: libtool,v 1.129 2010/07/06 14:50:53 espie Exp $ - -# Copyright (c) 2007-2010 Steven Mestdagh -# -# 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); -use Cwd qw(getcwd abs_path); -use File::Basename; -use File::Glob ':glob'; -use File::Path; -use Getopt::Long; -use Getopt::Std; - -package main; - -use subs qw( - create_symlinks - generate_objlist - get_search_dirs - guess_implicit_mode - help - notyet - parse_version_info - process_deplibs - reverse_zap_duplicates_ref - ); - -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); - } -} - -{ -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++; -} -} - -{ -package Parser; -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$/; - 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}); - push(@{$lainfo->{'cached_libdirs'}}, - $lainfo->{'libdir'}); - if (@{$lainfo->{'cached_deplibs'}} > 50) { - $lainfo->{'cached_deplibs'} = main::reverse_zap_duplicates_ref($lainfo->{'cached_deplibs'}); - } - if (@{$lainfo->{'cached_libdirs'}} > 50) { - $lainfo->{'cached_libdirs'} = main::reverse_zap_duplicates_ref($lainfo->{'cached_libdirs'}); - } - if (@{$lainfo->{'cached_result'}} > 50) { - $lainfo->{'cached_result'} = main::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. -# XXX the variable $lashared will register whether or not a .la file is -# found which refers to a shared library -# this is used to decide where to link executables and create wrappers -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}; - my $lashared = $self->{seen_la_shared}; - - 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(.*)/) { - if (!exists $dirs->{$1}) { - $dirs->{$1} = 1; - push @$deplibs, $a; - } - } 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); - my $lafile = LaFile->find($key, $dirs); - if ($lafile) { - $libs->{$key}->{lafile} = $lafile; - my $absla = main::abs_path($lafile); - push @$deplibs, $absla; - push @$result, $lafile; - next; - } else { - $libs->{$key}->find($dirs, 1, 'notyet', $libsearchdirs); - my @deps = $libs->{$key}->inspect; - foreach my $d (@deps) { - my $k = main::basename $d; - $k =~ s/^(\S+)\.so.*$/$1/; - $k =~ s/^lib//; - push(@largs, "-l$k"); - } - 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); - } - my $d = main::abs_path(main::dirname($a)); - $dirs->{$d} = 1; - $libs->{$key}->{fullpath} = $a; - push(@$result, $a); - } elsif ($a =~ m/(\S+\/)*(\S+)\.la$/) { - (my $key = $2) =~ s/^lib//; - my $d = main::abs_path(main::dirname($a)); - $dirs->{$d} = 1; - my $fulla = main::abs_path($a); - my $lainfo = LaFile->parse($fulla); - my $dlname = $lainfo->{'dlname'}; - my $oldlib = $lainfo->{'old_library'}; - my $libdir = $lainfo->{'libdir'}; - if ($dlname ne '') { - $$lashared = 1; - 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//; - my $d = main::abs_path(main::dirname($a)); - $dirs->{$d} = 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 -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}; - my $ltdir = $main::ltdir; - - 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 = main::abs_path(main::dirname($a)); - $dirs->{$d} = 1; - my $fulla = main::abs_path($a); - my $lainfo = LaFile->parse($fulla); - my $dlname = $lainfo->stringize('dlname'); - my $oldlib = $lainfo->stringize('old_library'); - 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; -} -} - -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; -} - -package LaFile; -our @ISA=(qw(LaLoFile)); -use File::Basename; - -# 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 <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+= # \n"; - close $fh; - } - open ($fh, '>>', $logfile); - 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.a") { - 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 = shift; - my $ltprog = shift; - my $la = shift; - my $fname = shift; - my $odir = shift; - my $shared = shift; - my $objs = shift; - my $dirs = shift; - my $libs = shift; - my $deplibs = shift; - my $libdirs = shift; - my $parser = shift; - my $opts = shift; - - Trace::debug {"creating link command for library (linked ", - ($shared) ? "dynam" : "stat", "ically)\n"}; - - my $what = ref($self); - my @libflags; - my @cmd; - my $ltdir = $main::ltdir; - my $dst = ($odir eq '.') ? "$ltdir/$fname" : "$odir/$ltdir/$fname"; - if ($la =~ m/\.a$/) { - # probably just a convenience library - $dst = ($odir eq '.') ? "$fname" : "$odir/$fname"; - } - mkdir "$odir/$ltdir" if (! -d "$odir/$ltdir"); - - 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 = main::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 = main::basename $a; - my $xdir = "$odir/$ltdir/${la}x/$libfile"; - main::extract_archive($xdir, $a); - my @kobjs = main::get_objlist_from_archive($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, $what); - my $a = $l->{fullpath}; - if ($a =~ m/\.a$/ && $a !~ m/_pic\.a/) { - # extract objects from archive - my $libfile = main::basename $a; - my $xdir = "$odir/$ltdir/${la}x/$libfile"; - main::extract_archive($xdir, $a); - my @kobjs = main::get_objlist_from_archive($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/; - main::get_symbollist($symbolsfile, $opts->{'export-symbols-regex'}, $objs); - } - my $tmp = []; - while (my $k = shift @$finalorderedlibs) { - my $l = $libs->{$k}; - $l->find($dirs, 1, $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($ltdir, $libs); - my $prev_was_archive = 0; - my $libcounter = 0; - foreach my $k (@$finalorderedlibs) { - my $a = $libs->{$k}->{fullpath} || die "ERROR: $k not found in \$libs"; - 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, $main::sharedflag, @main::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$ltdir", @libflags if (@libflags); - push @cmd, "-Wl,-retain-symbols-file,$symbolsfile" if ($symbolsfile); - Exec->command(@cmd); -} - -package LoFile; -our @ISA=(qw(LaLoFile)); -use File::Basename; - -# 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 <{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); - } -} - -package Program; -use File::Basename; - -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 $ltdir = $main::ltdir; - my $version = $main::version; - open(my $pw, '>', $program) or die "cannot write $program: $!\n"; - print $pw <&2 - exit 1 -fi -EOF -; - close($pw); - chmod 0755, $program; -} - -sub is_wrapper -{ -# my $self = shift; - my $program = shift; - - open(my $pw, '<', $program) or die "cannot open $program: $!\n"; - return eval(grep { m/wrapper\sfor/ } <$pw>); -} - -sub link -{ - my $self = shift; - my $ltprog = shift; - my $dirs = shift; - my $libs = shift; - my $deplibs = shift; - my $libdirs = shift; - my $parser = shift; - my $opts = shift; - my $seen_la_shared = shift; - - my $ltdir = $main::ltdir; - Trace::debug {"linking program (", - ($self->{shared}) ? "dynam" : "stat", "ically)\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; - if ($self->{shared} && $seen_la_shared) { - $dst = ($odir eq '.') ? "$ltdir/$fname" : "$odir/$ltdir/$fname"; - mkdir "$odir/$ltdir" if (! -d "$odir/$ltdir"); - } else { - $dst = ($odir eq '.') ? $fname : "$odir/$fname"; - } - - 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 = main::reverse_zap_duplicates_ref($orderedlibs); - Trace::debug {"final orderedlibs = @$finalorderedlibs\n"}; - - my $symbolsfile; - if ($opts->{'export-symbols'}) { - $symbolsfile = $opts->{'export-symbols'}; - } elsif ($opts->{'export-symbols-regex'}) { - ($symbolsfile = "$odir/$ltdir/$fname") =~ s/\.la$/.exp/; - main::get_symbollist($symbolsfile, $opts->{'export-symbols-regex'}, $self->{objlist}); - } - $libdirs = main::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 = main::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"}; - $libs->{$k} = Library->new($k); - } - my $l = $libs->{$k}; - $l->find($dirs, $self->{shared}, $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($ltdir, $libs); - foreach my $k (@$finalorderedlibs) { - my $a = $libs->{$k}->{fullpath} || die "ERROR: $k not found in \$libs"; - 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, '-static' if (!$self->{shared}); - push @cmd, @$args if ($args); - push @cmd, @{$self->{objlist}} if (@{$self->{objlist}}); - push @cmd, @$staticlibs if (@$staticlibs); - push @cmd, "-L$ltdir", @libflags if (@libflags); - push @cmd, @$RPdirs if (@$RPdirs); - push @cmd, "-Wl,-retain-symbols-file,$symbolsfile" if ($symbolsfile); - Exec->command(@cmd); -} - -package Library; - -# find actual library filename -# XXX pick the right one if multiple are found! -sub find -{ - my ($self, $dirs, $shared, $linkmode, $ldconfigdirs) = @_; - - my $libtofind = $self->{key}; - my $libfile = 0; - my @globbedlib; - my $ltdir = $main::ltdir; - - my $pic = ''; # used when finding static libraries - if ($linkmode eq 'LaFile') { - $pic = '_pic'; - } - - if (defined $self->{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 $d = main::abs_path(main::dirname($self->{lafile})); - # get the name we need (this may include a -release) - if (!$dlname && !$oldlib) { - die "neither static nor shared library found in $self->{lafile}\n"; - } - if ($d !~ m/\Q$ltdir\E$/ && $lainfo->{'installed'} eq 'no') { - $d .= "/$ltdir"; - } - if ($shared) { - if ($dlname) { - $libfile = "$d/$dlname"; - } else { - # fall back to static - $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 "$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; -} - -package main; - -use Config; -use constant { - OBJECT => 0, - LIBRARY => 1, - PROGRAM => 2, -}; - -our $version = '1.5.26'; # pretend to be this version of libtool -my @no_shared_archs = qw(m88k vax); -# XXX my $machine_arch = `machine -a`; -my $machine_arch = $Config{'ARCH'}; -(my $gnu_arch = $machine_arch) =~ s/amd64/x86_64/; -my @valid_modes = qw(clean compile execute finish install link uninstall); -my @valid_src = qw(asm c cc cpp cxx f s); -my $cwd = getcwd(); -our $ltdir = '.libs'; -our @picflags = ('-fPIC', '-DPIC'); -our $sharedflag = '-shared'; -my $instlibdir = '/usr/local/lib'; -my @libsearchdirs; -$instlibdir = $ENV{'LIBDIR'} if defined $ENV{'LIBDIR'}; - -my $mode; -our $D = 0; # debug flag -my $verbose = 1; - -my %opts; # options passed to libtool -my @tags; # list of --tag options passed to libtool - -# just to be clear: -# when building a library: -# * -R libdir records libdir in dependency_libs -# * -rpath is the path where the (shared) library will be installed -# when building a program: -# * both -R libdir and -rpath libdir add libdir to the run-time path -# -Wl,-rpath,libdir will bypass libtool. - -# build static/shared objects? -my $static = 1; -my $shared = 0; -my $convenience = 0; -my $noshared = 0; -if (grep { $_ eq $machine_arch } @no_shared_archs) { - $noshared = 1; -} - -my $gp = new Getopt::Long::Parser; -# require_order so we stop parsing at the first non-option or argument, -# instead of parsing the whole ARGV. -$gp->configure( 'no_ignore_case', - 'pass_through', - 'no_auto_abbrev', - 'require_order' - ); -$gp->getoptions('config' => \&config, - 'debug' => \$D, - 'dry-run|n' => sub { Exec->dry_run }, - 'features' => \¬yet, - 'finish' => sub { $mode = 'finish'; }, - 'help' => \&help, # does not return - 'mode=s{1}' => \$mode, - 'quiet' => sub { $verbose = 0; }, - 'silent' => sub { $verbose = 0; }, - 'tag=s{1}' => \@tags, - 'version' => sub { say $version ; exit(0); }, - ); - -if ($verbose || $D) { - Exec->verbose_run; -} -# what are we going to run (cc, c++, ...) -my $ltprog = (); -# deal with multi-arg ltprog -Trace::debug {"ARGV = @ARGV\n"}; -while (@ARGV) { - # just read arguments until the next option... - if ($ARGV[0] =~ m/^\-/) { last; } - # XXX improve checks - if ($ARGV[0] =~ m/^\S+\.la/) { last; } - my $arg = shift @ARGV; - push @$ltprog, $arg; - Trace::debug {"arg = \"$arg\"\n"}; - # if the current argument is an install program, stop immediately - if ($arg =~ /cp$/) { last; } - if ($arg =~ /install([-.]sh)?$/) { last; } -} -Trace::debug {"ltprog = \"@$ltprog\"\n"}; -if (@$ltprog == 0) { die "no libtool command\n" }; - -# check mode and guess it if needed -if (!($mode && grep { $_ eq $mode } @valid_modes)) { - $mode = guess_implicit_mode($ltprog); - if ($mode) { - Trace::debug {"implicit mode: $mode\n"}; - } else { - die "MODE must be one of:\n@valid_modes\n"; - } -} - -# from here, options may be intermixed with arguments -$gp->configure('permute'); - -if ($mode eq 'compile') { - my $lofile = LoFile->new; - - $gp->getoptions('o=s' => \$opts{'o'}, - 'prefer-pic' => \$opts{'prefer-pic'}, - 'prefer-non-pic'=> \$opts{'prefer-non-pic'}, - 'static' => \$opts{'static'}, - ); - # XXX options ignored: -prefer-pic and -prefer-non-pic - my $pic = 0; - my $nonpic = 1; - # assume we need to build pic objects - $pic = 1 if (!$noshared); - $nonpic = 0 if ($pic && grep { $_ eq 'disable-static' } @tags); - $pic = 0 if ($nonpic && grep { $_ eq 'disable-shared' } @tags); - $nonpic = 1 if ($opts{'static'}); - - my ($outfile, $odir, $ofile, $srcfile, $srcext); - # XXX check whether -c flag is present and if not, die? - if ($opts{'o'}) { - # fix extension if needed - ($outfile = $opts{'o'}) =~ s/\.o$/.lo/; - $odir = dirname $outfile; - $ofile = basename $outfile; - } else { - # XXX sometimes no -o flag is present and we need another way - my $srcre = join '|', @valid_src; - my $found = 0; - foreach my $a (@ARGV) { - if ($a =~ m/\.($srcre)$/i) { - $srcfile = $a; - $srcext = $1; - $found = 1; - last; - } - } - $found or die "cannot find source file in command\n"; - # the output file ends up in the current directory - $odir = '.'; - ($ofile = basename $srcfile) =~ s/\.($srcext)$/.lo/i; - $outfile = "$odir/$ofile"; - } - Trace::debug {"srcfile = $srcfile\n"} if $srcfile; - Trace::debug {"outfile = $outfile\n"}; - (my $nonpicobj = $ofile) =~ s/\.lo$/.o/; - my $picobj = "$ltdir/$nonpicobj"; - - $lofile->{picobj} = $picobj if $pic; - $lofile->{nonpicobj} = $nonpicobj if $nonpic; - $lofile->compile($ltprog, $odir, \@ARGV); - $lofile->write($outfile); -} elsif ($mode eq 'install') { - # we just parse the options in order to find the actual arguments - my @argvcopy = @ARGV; - my %install_opts; - Trace::debug {"ltprog[-1] = $$ltprog[-1]\n"}; - if ($$ltprog[-1] =~ m/install([.-]sh)?$/) { - getopts('BbCcdf:g:m:o:pSs', \%install_opts); - if (@ARGV < 2 && (!defined $install_opts{'d'} && @ARGV == 1)) { - die "wrong number of arguments for install\n"; - } - } elsif ($$ltprog[-1] =~ m/cp$/) { - getopts('HLPRfipr', \%install_opts); - if (@ARGV < 2) { - die "wrong number of arguments for install\n"; - } - } else { - die "unsupported install program $$ltprog[-1]\n"; - } - my @instopts = @argvcopy[0 .. (@argvcopy - @ARGV - 1)]; - my $dst = pop @ARGV; - my @src = @ARGV; - my $dstdir; - if (-d $dst) { - $dstdir = $dst; - } else { - # dst is not a directory, i.e. a file - if (@src > 1) { - # XXX not really libtool's task to check this - die "multiple source files combined with file destination"; - } else { - $dstdir = dirname $dst; - } - } - my $toinstall = {}; - my $tosymlink = {}; # for libraries with a -release in their name - my $addedmode = 0; - foreach my $s (@src) { - my $dstfile = basename $s; - # resolve symbolic links, so we don't try to test later - # whether the symlink is a program wrapper etc. - if (-l $s) { - $s = readlink($s) or die "Cannot readlink $s"; - } - my $srcdir = dirname $s; - my $srcfile = basename $s; - Trace::debug {"srcdir = $srcdir\nsrcfile = $srcfile\n"}; - Trace::debug {"dstdir = $dstdir\ndstfile = $dstfile\n"}; - if ($srcfile =~ m/^\S+\.la$/) { - # we are installing a .la library - if ($$ltprog[-1] =~ m/install([.-]sh)?$/) { - push @instopts, '-m', '644' unless $addedmode; - $addedmode = 1; - } - my $lainfo = LaFile->parse($s); - # replace info where needed when installing the .la file - my $sharedlib = $lainfo->{'dlname'}; - my $staticlib = $lainfo->{'old_library'}; - my @libnames = split /\s+/, $lainfo->{'library_names'}; - my $laipath = "$srcdir/$ltdir/$srcfile".'i'; - $toinstall->{"$srcdir/$ltdir/$staticlib"} = "$dstdir/$staticlib" - if ($staticlib); - $toinstall->{"$srcdir/$ltdir/$sharedlib"} = "$dstdir/$sharedlib" - if ($sharedlib); - $toinstall->{"$laipath"} = "$dstdir/$dstfile"; - foreach my $n (@libnames) { - $tosymlink->{$n} = $sharedlib if ($n ne $sharedlib); - } - } elsif (-f "$srcdir/$ltdir/$srcfile" && Program::is_wrapper($s)) { - $toinstall->{"$srcdir/$ltdir/$srcfile"} = $dst; - } else { - $toinstall->{$s} = $dst; - } - } - while (my ($s, $d) = each %$toinstall) { - my @realinstopts = @instopts; - # do not try to strip .la files - if ($s =~ m/\.la$/ || $d =~ m /\.la$/) { - @realinstopts = grep { $_ ne '-s' } @realinstopts; - } - Exec->command(@$ltprog, @realinstopts, $s, $d); - } - while (my ($d, $s) = each %$tosymlink) { - unlink("$dstdir/$d"); - symlink($s, "$dstdir/$d"); - } - if (defined $install_opts{'d'}) { - Exec->command(@$ltprog, @instopts, @ARGV); - } -} elsif ($mode eq 'link') { - my $cmd; - my @Ropts; # -R options on the command line - my @Rresolved; # -R options originating from .la resolution - my @RPopts; # -rpath options - my $deplibs = []; # list of dependent libraries (both -L and -l flags) - my $libdirs = []; # list of libdirs - my $libs = {}; # libraries - my $dirs = {}; # paths to find libraries - # put a priority in the dir hash - # always look here - $dirs->{'/usr/lib'} = 3; - - $gp->getoptions('all-static' => \$opts{'all-static'}, - 'avoid-version' => \$opts{'avoid-version'}, - 'dlopen=s{1}' => \$opts{'dlopen'}, - 'dlpreopen=s{1}' => \$opts{'dlpreopen'}, - 'export-dynamic' => \$opts{'export-dynamic'}, - 'export-symbols=s' => \$opts{'export-symbols'}, - 'export-symbols-regex=s'=> \$opts{'export-symbols-regex'}, - 'module' => \$opts{'module'}, - 'no-fast-install' => \$opts{'no-fast-install'}, - 'no-install' => \$opts{'no-install'}, - 'no-undefined' => \$opts{'no-undefined'}, - 'o=s' => \$opts{'o'}, - 'objectlist=s' => \$opts{'objectlist'}, - 'precious-files-regex=s'=> \$opts{'precious-files-regex'}, - 'prefer-pic' => \$opts{'prefer-pic'}, - 'prefer-non-pic' => \$opts{'prefer-non-pic'}, - 'release=s' => \$opts{'release'}, - 'rpath=s' => \@RPopts, - 'R=s' => \@Ropts, - 'shrext=s' => \$opts{'shrext'}, - 'static' => \$opts{'static'}, - 'thread-safe' => \$opts{'thread-safe'}, - 'version-info=s{1}' => \$opts{'version-info'}, - 'version_info=s{1}' => \$opts{'version-info'}, - 'version-number=s{1}' => \$opts{'version-info'}, - ); - # XXX options ignored: dlopen, dlpreopen, no-fast-install, - # no-install, no-undefined, precious-files-regex, - # shrext, thread-safe, prefer-pic, prefer-non-pic - - @libsearchdirs = get_search_dirs(); - # add the .libs dir as well in case people try to link directly - # with the real library instead of the .la library - push @libsearchdirs, './.libs'; - - my $outfile = $opts{'o'}; - if (!$outfile) { - die "no output file given.\n"; - } - Trace::debug {"outfile = $outfile\n"}; - my $odir = dirname $outfile; - my $ofile = basename $outfile; - - # what are we linking? - my $linkmode = PROGRAM; - if ($ofile =~ m/\.l?a$/) { - $linkmode = LIBRARY; - } - Trace::debug {"linkmode: $linkmode\n"}; - - # eat multiple version-info arguments, we only accept the first. - map { $_ = '' if ($_ =~ m/\d+:\d+:\d+/); } @ARGV; - - my @objs; - my @sobjs; - my $allpicobj; - if ($opts{'objectlist'}) { - my $objectlist = $opts{'objectlist'}; - open(my $ol, '<', $objectlist) or die "cannot open $objectlist: $!\n"; - my @objlist = <$ol>; - for (@objlist) { chomp; } - $allpicobj = generate_objlist(\@objs, \@sobjs, \@objlist); - } else { - $allpicobj = generate_objlist(\@objs, \@sobjs, \@ARGV); - } - Trace::debug {"objs = @objs\n"}; - Trace::debug {"sobjs = @sobjs\n"}; - - my $parser = Parser->new(\@ARGV); - $parser->{result} = []; - my $seen_la_shared = 0; - $parser->{seen_la_shared} = \$seen_la_shared; - - if ($linkmode == PROGRAM) { - my $program = Program->new; - $program->{outfilepath} = $outfile; - # XXX give higher priority to dirs of not installed libs - if ($opts{'export-dynamic'}) { - push(@{$parser->{args}}, "-Wl,-E"); - } - if ($opts{'static'}) { - $program->{shared} = 0; - } else { - $program->{shared} = 1; - } - - $parser->parse_linkargs1($deplibs, \@Rresolved, \@libsearchdirs, - $dirs, $libs, $parser->{args}, 0); - $parser->{args} = $parser->{result}; - Trace::debug {"end parse_linkargs1\n"}; - Trace::debug {"deplibs = @$deplibs\n"}; - $seen_la_shared = ${$parser->{seen_la_shared}}; - - $program->{objlist} = \@objs; - if (@objs == 0) { - if (@sobjs > 0) { - Trace::debug {"no non-pic libtool objects found, trying pic objects...\n"}; - $program->{objlist} = \@sobjs; - } elsif (@sobjs == 0) { - Trace::debug {"no libtool objects of any kind found\n"}; - Trace::debug {"hoping for real objects in ARGV...\n"}; - } - } - my $RPdirs = []; - @$RPdirs = (@Ropts, @RPopts, @Rresolved); - $program->{RPdirs} = $RPdirs; - - $program->link($ltprog, $dirs, $libs, $deplibs, $libdirs, $parser, \%opts, $seen_la_shared); - if ($program->{shared} && $seen_la_shared) { - $program->write_wrapper(); - } - } elsif ($linkmode == LIBRARY) { - my $lainfo = LaFile->new; - - $shared = 1 if ($opts{'version-info'} || - $opts{'avoid-version'} || - $opts{'module'}); - if (!@RPopts) { - $convenience = 1; - $noshared = 1; - $static = 1; - $shared = 0; - } else { - $shared = 1; - } - if ($ofile =~ m/\.a$/ && !$convenience) { - $ofile =~ s/\.a$/.la/; - $outfile =~ s/\.a$/.la/; - } - (my $libname = $ofile) =~ s/\.l?a$//; # remove extension - my $staticlib = $libname.'.a'; - my $sharedlib = $libname.'.so'; - my $sharedlib_symlink; - - if ($opts{'static'}) { - $shared = 0; - $static = 1; - } - $shared = 0 if $noshared; - - $parser->parse_linkargs1($deplibs, \@Rresolved, \@libsearchdirs, - $dirs, $libs, $parser->{args}, 0); - $parser->{args} = $parser->{result}; - Trace::debug {"end parse_linkargs1\n"}; - Trace::debug {"deplibs = @$deplibs\n"}; - $seen_la_shared = ${$parser->{seen_la_shared}}; - - my $sover = '0.0'; - my $origver = 'unknown'; - # environment overrides -version-info - (my $envlibname = $libname) =~ s/[.+-]/_/g; - my ($current, $revision, $age) = (0, 0, 0); - if ($opts{'version-info'}) { - ($current, $revision, $age) = parse_version_info($opts{'version-info'}); - $origver = "$current.$revision"; - $sover = $origver; - } - if ($ENV{"${envlibname}_ltversion"}) { - # this takes priority over the previous - $sover = $ENV{"${envlibname}_ltversion"}; - ($current, $revision) = split /\./, $sover; - $age = 0; - } - if (defined $opts{'release'}) { - $sharedlib_symlink = $sharedlib; - $sharedlib = $libname.'-'.$opts{'release'}.'.so'; - } - if ($opts{'avoid-version'} || - (defined $opts{'release'} && !$opts{'version-info'})) { - # don't add a version in these cases - } else { - $sharedlib .= ".$sover"; - if (defined $opts{'release'}) { - $sharedlib_symlink .= ".$sover"; - } - } - - # XXX add error condition somewhere... - $static = 0 if ($shared && grep { $_ eq 'disable-static' } @tags); - $shared = 0 if ($static && grep { $_ eq 'disable-shared' } @tags); - - Trace::debug {"SHARED: $shared\nSTATIC: $static\n"}; - - $lainfo->{'libname'} = $libname; - if ($shared) { - $lainfo->{'dlname'} = $sharedlib; - $lainfo->{'library_names'} = $sharedlib; - $lainfo->{'library_names'} .= " $sharedlib_symlink" - if (defined $opts{'release'}); - $lainfo->link($ltprog, $ofile, $sharedlib, $odir, 1, \@sobjs, $dirs, $libs, $deplibs, $libdirs, $parser, \%opts); - Trace::debug {"sharedlib: $sharedlib\n"}; - $lainfo->{'current'} = $current; - $lainfo->{'revision'} = $revision; - $lainfo->{'age'} = $age; - } - if ($static) { - $lainfo->{'old_library'} = $staticlib; - $lainfo->link($ltprog, $ofile, $staticlib, $odir, 0, ($allpicobj) ? \@sobjs : \@objs, $dirs, $libs, $deplibs, $libdirs, $parser, \%opts); - Trace::debug {($convenience ? "convenience" : "static")." lib: $staticlib\n"}; - } - $lainfo->{'installed'} = 'no'; - $lainfo->{'shouldnotlink'} = $opts{'module'} ? 'yes' : 'no'; - map { $_ = "-R$_" } @Ropts; - unshift @$deplibs, @Ropts if (@Ropts); - Trace::debug {"deplibs = @$deplibs\n"}; - my $finaldeplibs = reverse_zap_duplicates_ref($deplibs); - Trace::debug {"finaldeplibs = @$finaldeplibs\n"}; - $lainfo->set('dependency_libs', "@$finaldeplibs"); - if (@RPopts) { - if (@RPopts > 1) { - Trace::debug {"more than 1 -rpath option given, taking the first: ", $RPopts[0], "\n"}; - } - $lainfo->{'libdir'} = $RPopts[0]; - } - if (!($convenience && $ofile =~ m/\.a$/)) { - $lainfo->write($outfile, $ofile); - unlink("$odir/$ltdir/$ofile"); - symlink("../$ofile", "$odir/$ltdir/$ofile"); - } - my $lai = "$odir/$ltdir/$ofile".'i'; - if ($shared) { - my $pdeplibs = process_deplibs($finaldeplibs); - if (defined $pdeplibs) { - $lainfo->set('dependency_libs', "@$pdeplibs"); - } - $lainfo->write_shared_libs_log($origver); - } - $lainfo->{'installed'} = 'yes'; - # write .lai file (.la file that will be installed) - $lainfo->write($lai, $ofile); - } -} elsif ($mode eq 'finish' || $mode eq 'clean' || $mode eq 'uninstall') { - # don't do anything - exit 0; -} elsif ($mode eq 'execute') { - # XXX check whether this is right - Exec->silent_run; - Exec->command(@$ltprog, @ARGV); -} else { - die "MODE=$mode not implemented yet.\n"; -} - -if (Exec->performed == 0) { - die "no commands to execute.\n" -} - -########################################################################### - -sub help -{ - print <{fullpath}; - next if (!defined $f); - next if ($f =~ m/\.a$/); - my $libfile = basename $f; - Trace::debug {"ln -s $f $dir/$libfile\n"}; - if (! -f "$dir/$libfile") { - symlink abs_path($f), "$dir/$libfile" or die "cannot create symlink: $!\n"; - } - } -} - -# prepare dependency_libs information for the .la file which is installed -# i.e. remove any .libs directories and use the final libdir for all the -# .la files -sub process_deplibs -{ - my $linkflags = shift; - - my $result; - - foreach my $lf (@$linkflags) { - if ($lf =~ m/-L\S+\Q$ltdir\E$/) { - } elsif ($lf =~ m/\/\S+\/(\S+\.la)/) { - my $lafile = $1; - $lf = LaFile->parse($lf)->{'libdir'}.'/'.$lafile; - push @$result, $lf; - } else { - push @$result, $lf; - } - } - return $result; -} - -# populate arrays of non-pic and pic objects and remove these from @ARGV -sub generate_objlist -{ - my $objs = shift; - my $sobjs = shift; - my $objsource = shift; - my $allpic = 1; - - my $result = []; - foreach my $a (@$objsource) { - if ($a =~ m/\S+\.lo$/) { - my $ofile = basename $a; - my $odir = dirname $a; - my $loinfo = LoFile->parse($a); - if ($loinfo->{'non_pic_object'}) { - my $o; - $o .= "$odir/" if ($odir ne '.'); - $o .= $loinfo->{'non_pic_object'}; - push @$objs, $o; - } - if ($loinfo->{'pic_object'}) { - my $o; - $o .= "$odir/" if ($odir ne '.'); - $o .= $loinfo->{'pic_object'}; - push @$sobjs, $o; - } else { - $allpic = 0; - } - } else { - push @$result, $a; - } - } - @$objsource = @$result; - return $allpic; -} - -# XXX reuse code from SharedLibs.pm instead -sub get_search_dirs -{ - my @libsearchdirs; - open(my $fh, '-|', 'ldconfig -r'); - if (defined $fh) { - while (<$fh>) { - if (m/^\s*search directories:\s*(.*?)\s*$/o) { - foreach my $d (split(/\:/o, $1)) { - push @libsearchdirs, $d; - } - last; - } - } - close($fh); - } else { - die "Can't find ldconfig\n"; - } - return @libsearchdirs; -} - -sub extract_archive -{ - my $dir = shift; - my $archive = shift; - - if (! -d $dir) { - Trace::debug {"mkdir -p $dir\n"}; - File::Path::mkpath($dir); - } - Exec->chdir($dir)->command('ar', 'x', $archive); -} - -sub get_objlist_from_archive -{ - my $a = shift; - - open(my $arh, '-|', "ar t $a"); - my @o = <$arh>; - close $arh; - map { chomp; } @o; - return @o; -} - -sub get_symbollist -{ - my $filepath = shift; - my $regex = shift; - my $objlist = shift; - - 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"; -} - -# 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; -} - -# try to guess libtool mode when it is not specified -sub guess_implicit_mode -{ - my $ltprog = shift; - my $m = 0; - for my $a (@$ltprog) { - if ($a =~ m/(install([.-]sh)?|cp)$/) { - $m = 'install'; - } elsif ($a =~ m/cc|c\+\+/) { # XXX improve test - if (grep { $_ eq '-c' } @ARGV) { - $m = 'compile'; - } else { - $m = 'link'; - } - } - } - return $m; -}