Annotation of src/usr.bin/libtool/libtool, Revision 1.34
1.1 espie 1: #!/usr/bin/perl
1.34 ! espie 2: # $OpenBSD: libtool,v 1.33 2012/07/09 23:13:29 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);
1.23 espie 22: use Cwd qw(getcwd);
1.1 espie 23: use File::Glob ':glob';
1.3 espie 24:
1.1 espie 25: use LT::Trace;
26: use LT::Exec;
27: use LT::Util;
1.23 espie 28: use LT::Getopt;
1.1 espie 29:
1.3 espie 30: $SIG{__DIE__} = sub {
31: require Carp;
32:
33: my $_ = pop @_;
34: s/(.*)( at .*? line .*?\n$)/$1/s;
35: push @_, $_;
36: die &Carp::longmess;
37: };
38:
1.16 jasper 39: package LT::OSConfig;
40:
41: use Config;
1.18 jasper 42: use LT::Util;
1.16 jasper 43:
44: sub new
45: {
46: my $class = shift;
1.18 jasper 47: # XXX: incomplete
48: my $self = {
1.19 espie 49: machine_arch => $Config{ARCH},
1.18 jasper 50: ltdir => $ltdir,
1.24 jasper 51: version => $version,
1.33 espie 52: objdir => $ltdir,
1.34 ! espie 53: build_old_libs => 'yes',
1.24 jasper 54: pic_flags => join(' ', @picflags),
1.18 jasper 55: };
1.19 espie 56: ($self->{gnu_arch} = $self->{machine_arch}) =~ s/amd64/x86_64/;
1.22 jasper 57:
58: if (grep { $_ eq $self->{machine_arch} } qw(m88k vax)) {
1.34 ! espie 59: $self->{build_libtool_libs} = 'yes';
1.22 jasper 60: $self->{noshared} = 1;
61: } else {
1.34 ! espie 62: $self->{build_libtool_libs} = 'no';
1.22 jasper 63: $self->{noshared} = 0;
64: }
65:
1.18 jasper 66: bless $self, $class;
1.16 jasper 67: }
68:
1.20 jasper 69: sub dump
70: {
71: my $self = shift;
1.34 ! espie 72: for my $key (sort keys %$self) {
! 73: say "$key=$self->{$key}";
1.20 jasper 74: }
75: }
76:
1.19 espie 77: package LT::Mode;
1.23 espie 78: use LT::Util;
1.19 espie 79:
80: sub new
81: {
82: my ($class, $origin) = @_;
83: bless {origin => $origin }, $class;
84: }
85:
1.30 espie 86: sub load_subclass
87: {
88: my ($self, $class) = @_;
89: local $SIG{__DIE__} = 'DEFAULT';
90: eval "require $class;";
91: if ($@) {
92: unless ($@ =~ m/^Can't locate .* in \@INC/) {
93: say STDERR $@;
94: exit 1;
95: }
96: }
97: }
98:
1.19 espie 99: my $mode_maker = { compile => 'LT::Mode::Compile',
100: clean => 'LT::Mode::Clean',
101: execute => 'LT::Mode::Execute',
102: finish => 'LT::Mode::Finish',
103: install => 'LT::Mode::Install',
104: link => 'LT::Mode::Link',
105: uninstall => 'LT::Mode::Uninstall' };
106:
107: sub factory
108: {
109: my ($class, $mode, $origin) = @_;
1.30 espie 110: my $s = $mode_maker->{$mode};
111: if ($s) {
112: $class->load_subclass($s);
113: return $s->new($origin);
1.19 espie 114: } else {
1.23 espie 115: shortdie "Mode=$mode not implemented yet.\n";
1.19 espie 116: }
117: }
118:
1.26 espie 119: sub help
120: {
121: }
122:
123: sub help_all
124: {
1.30 espie 125: my $class = shift;
126: for my $s (sort values %$mode_maker) {
127: $class->load_subclass($s);
128: $s->help;
1.26 espie 129: }
130: }
131:
1.19 espie 132: package LT::Mode::Empty;
133: our @ISA = qw(LT::Mode);
134: sub run
135: {
136: exit 0;
137: }
138:
139: package LT::Mode::Clean;
140: our @ISA = qw(LT::Mode::Empty);
1.27 espie 141: sub help
142: {
143: print <<"EOH";
144:
145: Usage: $0 --mode=clean RM [RM-Option]... FILE...
146: has not been implemented.
147: It should remove files from the build directory.
148: EOH
149: }
150:
1.19 espie 151: package LT::Mode::Execute;
152: our @ISA = qw(LT::Mode);
153: sub run
154: {
155: my ($class, $ltprog, $gp, $noshared) = @_;
156: # XXX check whether this is right
157: LT::Exec->silent_run;
158: LT::Exec->execute(@$ltprog, @main::ARGV);
159: }
160:
1.27 espie 161: sub help
162: {
163: print <<"EOH";
164:
165: Usage: $0 --mode=execute COMMAND [ARGS...]
166: Run a program after setting correct library path.
167: EOH
168: }
169:
170:
1.19 espie 171: package LT::Mode::Finish;
172: our @ISA = qw(LT::Mode::Empty);
1.27 espie 173: sub help
174: {
175: print <<"EOH";
176:
177: Usage: $0 --mode=finish [LIBDIR}...
178: Complete the installation of libtool libraries.
179: Not needed for our usage.
180: EOH
181: }
1.19 espie 182:
183: package LT::Mode::Uninstall;
184: our @ISA = qw(LT::Mode::Empty);
1.27 espie 185: sub help
186: {
187: print <<"EOH";
188:
189: Usage: $0 --mode=uninstall RM [RM-OPTION]... FILE...
190: has not been implemented
191: It should remove libraries from an installation directory.
192: EOH
193: }
1.19 espie 194:
1.10 espie 195: package LT::Options;
1.23 espie 196: use LT::Util;
197: our @ISA = qw(LT::Getopt);
1.10 espie 198:
199: my @valid_modes = qw(compile clean execute finish install link uninstall);
1.19 espie 200:
1.10 espie 201: my @known_tags = qw(disable-shared disable-static CC CXX F77 FC GO GCJ RC);
202:
203: sub new
204: {
205: my $class = shift;
1.32 espie 206: my $o = bless {}, $class;
1.10 espie 207: return $o;
208: }
209:
210: sub add_tag
211: {
212: my ($self, $value) = @_;
213: if ($value =~ m/[^\-\w,\/]/) {
1.23 espie 214: shortdie "invalid tag name: $value";
1.10 espie 215: exit 1;
216: }
217: if (grep {$value eq $_} @known_tags) {
218: $self->{tags}{$value} = 1;
219: } else {
220: say STDERR "ignoring unknown tag: $value";
221: }
222: }
223:
224: sub has_tag
225: {
226: my ($self, $tag) = @_;
227: return defined $self->{tags}{$tag};
228: }
229:
230: sub getoptions
231: {
232: my $o = shift;
1.32 espie 233: require Getopt::Long;
234: my $p = Getopt::Long::Parser->new;
235: $p->configure('no_ignore_case',
236: 'pass_through',
237: 'no_auto_abbrev',
238: 'permute');
239: $p->getoptions(@_);
1.10 espie 240: }
241:
242: sub is_abreviated_mode
243: {
244: my ($self, $arg) = @_;
1.15 jasper 245: return undef if !$arg;
1.10 espie 246: for my $m (@valid_modes) {
247: next if length $arg > length $m;
248: if ($arg eq substr($m, 0, length $arg)) {
1.19 espie 249: return LT::Mode->factory($m, $arg);
1.10 espie 250: }
251: }
252: return undef;
253: }
254:
255: # XXX this should always fail if we are libtool2 !
256: # try to guess libtool mode when it is not specified
257: sub guess_implicit_mode
258: {
259: my ($self, $ltprog) = @_;
260: my $m;
261: for my $a (@$ltprog) {
262: if ($a =~ m/(install([.-]sh)?|cp)$/) {
1.29 espie 263: $m = LT::Mode->factory('install', "implicit $a");
1.10 espie 264: } elsif ($a =~ m/cc|c\+\+/) { # XXX improve test
265: if (grep { $_ eq '-c' } @ARGV) {
1.29 espie 266: $m = LT::Mode->factory('compile', "implicit");
1.10 espie 267: } else {
1.29 espie 268: $m = LT::Mode->factory('link', "implicit");
1.10 espie 269: }
270: }
271: }
272: return $m;
273: }
274:
275: sub valid_modes
276: {
277: my $self = shift;
278: return join(' ', @valid_modes);
279: }
280:
281: package main;
1.1 espie 282:
1.17 espie 283: my $ltconfig = LT::OSConfig->new;
1.1 espie 284: my $cwd = getcwd();
285: my $mode;
286: my $verbose = 1;
1.26 espie 287: my $help = 0;
1.1 espie 288:
1.31 espie 289:
290: # XXX compat game to satisfy both libtool 1 and libtool 2
291: unless ($ARGV[0] eq 'install' && $ARGV[1] =~ m/^-[bcCdpSsBfgmo]/) {
292: if ($mode = LT::Options->is_abreviated_mode($ARGV[0])) {
293: shift @ARGV;
294: }
295: }
296:
1.1 espie 297: # just to be clear:
298: # when building a library:
299: # * -R libdir records libdir in dependency_libs
300: # * -rpath is the path where the (shared) library will be installed
301: # when building a program:
302: # * both -R libdir and -rpath libdir add libdir to the run-time path
303: # -Wl,-rpath,libdir will bypass libtool.
304:
1.10 espie 305: my $gp = LT::Options->new;
1.25 espie 306: $gp->handle_options(
307: '-config' => \&config,
308: '-debug|x' => sub {
309: LT::Trace->set(1);
310: LT::Exec->verbose_run;
311: },
312: '-dry-run|-dryrun|n' => sub { LT::Exec->dry_run; },
313: '-features' => sub {
314: my $v = `uname -r`;
315: chomp $v;
316: say "host: $ltconfig->{gnu_arch}-unknown-openbsd$v";
317: say "enable shared libraries" unless $ltconfig->{noshared};
318: say "enable static libraries";
319: exit 0;
320: },
1.29 espie 321: '-finish' => sub { $mode = LT::Mode->factory('finish', '--finish'); },
1.26 espie 322: '-help|?|h' => sub { $help = 1; },
323: '-help-all' => sub { basic_help(); LT::Mode->help_all; exit 0; },
1.25 espie 324: '-mode=' => sub {
325: $mode = LT::Mode->factory($_[2], "--mode=$_[2]");
326: },
327: '-quiet|-silent|-no-verbose' => sub { $verbose = 0; },
328: '-verbose|-no-silent|-no-quiet|v' => sub {$verbose = 1;},
329: '-tag=' => sub { $gp->add_tag($_[2]); },
330: '-version' => sub {
331: say "libtool (not (GNU libtool)) $ltconfig->{version}";
332: exit 0;
333: },
1.26 espie 334: '-no-warning|-no-warn' => sub {},
1.28 espie 335: # ignored
336: '-preserve-dup-deps',
337: '-dlopen=|dlopen=@',
1.25 espie 338: );
1.1 espie 339:
1.26 espie 340: if ($help) {
341: basic_help();
342: if ($mode) {
343: $mode->help;
344: }
345: exit 0;
346: }
1.10 espie 347: if ($verbose) {
1.1 espie 348: LT::Exec->verbose_run;
349: }
1.10 espie 350:
1.1 espie 351: # what are we going to run (cc, c++, ...)
352: my $ltprog = [];
353: # deal with multi-arg ltprog
1.10 espie 354: tsay {"ARGV = \"@ARGV\""};
1.1 espie 355: while (@ARGV) {
356: # just read arguments until the next option...
357: if ($ARGV[0] =~ m/^\-/) { last; }
358: # XXX improve checks
359: if ($ARGV[0] =~ m/^\S+\.la/) { last; }
360: my $arg = shift @ARGV;
361: push @$ltprog, $arg;
1.10 espie 362: tsay {"arg = \"$arg\""};
1.1 espie 363: # if the current argument is an install program, stop immediately
364: if ($arg =~ /cp$/) { last; }
365: if ($arg =~ /install([-.]sh)?$/) { last; }
366: }
1.10 espie 367: tsay {"ltprog = \"@$ltprog\""};
1.14 espie 368:
369: # XXX compat game to satisfy both libtool 1 and libtool 2
370: # let libtool install work as both libtool 1 and libtool 2
1.19 espie 371: if (@$ltprog == 0 && defined $mode && $mode->{origin} eq 'install') {
372: $ltprog = [ 'install' ];
1.14 espie 373: }
1.31 espie 374:
1.6 jasper 375: if (@$ltprog == 0) { die "No libtool command given.\n" .
376: "Use `libtool --help' for more information.\n" };
1.1 espie 377: # make ltprog a list of elements without whitespace (prevent exec errors)
378: my @tmp_ltprog = @$ltprog;
379: @$ltprog = ();
380: for my $el (@tmp_ltprog) {
381: my @parts = split /\s+/, $el;
382: push @$ltprog, @parts;
383: }
384:
1.10 espie 385: if (!defined $mode) {
386: $mode = $gp->guess_implicit_mode($ltprog);
1.19 espie 387: tsay {"implicit mode: ", $mode->{origin}} if $mode;
1.28 espie 388: }
389:
390: if (!defined $mode) {
391: shortdie "no explicit mode, couldn't figure out implicit mode\n";
392: }
393:
394: if (!$mode->isa("LT::Mode::Execute")) {
1.29 espie 395: if ($gp->dlopen) {
1.28 espie 396: shortdie "Error: -dlopen FILE in generic libtool options is an error in non execute mode";
397: }
1.1 espie 398: }
399:
400: # from here, options may be intermixed with arguments
401:
1.22 jasper 402: $mode->run($ltprog, $gp, $ltconfig->{noshared});
1.1 espie 403:
404: if (LT::Exec->performed == 0) {
405: die "No commands to execute.\n"
406: }
407:
408: ###########################################################################
409:
1.26 espie 410: sub basic_help
1.1 espie 411: {
412: print <<EOF
413: Usage: $0 [options]
414: --config - print configuration
415: --debug - turn on debugging output
416: --dry-run - don't do anything, only show what would be done
417: --help - this message
418: --mode=MODE - use operation mode MODE
419: --quiet - do not print informational messages
420: --silent - same as `--quiet'
1.5 jasper 421: --tag=TAG - specify a configuration variable TAG
1.1 espie 422: --version - print version of libtool
423: EOF
424: ;
425: }
426:
427: sub config
428: {
1.20 jasper 429: $ltconfig->dump;
1.1 espie 430: exit 0;
431: }
432: