Annotation of src/usr.bin/libtool/libtool, Revision 1.18
1.1 espie 1: #!/usr/bin/perl
1.18 ! jasper 2: # $OpenBSD: libtool,v 1.17 2012/07/07 18:21:56 espie Exp $
1.1 espie 3:
4: # Copyright (c) 2007-2010 Steven Mestdagh <steven@openbsd.org>
1.13 espie 5: # Copyright (c) 2012 Marc Espie <espie@openbsd.org>
1.1 espie 6: #
7: # Permission to use, copy, modify, and distribute this software for any
8: # purpose with or without fee is hereby granted, provided that the above
9: # copyright notice and this permission notice appear in all copies.
10: #
11: # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12: # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13: # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14: # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15: # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16: # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17: # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18:
19: use strict;
20: use warnings;
21: use feature qw(say switch state);
22: use Cwd qw(getcwd abs_path);
23: use File::Basename;
24: use File::Glob ':glob';
25: use File::Path;
1.3 espie 26:
1.1 espie 27: use LT::Trace;
28: use LT::Exec;
29: use LT::Util;
30:
1.3 espie 31: $SIG{__DIE__} = sub {
32: require Carp;
33:
34: my $_ = pop @_;
35: s/(.*)( at .*? line .*?\n$)/$1/s;
36: push @_, $_;
37: die &Carp::longmess;
38: };
39:
1.16 jasper 40: package LT::OSConfig;
41:
42: use Config;
1.18 ! jasper 43: use LT::Util;
1.16 jasper 44:
45: sub new
46: {
47: my $class = shift;
1.18 ! jasper 48: # XXX: incomplete
! 49: my $self = {
1.16 jasper 50: machine_arch => $Config{'ARCH'},
1.18 ! jasper 51: ltdir => $ltdir,
! 52: };
! 53: ($self->{gnu_arch} = $self->{'machine_arch'}) =~ s/amd64/x86_64/;
! 54: bless $self, $class;
1.16 jasper 55: }
56:
1.10 espie 57: package LT::Options;
58: use Getopt::Long;
59:
60: my @valid_modes = qw(compile clean execute finish install link uninstall);
61: my @known_tags = qw(disable-shared disable-static CC CXX F77 FC GO GCJ RC);
62:
63: sub new
64: {
65: my $class = shift;
66: my $o = bless { gp => Getopt::Long::Parser->new }, $class;
67: # require_order so we stop parsing at the first non-option or argument,
68: # instead of parsing the whole ARGV.
69: $o->{gp}->configure('no_ignore_case',
70: 'pass_through',
71: 'no_auto_abbrev',
72: 'require_order');
73: return $o;
74: }
75:
76: sub add_tag
77: {
78: my ($self, $value) = @_;
79: if ($value =~ m/[^\-\w,\/]/) {
80: # XXX stupid Getopt pre-empts die !
81: say STDERR "invalid tag name: $value";
82: exit 1;
83: }
84: if (grep {$value eq $_} @known_tags) {
85: $self->{tags}{$value} = 1;
86: } else {
87: say STDERR "ignoring unknown tag: $value";
88: }
89: }
90:
91: sub has_tag
92: {
93: my ($self, $tag) = @_;
94: return defined $self->{tags}{$tag};
95: }
96:
97: sub configure
98: {
99: my $o = shift;
100: $o->{gp}->configure(@_);
101: }
102:
103: sub getoptions
104: {
105: my $o = shift;
106: $o->{gp}->getoptions(@_);
107: }
108:
109: sub is_abreviated_mode
110: {
111: my ($self, $arg) = @_;
1.15 jasper 112: return undef if !$arg;
1.10 espie 113: for my $m (@valid_modes) {
114: next if length $arg > length $m;
115: if ($arg eq substr($m, 0, length $arg)) {
116: return $m;
117: }
118: }
119: return undef;
120: }
121:
122: sub is_valid_mode
123: {
124: my ($self, $mode) = @_;
125: if (defined $mode) {
126: return grep {$_ eq $mode} @valid_modes;
127: } else {
128: return 0;
129: }
130: }
131:
132: # XXX this should always fail if we are libtool2 !
133: # try to guess libtool mode when it is not specified
134: sub guess_implicit_mode
135: {
136: my ($self, $ltprog) = @_;
137: my $m;
138: for my $a (@$ltprog) {
139: if ($a =~ m/(install([.-]sh)?|cp)$/) {
140: $m = 'install';
141: } elsif ($a =~ m/cc|c\+\+/) { # XXX improve test
142: if (grep { $_ eq '-c' } @ARGV) {
143: $m = 'compile';
144: } else {
145: $m = 'link';
146: }
147: }
148: }
149: return $m;
150: }
151:
152: sub valid_modes
153: {
154: my $self = shift;
155: return join(' ', @valid_modes);
156: }
157:
158: package main;
1.1 espie 159:
160: use subs qw(
161: create_symlinks
162: help
163: notyet
164: );
165:
1.17 espie 166: my $ltconfig = LT::OSConfig->new;
1.1 espie 167: my @no_shared_archs = qw(m88k vax);
168: my $cwd = getcwd();
1.16 jasper 169: my $instlibdir = $ENV{'LIBDIR'} // '/usr/local/lib';
1.1 espie 170:
171: my $mode;
172: my $verbose = 1;
173:
174: # just to be clear:
175: # when building a library:
176: # * -R libdir records libdir in dependency_libs
177: # * -rpath is the path where the (shared) library will be installed
178: # when building a program:
179: # * both -R libdir and -rpath libdir add libdir to the run-time path
180: # -Wl,-rpath,libdir will bypass libtool.
181:
182: # build static/shared objects?
183: my $noshared = 0;
1.16 jasper 184: if (grep { $_ eq $ltconfig->{'machine_arch'} } @no_shared_archs) {
1.1 espie 185: $noshared = 1;
186: }
187:
1.10 espie 188:
189: if ($mode = LT::Options->is_abreviated_mode($ARGV[0])) {
190: shift @ARGV;
191: }
192:
193: my $gp = LT::Options->new;
1.1 espie 194: $gp->getoptions('config' => \&config,
1.10 espie 195: 'debug' => sub {
196: LT::Trace->set($_[1]);
197: LT::Exec->verbose_run;
198: },
199: 'dry-run|n' => sub { LT::Exec->dry_run; },
200: 'features' => sub {
201: my $v = `uname -r`;
202: chomp $v;
1.18 ! jasper 203: say "host: $ltconfig->{gnu_arch}-unknown-openbsd$v";
1.10 espie 204: say "enable shared libraries" unless $noshared;
205: say "enable static libraries";
206: exit 0;
207: },
1.1 espie 208: 'finish' => sub { $mode = 'finish'; },
209: 'help' => \&help, # does not return
210: 'mode=s{1}' => \$mode,
211: 'quiet' => sub { $verbose = 0; },
212: 'silent' => sub { $verbose = 0; },
1.10 espie 213: 'tag=s{1}' => sub { $gp->add_tag($_[1]); },
214: 'version' => sub {
215: say "libtool (not (GNU libtool)) $version" ;
216: exit 0;
217: },
1.1 espie 218: );
219:
1.10 espie 220: if ($verbose) {
1.1 espie 221: LT::Exec->verbose_run;
222: }
1.10 espie 223:
1.1 espie 224: # what are we going to run (cc, c++, ...)
225: my $ltprog = [];
226: # deal with multi-arg ltprog
1.10 espie 227: tsay {"ARGV = \"@ARGV\""};
1.1 espie 228: while (@ARGV) {
229: # just read arguments until the next option...
230: if ($ARGV[0] =~ m/^\-/) { last; }
231: # XXX improve checks
232: if ($ARGV[0] =~ m/^\S+\.la/) { last; }
233: my $arg = shift @ARGV;
234: push @$ltprog, $arg;
1.10 espie 235: tsay {"arg = \"$arg\""};
1.1 espie 236: # if the current argument is an install program, stop immediately
237: if ($arg =~ /cp$/) { last; }
238: if ($arg =~ /install([-.]sh)?$/) { last; }
239: }
1.10 espie 240: tsay {"ltprog = \"@$ltprog\""};
1.14 espie 241:
242: # XXX compat game to satisfy both libtool 1 and libtool 2
243: # let libtool install work as both libtool 1 and libtool 2
244: if (@$ltprog == 0 && defined $mode && $mode eq 'install') {
245: $ltprog = [ $mode ];
246: }
1.6 jasper 247: if (@$ltprog == 0) { die "No libtool command given.\n" .
248: "Use `libtool --help' for more information.\n" };
1.1 espie 249: # make ltprog a list of elements without whitespace (prevent exec errors)
250: my @tmp_ltprog = @$ltprog;
251: @$ltprog = ();
252: for my $el (@tmp_ltprog) {
253: my @parts = split /\s+/, $el;
254: push @$ltprog, @parts;
255: }
256:
1.10 espie 257: if (!defined $mode) {
258: $mode = $gp->guess_implicit_mode($ltprog);
259: tsay {"implicit mode: ", $mode} if $mode;
260: }
261:
262: if (!$gp->is_valid_mode($mode)) {
263: say STDERR "$0: $mode: invalid argument for --mode" if defined $mode;
264: die "MODE must be one of: ", $gp->valid_modes, "\n";
1.1 espie 265: }
266:
267: # from here, options may be intermixed with arguments
268: $gp->configure('permute');
269:
270: if ($mode eq 'compile') {
1.3 espie 271: require LT::Mode::Compile;
1.10 espie 272: LT::Mode::Compile->run($ltprog, $gp, $noshared);
1.3 espie 273: } elsif ($mode eq 'install') {
274: require LT::Mode::Install;
275: LT::Mode::Install->run($ltprog);
1.1 espie 276:
277: } elsif ($mode eq 'link') {
1.3 espie 278: require LT::Mode::Link;
1.10 espie 279: LT::Mode::Link->run($ltprog, $gp, $noshared);
1.1 espie 280: } elsif ($mode eq 'finish' || $mode eq 'clean' || $mode eq 'uninstall') {
281: # don't do anything
282: exit 0;
283: } elsif ($mode eq 'execute') {
284: # XXX check whether this is right
285: LT::Exec->silent_run;
1.3 espie 286: LT::Exec->execute(@$ltprog, @ARGV);
1.1 espie 287: } else {
288: die "MODE=$mode not implemented yet.\n";
289: }
290:
291: if (LT::Exec->performed == 0) {
292: die "No commands to execute.\n"
293: }
294:
295: ###########################################################################
296:
297: sub help
298: {
299: print <<EOF
300: Usage: $0 [options]
301: --config - print configuration
302: --debug - turn on debugging output
303: --dry-run - don't do anything, only show what would be done
304: --help - this message
305: --mode=MODE - use operation mode MODE
306: --quiet - do not print informational messages
307: --silent - same as `--quiet'
1.5 jasper 308: --tag=TAG - specify a configuration variable TAG
1.1 espie 309: --version - print version of libtool
310: EOF
311: ;
312: exit 1;
313: }
314:
315: sub notyet
316: {
317: die "Option not implemented yet.\n";
318: }
319:
320: sub config
321: {
1.18 ! jasper 322: while ( my ($key, $value) = each(%$ltconfig) ) {
! 323: print "$key = $value\n";
! 324: }
1.1 espie 325: exit 0;
326: }
327:
328: sub create_symlinks
329: {
1.7 espie 330: my ($dir, $libs) = @_;
1.1 espie 331: if (! -d $dir) {
1.7 espie 332: mkdir($dir) or die "Cannot mkdir($dir) : $!\n";
1.1 espie 333: }
1.7 espie 334:
1.1 espie 335: foreach my $l (values %$libs) {
336: my $f = $l->{fullpath};
1.7 espie 337: next if !defined $f;
338: next if $f =~ m/\.a$/;
1.1 espie 339: my $libnames = [];
340: if (defined $l->{lafile}) {
341: require LT::LaFile;
342: my $lainfo = LT::LaFile->parse($l->{lafile});
343: my $librarynames = $lainfo->stringize('library_names');
344: @$libnames = split /\s/, $librarynames;
345: $libnames = reverse_zap_duplicates_ref($libnames);
346: } else {
1.3 espie 347: push @$libnames, basename($f);
1.1 espie 348: }
349: foreach my $libfile (@$libnames) {
1.4 espie 350: my $link = "$dir/$libfile";
1.10 espie 351: tsay {"ln -s $f $link"};
1.7 espie 352: next if -f $link;
353: my $p = abs_path($f);
1.8 espie 354: if (!symlink($p, $link)) {
355: die "Cannot create symlink($p, $link): $!\n"
1.9 espie 356: unless $!{EEXIST};
1.8 espie 357: }
1.1 espie 358: }
359: }
1.7 espie 360: return $dir;
1.1 espie 361: }
362: