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