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