SYN SYN
[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;
22d4bb9c 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
22d4bb9c 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;
22d4bb9c 46use warnings;
47use v5.6.0;
52cebf5e 48
22d4bb9c 49use Config;
50use Fcntl qw(:DEFAULT :flock);
51use File::Temp qw(tempfile);
52use Cwd;
53our $VERSION = 2.02;
54$| = 1;
52cebf5e 55
22d4bb9c 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
22d4bb9c 63our ($Options, $BinPerl, $Backend);
64our ($Input => $Output);
ef712cf7 65
22d4bb9c 66# eval { main(); 1 } or die;
52cebf5e 67
68main();
69
22d4bb9c 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
22d4bb9c 79#######################################################################
52cebf5e 80
22d4bb9c 81sub choose_backend {
82 # Choose the backend.
83 $Backend = 'C';
84 if (opt(B)) {
85 checkopts_byte();
86 $Backend = 'Bytecode';
52cebf5e 87 }
22d4bb9c 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 }
22d4bb9c 92 $Backend = 'CC' if opt(O);
52cebf5e 93}
94
52cebf5e 95
22d4bb9c 96sub generate_code {
a07043ec 97
22d4bb9c 98 vprint 0, "Compiling $Input";
9636a016 99
22d4bb9c 100 $BinPerl = yclept(); # Calling convention for perl.
52cebf5e 101
22d4bb9c 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
22d4bb9c 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
22d4bb9c 167 $Options->{v} += 0;
52cebf5e 168
22d4bb9c 169 helpme() if opt(h); # And exit
ef712cf7 170
22d4bb9c 171 $Output = opt(o) || 'a.out';
ef712cf7 172
22d4bb9c 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
22d4bb9c 189}
ee8c7f54 190
22d4bb9c 191sub opt(*) {
192 my $opt = shift;
193 return exists($Options->{$opt}) && ($Options->{$opt} || 0);
194}
52cebf5e 195
22d4bb9c 196sub compile_module {
197 die "$0: Compiling to shared libraries is currently disabled\n";
52cebf5e 198}
199
22d4bb9c 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
22d4bb9c 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
22d4bb9c 213 # these dies are not "$0: .... \n" because they "can't happen"
ef712cf7 214
22d4bb9c 215 sysopen(OUT, $Output, $openflags)
216 or die "can't write to $Output: $!";
52cebf5e 217
22d4bb9c 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
22d4bb9c 222 truncate(OUT, 0)
223 or die "couldn't trunc $Output: $!";
52cebf5e 224
22d4bb9c 225 print OUT <<EOF;
226#!$^X
227use ByteLoader $ByteLoader::VERSION;
52cebf5e 228EOF
229
22d4bb9c 230 # Now the compile:
231 vprint 1, "Compiling...";
232 vprint 3, "Calling $command";
52cebf5e 233
22d4bb9c 234 my ($output_r, $error_r) = spawnit($command);
52cebf5e 235
22d4bb9c 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 }
22d4bb9c 242
243 # Write it and leave.
244 print OUT @$output_r or die "can't write $Output: $!";
245 close OUT or die "can't close $Output: $!";
52cebf5e 246
22d4bb9c 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
22d4bb9c 252sub compile_cstyle {
253 my $stash = grab_stash();
ef712cf7 254
22d4bb9c 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 }
22d4bb9c 277 vprint 1, "Writing C on $cfile";
52cebf5e 278
22d4bb9c 279 my $max_line_len = '';
280 if ($^O eq 'MSWin32' && $Config{cc} =~ /^cl/i) {
281 $max_line_len = '-l2000,';
282 }
52cebf5e 283
22d4bb9c 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
22d4bb9c 290 my ($output_r, $error_r) = spawnit($command);
291 my @output = @$output_r;
292 my @error = @$error_r;
52cebf5e 293
22d4bb9c 294 if (@error && $? != 0) {
295 die "$0: $Input did not compile, which can't happen:\n@error\n";
296 }
52cebf5e 297
22d4bb9c 298 cc_harness($cfile,$stash) unless opt(c);
52cebf5e 299
22d4bb9c 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
22d4bb9c 307sub cc_harness {
308 my ($cfile,$stash)=@_;
309 use ExtUtils::Embed ();
310 my $command = ExtUtils::Embed::ccopts." -o $Output $cfile ";
311 $command .= join " -I", split /\s+/, opt(I);
312 $command .= join " -L", split /\s+/, opt(L);
313 my @mods = split /-?u /, $stash;
314 $command .= ExtUtils::Embed::ldopts("-std", \@mods);
315 vprint 3, "running cc $command";
316 system("cc $command");
52cebf5e 317}
318
22d4bb9c 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 }
22d4bb9c 333
334 $command .= "-I$_ " for @INC;
335 return $command;
52cebf5e 336}
337
22d4bb9c 338# Use B::Stash to find additional modules and stuff.
52cebf5e 339{
22d4bb9c 340 my $_stash;
341 sub grab_stash {
52cebf5e 342
22d4bb9c 343 warn "already called get_stash once" if $_stash;
52cebf5e 344
22d4bb9c 345 my $command = "$BinPerl -MB::Stash -c $Input";
346 # Filename here is perfectly sanitised.
347 vprint 3, "Calling $command\n";
9636a016 348
22d4bb9c 349 my ($stash_r, $error_r) = spawnit($command);
350 my @stash = @$stash_r;
351 my @error = @$error_r;
52cebf5e 352
22d4bb9c 353 if (@error && $? != 0) {
354 die "$0: $Input did not compile:\n@error\n";
355 }
52cebf5e 356
22d4bb9c 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
22d4bb9c 363}
52cebf5e 364
22d4bb9c 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
22d4bb9c 369 die "$0: Please choose one of either -B and -O.\n" if opt(O);
52cebf5e 370
22d4bb9c 371 if (opt(shared)) {
372 warn "$0: Will not create a shared library for bytecode\n";
373 delete $Options->{shared};
374 }
52cebf5e 375
22d4bb9c 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
22d4bb9c 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
22d4bb9c 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 }
22d4bb9c 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
22d4bb9c 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
22d4bb9c 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
22d4bb9c 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
22d4bb9c 479perlcc - generate executables from Perl programs
52cebf5e 480
481=head1 SYNOPSIS
482
22d4bb9c 483 $ perlcc hello # Compiles into executable 'a.out'
484 $ perlcc -o hello hello.pl # Compiles into executable 'hello'
52cebf5e 485
22d4bb9c 486 $ perlcc -O file # Compiles using the optimised C backend
487 $ perlcc -B file # Compiles using the bytecode backend
52cebf5e 488
22d4bb9c 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
22d4bb9c 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
22d4bb9c 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
22d4bb9c 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
22d4bb9c 509=head1 OPTIONS
52cebf5e 510
511=over 4
512
22d4bb9c 513=item -LI<library directories>
52cebf5e 514
22d4bb9c 515Adds the given directories to the library search path when C code is
516passed to your C compiler.
52cebf5e 517
22d4bb9c 518=item -II<include directories>
52cebf5e 519
22d4bb9c 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
22d4bb9c 524=item -o I<output file name>
9636a016 525
22d4bb9c 526Specifies the file name for the final compiled executable.
9636a016 527
22d4bb9c 528=item -c I<C file name>
9636a016 529
22d4bb9c 530Create C code only; do not compile to a standalone binary.
52cebf5e 531
22d4bb9c 532=item -e I<perl code>
52cebf5e 533
22d4bb9c 534Compile a one-liner, much the same as C<perl -e '...'>
52cebf5e 535
22d4bb9c 536=item -S
52cebf5e 537
22d4bb9c 538Do not delete generated C code after compilation.
52cebf5e 539
22d4bb9c 540=item -B
52cebf5e 541
22d4bb9c 542Use the Perl bytecode code generator.
52cebf5e 543
22d4bb9c 544=item -O
52cebf5e 545
22d4bb9c 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
22d4bb9c 550=item -v
52cebf5e 551
22d4bb9c 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;