Integrate mainline.
[p5sagit/p5-mst-13.2.git] / utils / perlcc.PL
CommitLineData
52cebf5e 1#!/usr/local/bin/perl
2
3use Config;
4use File::Basename qw(&basename &dirname);
de0d1968 5use File::Spec;
8a5546a1 6use Cwd;
52cebf5e 7
8# List explicitly here the variables you want Configure to
9# generate. Metaconfig only looks for shell variables, so you
10# have to mention them as if they were shell variables, not
11# %Config entries. Thus you write
12# $startperl
13# to ensure Configure will look for $Config{startperl}.
14# Wanted: $archlibexp
15
16# This forces PL files to create target in same directory as PL file.
17# This is so that make depend always knows where to find PL derivatives.
8a5546a1 18$origdir = cwd;
52cebf5e 19chdir dirname($0);
20$file = basename($0, '.PL');
21$file .= '.com' if $^O eq 'VMS';
22
23open OUT,">$file" or die "Can't create $file: $!";
24
25print "Extracting $file (with variable substitutions)\n";
26
27# In this section, perl variables will be expanded during extraction.
28# You can use $Config{...} to use Configure variables.
29
30print OUT <<"!GROK!THIS!";
31$Config{startperl}
32 eval 'exec $Config{perlpath} -S \$0 \${1+"\$@"}'
33 if \$running_under_some_shell;
ecde9bf0 34--\$running_under_some_shell;
52cebf5e 35!GROK!THIS!
36
37# In the following, perl variables are not expanded during extraction.
38
39print OUT <<'!NO!SUBS!';
40
ecde9bf0 41# Version 2.0, Simon Cozens, Thu Mar 30 17:52:45 JST 2000
42# Version 2.01, Tom Christiansen, Thu Mar 30 08:25:14 MST 2000
43# Version 2.02, Simon Cozens, Sun Apr 16 01:53:36 JST 2000
44
52cebf5e 45use strict;
ecde9bf0 46use warnings;
47use v5.6.0;
52cebf5e 48
ecde9bf0 49use Config;
50use Fcntl qw(:DEFAULT :flock);
51use File::Temp qw(tempfile);
52use Cwd;
53our $VERSION = 2.02;
54$| = 1;
52cebf5e 55
ecde9bf0 56use subs qw{
57 cc_harness check_read check_write checkopts_byte choose_backend
58 compile_byte compile_cstyle compile_module generate_code
59 grab_stash parse_argv sanity_check vprint yclept spawnit
60};
61sub opt(*); # imal quoting
52cebf5e 62
ecde9bf0 63our ($Options, $BinPerl, $Backend);
64our ($Input => $Output);
ef712cf7 65
ecde9bf0 66# eval { main(); 1 } or die;
52cebf5e 67
68main();
69
ecde9bf0 70sub main {
71 parse_argv();
72 check_write($Output);
73 choose_backend();
74 generate_code();
75 die "XXX: Not reached?";
76 exit(0);
52cebf5e 77}
9636a016 78
ecde9bf0 79#######################################################################
52cebf5e 80
ecde9bf0 81sub choose_backend {
82 # Choose the backend.
83 $Backend = 'C';
84 if (opt(B)) {
85 checkopts_byte();
86 $Backend = 'Bytecode';
52cebf5e 87 }
ecde9bf0 88 if (opt(S) && opt(c)) {
89 # die "$0: Do you want me to compile this or not?\n";
90 delete $Options->{S};
52cebf5e 91 }
ecde9bf0 92 $Backend = 'CC' if opt(O);
52cebf5e 93}
94
52cebf5e 95
ecde9bf0 96sub generate_code {
a07043ec 97
ecde9bf0 98 vprint 0, "Compiling $Input";
9636a016 99
ecde9bf0 100 $BinPerl = yclept(); # Calling convention for perl.
52cebf5e 101
ecde9bf0 102 if (opt(shared)) {
103 compile_module();
104 } else {
105 if ($Backend eq 'Bytecode') {
106 compile_byte();
107 } else {
108 compile_cstyle();
109 }
52cebf5e 110 }
52cebf5e 111
52cebf5e 112}
113
ecde9bf0 114# usage: vprint [level] msg args
115sub vprint {
116 my $level;
117 if (@_ == 1) {
118 $level = 1;
119 } elsif ($_[0] =~ /^\d$/) {
120 $level = shift;
121 } else {
122 # well, they forgot to use a number; means >0
123 $level = 0;
124 }
125 my $msg = "@_";
126 $msg .= "\n" unless substr($msg, -1) eq "\n";
127 print "$0: $msg" if opt(v) > $level;
128}
129
130sub parse_argv {
131
132 use Getopt::Long;
133 Getopt::Long::Configure("bundling");
134 Getopt::Long::Configure("no_ignore_case");
135
136 # no difference in exists and defined for %ENV; also, a "0"
137 # argument or a "" would not help cc, so skip
138 unshift @ARGV, split ' ', $ENV{PERLCC_OPTS} if $ENV{PERLCC_OPTS};
139
140 $Options = {};
141 Getopt::Long::GetOptions( $Options,
142 'L:s', # lib directory
143 'I:s', # include directories (FOR C, NOT FOR PERL)
144 'o:s', # Output executable
145 'v+', # Verbosity level
146 'e:s', # One-liner
147 'B', # Byte compiler backend
148 'O', # Optimised C backend
149 'c', # Compile only
150 'h', # Help me
151 'S', # Dump C files
152 's:s', # Dirty hack to enable -shared/-static
153 'shared', # Create a shared library (--shared for compat.)
154 );
155
156 # This is an attempt to make perlcc's arg. handling look like cc.
157 if ( opt('s') ) { # must quote: looks like s)foo)bar)!
158 if (opt('s') eq 'hared') {
159 $Options->{shared}++;
160 } elsif (opt('s') eq 'tatic') {
161 $Options->{static}++;
162 } else {
163 warn "$0: Unknown option -s", opt('s');
164 }
52cebf5e 165 }
166
ecde9bf0 167 $Options->{v} += 0;
52cebf5e 168
ecde9bf0 169 helpme() if opt(h); # And exit
ef712cf7 170
ecde9bf0 171 $Output = opt(o) || 'a.out';
ef712cf7 172
ecde9bf0 173 if (opt(e)) {
174 warn "$0: using -e 'code' as input file, ignoring @ARGV\n" if @ARGV;
175 # We don't use a temporary file here; why bother?
176 # XXX: this is not bullet proof -- spaces or quotes in name!
177 $Input = "-e '".opt(e)."'"; # Quotes eaten by shell
178 } else {
179 $Input = shift @ARGV; # XXX: more files?
180 die "$0: No input file specified\n" unless $Input;
181 # DWIM modules. This is bad but necessary.
182 $Options->{shared}++ if $Input =~ /\.pm\z/;
183 warn "$0: using $Input as input file, ignoring @ARGV\n" if @ARGV;
184 check_read($Input);
185 check_perl($Input);
186 sanity_check();
52cebf5e 187 }
188
ecde9bf0 189}
5268c7a4 190
ecde9bf0 191sub opt(*) {
192 my $opt = shift;
193 return exists($Options->{$opt}) && ($Options->{$opt} || 0);
194}
52cebf5e 195
ecde9bf0 196sub compile_module {
197 die "$0: Compiling to shared libraries is currently disabled\n";
52cebf5e 198}
199
ecde9bf0 200sub compile_byte {
201 require ByteLoader;
202 my $stash = grab_stash();
203 my $command = "$BinPerl -MO=Bytecode,$stash $Input";
204 # The -a option means we'd have to close the file and lose the
205 # lock, which would create the tiniest of races. Instead, append
206 # the output ourselves.
207 vprint 1, "Writing on $Output";
52cebf5e 208
ecde9bf0 209 my $openflags = O_WRONLY | O_CREAT;
210 $openflags |= O_BINARY if eval { O_BINARY; 1 };
211 $openflags |= O_EXLOCK if eval { O_EXLOCK; 1 };
ef712cf7 212
ecde9bf0 213 # these dies are not "$0: .... \n" because they "can't happen"
ef712cf7 214
ecde9bf0 215 sysopen(OUT, $Output, $openflags)
216 or die "can't write to $Output: $!";
52cebf5e 217
ecde9bf0 218 # this is blocking; hold on; why are we doing this??
219 # flock OUT, LOCK_EX or die "can't lock $Output: $!"
220 # unless eval { O_EXLOCK; 1 };
52cebf5e 221
ecde9bf0 222 truncate(OUT, 0)
223 or die "couldn't trunc $Output: $!";
52cebf5e 224
ecde9bf0 225 print OUT <<EOF;
226#!$^X
227use ByteLoader $ByteLoader::VERSION;
52cebf5e 228EOF
229
ecde9bf0 230 # Now the compile:
231 vprint 1, "Compiling...";
232 vprint 3, "Calling $command";
52cebf5e 233
d873810b 234 my ($output_r, $error_r) = spawnit($command);
52cebf5e 235
d873810b 236 if (@$error_r && $? != 0) {
237 die "$0: $Input did not compile, which can't happen:\n@$error_r\n";
238 } else {
239 my @error = grep { !/^$Input syntax OK$/o } @$error_r;
240 warn "$0: Unexpected compiler output:\n@error" if @error;
ef712cf7 241 }
d873810b 242
ecde9bf0 243 # Write it and leave.
d873810b 244 print OUT @$output_r or die "can't write $Output: $!";
245 close OUT or die "can't close $Output: $!";
52cebf5e 246
ecde9bf0 247 # wait, how could it be anything but what you see next?
248 chmod 0777 & ~umask, $Output or die "can't chmod $Output: $!";
249 exit 0;
52cebf5e 250}
52cebf5e 251
ecde9bf0 252sub compile_cstyle {
253 my $stash = grab_stash();
ef712cf7 254
ecde9bf0 255 # What are we going to call our output C file?
256 my ($cfile,$cfh);
257 my $lose = 0;
258 if (opt(S) || opt(c)) {
259 # We need to keep it.
260 if (opt(e)) {
261 $cfile = "a.out.c";
262 } else {
263 $cfile = $Input;
264 # File off extension if present
265 # hold on: plx is executable; also, careful of ordering!
266 $cfile =~ s/\.(?:p(?:lx|l|h)|m)\z//i;
267 $cfile .= ".c";
268 $cfile = $Output if opt(c) && $Output =~ /\.c\z/i;
269 }
270 check_write($cfile);
271 } else {
272 # Don't need to keep it, be safe with a tempfile.
273 $lose = 1;
274 ($cfh, $cfile) = tempfile("pccXXXXX", SUFFIX => ".c");
275 close $cfh; # See comment just below
52cebf5e 276 }
ecde9bf0 277 vprint 1, "Writing C on $cfile";
52cebf5e 278
ecde9bf0 279 my $max_line_len = '';
280 if ($^O eq 'MSWin32' && $Config{cc} =~ /^cl/i) {
281 $max_line_len = '-l2000,';
282 }
52cebf5e 283
ecde9bf0 284 # This has to do the write itself, so we can't keep a lock. Life
285 # sucks.
286 my $command = "$BinPerl -MO=$Backend,$max_line_len$stash,-o$cfile $Input";
287 vprint 1, "Compiling...";
288 vprint 1, "Calling $command";
52cebf5e 289
ecde9bf0 290 my ($output_r, $error_r) = spawnit($command);
291 my @output = @$output_r;
292 my @error = @$error_r;
52cebf5e 293
ecde9bf0 294 if (@error && $? != 0) {
295 die "$0: $Input did not compile, which can't happen:\n@error\n";
296 }
52cebf5e 297
ecde9bf0 298 cc_harness($cfile,$stash) unless opt(c);
52cebf5e 299
ecde9bf0 300 if ($lose) {
301 vprint 2, "unlinking $cfile";
302 unlink $cfile or die "can't unlink $cfile: $!" if $lose;
303 }
304 exit(0);
52cebf5e 305}
306
ecde9bf0 307sub cc_harness {
308 my ($cfile,$stash)=@_;
309 use ExtUtils::Embed ();
310 my $command = ExtUtils::Embed::ccopts." -o $Output $cfile ";
3af308c7 311 $command .= " -I".$_ for split /\s+/, opt(I);
312 $command .= " -L".$_ for split /\s+/, opt(L);
ecde9bf0 313 my @mods = split /-?u /, $stash;
3af308c7 314 $command .= " ".ExtUtils::Embed::ldopts("-std", \@mods);
ecde9bf0 315 vprint 3, "running cc $command";
316 system("cc $command");
52cebf5e 317}
318
ecde9bf0 319# Where Perl is, and which include path to give it.
320sub yclept {
321 my $command = "$^X ";
322
323 # DWIM the -I to be Perl, not C, include directories.
324 if (opt(I) && $Backend eq "Bytecode") {
325 for (split /\s+/, opt(I)) {
326 if (-d $_) {
327 push @INC, $_;
328 } else {
329 warn "$0: Include directory $_ not found, skipping\n";
330 }
52cebf5e 331 }
332 }
ecde9bf0 333
334 $command .= "-I$_ " for @INC;
335 return $command;
52cebf5e 336}
337
ecde9bf0 338# Use B::Stash to find additional modules and stuff.
52cebf5e 339{
ecde9bf0 340 my $_stash;
341 sub grab_stash {
52cebf5e 342
ecde9bf0 343 warn "already called get_stash once" if $_stash;
52cebf5e 344
ecde9bf0 345 my $command = "$BinPerl -MB::Stash -c $Input";
346 # Filename here is perfectly sanitised.
347 vprint 3, "Calling $command\n";
9636a016 348
ecde9bf0 349 my ($stash_r, $error_r) = spawnit($command);
350 my @stash = @$stash_r;
351 my @error = @$error_r;
52cebf5e 352
ecde9bf0 353 if (@error && $? != 0) {
354 die "$0: $Input did not compile:\n@error\n";
355 }
52cebf5e 356
ecde9bf0 357 $stash[0] =~ s/,-u\<none\>//;
358 vprint 2, "Stash: ", join " ", split /,?-u/, $stash[0];
359 chomp $stash[0];
360 return $_stash = $stash[0];
52cebf5e 361 }
362
ecde9bf0 363}
52cebf5e 364
ecde9bf0 365# Check the consistency of options if -B is selected.
366# To wit, (-B|-O) ==> no -shared, no -S, no -c
367sub checkopts_byte {
52cebf5e 368
ecde9bf0 369 die "$0: Please choose one of either -B and -O.\n" if opt(O);
52cebf5e 370
ecde9bf0 371 if (opt(shared)) {
372 warn "$0: Will not create a shared library for bytecode\n";
373 delete $Options->{shared};
374 }
52cebf5e 375
ecde9bf0 376 for my $o ( qw[c S] ) {
377 if (opt($o)) {
378 warn "$0: Compiling to bytecode is a one-pass process--",
379 "-$o ignored\n";
380 delete $Options->{$o};
381 }
52cebf5e 382 }
383
52cebf5e 384}
385
ecde9bf0 386# Check the input and output files make sense, are read/writeable.
387sub sanity_check {
388 if ($Input eq $Output) {
389 if ($Input eq 'a.out') {
390 warn "$0: Compiling a.out is probably not what you want to do.\n";
391 # You fully deserve what you get now.
392 } else {
393 warn "$0: Will not write output on top of input file, ",
394 "compiling to a.out instead\n";
395 $Output = "a.out";
396 }
52cebf5e 397 }
398}
399
ecde9bf0 400sub check_read {
401 my $file = shift;
402 unless (-r $file) {
403 die "$0: Input file $file is a directory, not a file\n" if -d _;
404 unless (-e _) {
405 die "$0: Input file $file was not found\n";
406 } else {
407 die "$0: Cannot read input file $file: $!\n";
408 }
52cebf5e 409 }
ecde9bf0 410 unless (-f _) {
411 # XXX: die? don't try this on /dev/tty
412 warn "$0: WARNING: input $file is not a plain file\n";
413 }
52cebf5e 414}
415
ecde9bf0 416sub check_write {
417 my $file = shift;
418 if (-d $file) {
419 die "$0: Cannot write on $file, is a directory\n";
420 }
421 if (-e _) {
422 die "$0: Cannot write on $file: $!\n" unless -w _;
423 }
424 unless (-w cwd()) {
425 die "$0: Cannot write in this directory: $!\n"
ef712cf7 426 }
ef712cf7 427}
428
ecde9bf0 429sub check_perl {
430 my $file = shift;
431 unless (-T $file) {
432 warn "$0: Binary `$file' sure doesn't smell like perl source!\n";
433 print "Checking file type... ";
434 system("file", $file);
435 die "Please try a perlier file!\n";
436 }
437
438 open(my $handle, "<", $file) or die "XXX: can't open $file: $!";
439 local $_ = <$handle>;
440 if (/^#!/ && !/perl/) {
441 die "$0: $file is a ", /^#!\s*(\S+)/, " script, not perl\n";
442 }
443
444}
445
446# File spawning and error collecting
447sub spawnit {
448 my ($command) = shift;
449 my (@error,@output);
450 my $errname;
451 (undef, $errname) = tempfile("pccXXXXX");
452 {
453 open (S_OUT, "$command 2>$errname |")
454 or die "$0: Couldn't spawn the compiler.\n";
455 @output = <S_OUT>;
456 }
457 open (S_ERROR, $errname) or die "$0: Couldn't read the error file.\n";
458 @error = <S_ERROR>;
459 close S_ERROR;
460 close S_OUT;
461 unlink $errname or die "$0: Can't unlink error file $errname";
462 return (\@output, \@error);
463}
52cebf5e 464
ecde9bf0 465sub helpme {
466 print "perlcc compiler frontend, version $VERSION\n\n";
467 { no warnings;
468 exec "pod2usage $0";
469 exec "perldoc $0";
470 exec "pod2text $0";
471 }
52cebf5e 472}
473
474
475__END__
476
477=head1 NAME
478
ecde9bf0 479perlcc - generate executables from Perl programs
52cebf5e 480
481=head1 SYNOPSIS
482
ecde9bf0 483 $ perlcc hello # Compiles into executable 'a.out'
484 $ perlcc -o hello hello.pl # Compiles into executable 'hello'
52cebf5e 485
ecde9bf0 486 $ perlcc -O file # Compiles using the optimised C backend
487 $ perlcc -B file # Compiles using the bytecode backend
52cebf5e 488
ecde9bf0 489 $ perlcc -c file # Creates a C file, 'file.c'
490 $ perlcc -S -o hello file # Creates a C file, 'file.c',
491 # then compiles it to executable 'hello'
492 $ perlcc -c out.c file # Creates a C file, 'out.c' from 'file'
52cebf5e 493
ecde9bf0 494 $ perlcc -e 'print q//' # Compiles a one-liner into 'a.out'
495 $ perlcc -c -e 'print q//' # Creates a C file 'a.out.c'
496
52cebf5e 497=head1 DESCRIPTION
498
ecde9bf0 499F<perlcc> creates standalone executables from Perl programs, using the
500code generators provided by the L<B> module. At present, you may
501either create executable Perl bytecode, using the C<-B> option, or
502generate and compile C files using the standard and 'optimised' C
503backends.
52cebf5e 504
ecde9bf0 505The code generated in this way is not guaranteed to work. The whole
506codegen suite (C<perlcc> included) should be considered B<very>
507experimental. Use for production purposes is strongly discouraged.
52cebf5e 508
ecde9bf0 509=head1 OPTIONS
52cebf5e 510
511=over 4
512
ecde9bf0 513=item -LI<library directories>
52cebf5e 514
ecde9bf0 515Adds the given directories to the library search path when C code is
516passed to your C compiler.
52cebf5e 517
ecde9bf0 518=item -II<include directories>
52cebf5e 519
ecde9bf0 520Adds the given directories to the include file search path when C code is
521passed to your C compiler; when using the Perl bytecode option, adds the
522given directories to Perl's include path.
9636a016 523
ecde9bf0 524=item -o I<output file name>
9636a016 525
ecde9bf0 526Specifies the file name for the final compiled executable.
9636a016 527
ecde9bf0 528=item -c I<C file name>
9636a016 529
ecde9bf0 530Create C code only; do not compile to a standalone binary.
52cebf5e 531
ecde9bf0 532=item -e I<perl code>
52cebf5e 533
ecde9bf0 534Compile a one-liner, much the same as C<perl -e '...'>
52cebf5e 535
ecde9bf0 536=item -S
52cebf5e 537
ecde9bf0 538Do not delete generated C code after compilation.
52cebf5e 539
ecde9bf0 540=item -B
52cebf5e 541
ecde9bf0 542Use the Perl bytecode code generator.
52cebf5e 543
ecde9bf0 544=item -O
52cebf5e 545
ecde9bf0 546Use the 'optimised' C code generator. This is more experimental than
547everything else put together, and the code created is not guaranteed to
548compile in finite time and memory, or indeed, at all.
52cebf5e 549
ecde9bf0 550=item -v
52cebf5e 551
ecde9bf0 552Increase verbosity of output; can be repeated for more verbose output.
52cebf5e 553
554=back
555
52cebf5e 556=cut
557
558!NO!SUBS!
559
560close OUT or die "Can't close $file: $!";
561chmod 0755, $file or die "Can't reset permissions for $file: $!\n";
562exec("$Config{'eunicefix'} $file") if $Config{'eunicefix'} ne ':';
8a5546a1 563chdir $origdir;