Annotation of src/usr.bin/libtool/libtool, Revision 1.5
1.1 espie 1: #!/usr/bin/perl
1.5 ! jasper 2: # $OpenBSD: libtool,v 1.4 2012/06/24 20:56:57 espie Exp $
1.1 espie 3:
4: # Copyright (c) 2007-2010 Steven Mestdagh <steven@openbsd.org>
5: #
6: # Permission to use, copy, modify, and distribute this software for any
7: # purpose with or without fee is hereby granted, provided that the above
8: # copyright notice and this permission notice appear in all copies.
9: #
10: # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17:
18: use strict;
19: use warnings;
20: use feature qw(say switch state);
21: use Cwd qw(getcwd abs_path);
22: use File::Basename;
23: use File::Glob ':glob';
24: use File::Path;
25: use Getopt::Long;
1.3 espie 26:
1.1 espie 27: use LT::Trace;
28: use LT::Exec;
29: use LT::Util;
30:
31:
32: package main;
1.3 espie 33: $SIG{__DIE__} = sub {
34: require Carp;
35:
36: my $_ = pop @_;
37: s/(.*)( at .*? line .*?\n$)/$1/s;
38: push @_, $_;
39: die &Carp::longmess;
40: };
41:
1.1 espie 42:
43: use subs qw(
44: create_symlinks
45: guess_implicit_mode
46: help
47: notyet
48: );
49:
50:
51:
52: use Config;
53: my @no_shared_archs = qw(m88k vax);
54: my $machine_arch = $Config{'ARCH'};
55: (my $gnu_arch = $machine_arch) =~ s/amd64/x86_64/;
56: my @valid_modes = qw(clean compile execute finish install link uninstall);
57: my $cwd = getcwd();
58: my $instlibdir = '/usr/local/lib';
59: $instlibdir = $ENV{'LIBDIR'} if defined $ENV{'LIBDIR'};
60:
61: my $mode;
62: our $D = 0; # debug flag
63: my $verbose = 1;
64:
65: my %opts; # options passed to libtool
66: my @tags; # list of --tag options passed to libtool
67:
68: # just to be clear:
69: # when building a library:
70: # * -R libdir records libdir in dependency_libs
71: # * -rpath is the path where the (shared) library will be installed
72: # when building a program:
73: # * both -R libdir and -rpath libdir add libdir to the run-time path
74: # -Wl,-rpath,libdir will bypass libtool.
75:
76: # build static/shared objects?
77: my $noshared = 0;
78: if (grep { $_ eq $machine_arch } @no_shared_archs) {
79: $noshared = 1;
80: }
81:
82: my $gp = new Getopt::Long::Parser;
83: # require_order so we stop parsing at the first non-option or argument,
84: # instead of parsing the whole ARGV.
85: $gp->configure( 'no_ignore_case',
86: 'pass_through',
87: 'no_auto_abbrev',
88: 'require_order'
89: );
90: $gp->getoptions('config' => \&config,
91: 'debug' => \$D,
92: 'dry-run|n' => sub { LT::Exec->dry_run },
93: 'features' => \¬yet,
94: 'finish' => sub { $mode = 'finish'; },
95: 'help' => \&help, # does not return
96: 'mode=s{1}' => \$mode,
97: 'quiet' => sub { $verbose = 0; },
98: 'silent' => sub { $verbose = 0; },
99: 'tag=s{1}' => \@tags,
100: 'version' => sub { say "libtool (not (GNU libtool)) $version" ; exit(0); },
101: );
102:
103: if ($verbose || $D) {
104: LT::Exec->verbose_run;
105: }
106: # what are we going to run (cc, c++, ...)
107: my $ltprog = [];
108: # deal with multi-arg ltprog
109: LT::Trace::debug {"ARGV = @ARGV\n"};
110: while (@ARGV) {
111: # just read arguments until the next option...
112: if ($ARGV[0] =~ m/^\-/) { last; }
113: # XXX improve checks
114: if ($ARGV[0] =~ m/^\S+\.la/) { last; }
115: my $arg = shift @ARGV;
116: push @$ltprog, $arg;
117: LT::Trace::debug {"arg = \"$arg\"\n"};
118: # if the current argument is an install program, stop immediately
119: if ($arg =~ /cp$/) { last; }
120: if ($arg =~ /install([-.]sh)?$/) { last; }
121: }
122: LT::Trace::debug {"ltprog = \"@$ltprog\"\n"};
123: if (@$ltprog == 0) { die "No libtool command given.\n" };
124: # make ltprog a list of elements without whitespace (prevent exec errors)
125: my @tmp_ltprog = @$ltprog;
126: @$ltprog = ();
127: for my $el (@tmp_ltprog) {
128: my @parts = split /\s+/, $el;
129: push @$ltprog, @parts;
130: }
131:
132: # check mode and guess it if needed
133: if (!($mode && grep { $_ eq $mode } @valid_modes)) {
134: $mode = guess_implicit_mode($ltprog);
135: if ($mode) {
136: LT::Trace::debug {"implicit mode: $mode\n"};
137: } else {
138: die "MODE must be one of:\n@valid_modes\n";
139: }
140: }
141:
142: # from here, options may be intermixed with arguments
143: $gp->configure('permute');
144:
145: if ($mode eq 'compile') {
1.3 espie 146: require LT::Mode::Compile;
147: LT::Mode::Compile->run($ltprog, $gp, \@tags, $noshared);
148: } elsif ($mode eq 'install') {
149: require LT::Mode::Install;
150: LT::Mode::Install->run($ltprog);
1.1 espie 151:
152: } elsif ($mode eq 'link') {
1.3 espie 153: require LT::Mode::Link;
154: LT::Mode::Link->run($ltprog, $gp, \@tags, $noshared);
1.1 espie 155: } elsif ($mode eq 'finish' || $mode eq 'clean' || $mode eq 'uninstall') {
156: # don't do anything
157: exit 0;
158: } elsif ($mode eq 'execute') {
159: # XXX check whether this is right
160: LT::Exec->silent_run;
1.3 espie 161: LT::Exec->execute(@$ltprog, @ARGV);
1.1 espie 162: } else {
163: die "MODE=$mode not implemented yet.\n";
164: }
165:
166: if (LT::Exec->performed == 0) {
167: die "No commands to execute.\n"
168: }
169:
170: ###########################################################################
171:
172: sub help
173: {
174: print <<EOF
175: Usage: $0 [options]
176: --config - print configuration
177: --debug - turn on debugging output
178: --dry-run - don't do anything, only show what would be done
179: --help - this message
180: --mode=MODE - use operation mode MODE
181: --quiet - do not print informational messages
182: --silent - same as `--quiet'
1.5 ! jasper 183: --tag=TAG - specify a configuration variable TAG
1.1 espie 184: --version - print version of libtool
185: EOF
186: ;
187: exit 1;
188: }
189:
190: sub notyet
191: {
192: die "Option not implemented yet.\n";
193: }
194:
195: # XXX incomplete
196: sub config
197: {
198: print "objdir=$ltdir\n";
199: print "arch=$machine_arch\n";
200: print "...\n";
201: exit 0;
202: }
203:
204: sub create_symlinks
205: {
206: my $dir = shift;
207: my $libs = shift;
208:
209: if (! -d $dir) {
210: mkdir $dir or die "Cannot create directory: $!\n";
211: }
212: foreach my $l (values %$libs) {
213: my $f = $l->{fullpath};
214: next if (!defined $f);
215: next if ($f =~ m/\.a$/);
216: my $libnames = [];
217: if (defined $l->{lafile}) {
218: require LT::LaFile;
219: my $lainfo = LT::LaFile->parse($l->{lafile});
220: my $librarynames = $lainfo->stringize('library_names');
221: @$libnames = split /\s/, $librarynames;
222: $libnames = reverse_zap_duplicates_ref($libnames);
223: } else {
1.3 espie 224: push @$libnames, basename($f);
1.1 espie 225: }
226: foreach my $libfile (@$libnames) {
1.4 espie 227: my $link = "$dir/$libfile";
228: LT::Trace::debug {"ln -s $f $link\n"};
229: if (! -f $link) {
230: my $p = abs_path($f);
231: if (!symlink($p, $link)) {
232: die "Cannot create symlink($p, $link): $!\n" unless $!{EEXIST};
233: }
1.1 espie 234: }
235: }
236: }
237: }
238:
239: # try to guess libtool mode when it is not specified
240: sub guess_implicit_mode
241: {
242: my $ltprog = shift;
243: my $m = 0;
244: for my $a (@$ltprog) {
245: if ($a =~ m/(install([.-]sh)?|cp)$/) {
246: $m = 'install';
247: } elsif ($a =~ m/cc|c\+\+/) { # XXX improve test
248: if (grep { $_ eq '-c' } @ARGV) {
249: $m = 'compile';
250: } else {
251: $m = 'link';
252: }
253: }
254: }
255: return $m;
256: }