Initial bulk commit for "Git on MSys"
[msysgit/historical-msysgit.git] / bin / perlcc
blob14cf3a8d69e0a79f5e79da8c847563a3edef639a
1 #!/usr/bin/perl
2 eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
3 if $running_under_some_shell;
4 --$running_under_some_shell;
6 # Version 2.0, Simon Cozens, Thu Mar 30 17:52:45 JST 2000
7 # Version 2.01, Tom Christiansen, Thu Mar 30 08:25:14 MST 2000
8 # Version 2.02, Simon Cozens, Sun Apr 16 01:53:36 JST 2000
9 # Version 2.03, Edward Peschko, Mon Feb 26 12:04:17 PST 2001
11 use strict;
12 use warnings;
13 use v5.6.0;
15 use FileHandle;
16 use Config;
17 use Fcntl qw(:DEFAULT :flock);
18 use File::Temp qw(tempfile);
19 use Cwd;
20 our $VERSION = 2.03;
21 $| = 1;
23 $SIG{INT} = sub { exit(); }; # exit gracefully and clean up after ourselves.
25 use subs qw{
26 cc_harness check_read check_write checkopts_byte choose_backend
27 compile_byte compile_cstyle compile_module generate_code
28 grab_stash parse_argv sanity_check vprint yclept spawnit
30 sub opt(*); # imal quoting
32 our ($Options, $BinPerl, $Backend);
33 our ($Input => $Output);
34 our ($logfh);
35 our ($cfile);
37 # eval { main(); 1 } or die;
39 main();
41 sub main {
42 parse_argv();
43 check_write($Output);
44 choose_backend();
45 generate_code();
46 run_code();
47 _die("XXX: Not reached?");
50 #######################################################################
52 sub choose_backend {
53 # Choose the backend.
54 $Backend = 'C';
55 if (opt(B)) {
56 checkopts_byte();
57 $Backend = 'Bytecode';
59 if (opt(S) && opt(c)) {
60 # die "$0: Do you want me to compile this or not?\n";
61 delete $Options->{S};
63 $Backend = 'CC' if opt(O);
67 sub generate_code {
69 vprint 0, "Compiling $Input";
71 $BinPerl = yclept(); # Calling convention for perl.
73 if (opt(shared)) {
74 compile_module();
75 } else {
76 if ($Backend eq 'Bytecode') {
77 compile_byte();
78 } else {
79 compile_cstyle();
82 exit(0) if (!opt('r'));
85 sub run_code {
86 vprint 0, "Running code";
87 run("$Output @ARGV");
88 exit(0);
91 # usage: vprint [level] msg args
92 sub vprint {
93 my $level;
94 if (@_ == 1) {
95 $level = 1;
96 } elsif ($_[0] =~ /^\d$/) {
97 $level = shift;
98 } else {
99 # well, they forgot to use a number; means >0
100 $level = 0;
102 my $msg = "@_";
103 $msg .= "\n" unless substr($msg, -1) eq "\n";
104 if (opt(v) > $level)
106 print "$0: $msg" if !opt('log');
107 print $logfh "$0: $msg" if opt('log');
111 sub parse_argv {
113 use Getopt::Long;
114 # Getopt::Long::Configure("bundling"); turned off. this is silly because
115 # it doesn't allow for long switches.
116 Getopt::Long::Configure("no_ignore_case");
118 # no difference in exists and defined for %ENV; also, a "0"
119 # argument or a "" would not help cc, so skip
120 unshift @ARGV, split ' ', $ENV{PERLCC_OPTS} if $ENV{PERLCC_OPTS};
122 $Options = {};
123 Getopt::Long::GetOptions( $Options,
124 'L:s', # lib directory
125 'I:s', # include directories (FOR C, NOT FOR PERL)
126 'o:s', # Output executable
127 'v:i', # Verbosity level
128 'e:s', # One-liner
129 'r', # run resulting executable
130 'B', # Byte compiler backend
131 'O', # Optimised C backend
132 'c', # Compile only
133 'h', # Help me
134 'S', # Dump C files
135 'r', # run the resulting executable
136 'static', # Dirty hack to enable -shared/-static
137 'shared', # Create a shared library (--shared for compat.)
138 'log:s' # where to log compilation process information
141 # This is an attempt to make perlcc's arg. handling look like cc.
142 # if ( opt('s') ) { # must quote: looks like s)foo)bar)!
143 # if (opt('s') eq 'hared') {
144 # $Options->{shared}++;
145 # } elsif (opt('s') eq 'tatic') {
146 # $Options->{static}++;
147 # } else {
148 # warn "$0: Unknown option -s", opt('s');
152 $Options->{v} += 0;
154 helpme() if opt(h); # And exit
156 $Output = opt(o) || 'a.out';
157 $Output = relativize($Output);
158 $logfh = new FileHandle(">> " . opt('log')) if (opt('log'));
160 if (opt(e)) {
161 warn "$0: using -e 'code' as input file, ignoring @ARGV\n" if @ARGV;
162 # We don't use a temporary file here; why bother?
163 # XXX: this is not bullet proof -- spaces or quotes in name!
164 $Input = "-e '".opt(e)."'"; # Quotes eaten by shell
165 } else {
166 $Input = shift @ARGV; # XXX: more files?
167 _usage_and_die("$0: No input file specified\n") unless $Input;
168 # DWIM modules. This is bad but necessary.
169 $Options->{shared}++ if $Input =~ /\.pm\z/;
170 warn "$0: using $Input as input file, ignoring @ARGV\n" if @ARGV;
171 check_read($Input);
172 check_perl($Input);
173 sanity_check();
178 sub opt(*) {
179 my $opt = shift;
180 return exists($Options->{$opt}) && ($Options->{$opt} || 0);
183 sub compile_module {
184 die "$0: Compiling to shared libraries is currently disabled\n";
187 sub compile_byte {
188 require ByteLoader;
189 my $stash = grab_stash();
190 my $command = "$BinPerl -MO=Bytecode,$stash $Input";
191 # The -a option means we'd have to close the file and lose the
192 # lock, which would create the tiniest of races. Instead, append
193 # the output ourselves.
194 vprint 1, "Writing on $Output";
196 my $openflags = O_WRONLY | O_CREAT;
197 $openflags |= O_BINARY if eval { O_BINARY; 1 };
198 $openflags |= O_EXLOCK if eval { O_EXLOCK; 1 };
200 # these dies are not "$0: .... \n" because they "can't happen"
202 sysopen(OUT, $Output, $openflags)
203 or die "can't write to $Output: $!";
205 # this is blocking; hold on; why are we doing this??
206 # flock OUT, LOCK_EX or die "can't lock $Output: $!"
207 # unless eval { O_EXLOCK; 1 };
209 truncate(OUT, 0)
210 or die "couldn't trunc $Output: $!";
212 print OUT <<EOF;
213 #!$^X
214 use ByteLoader $ByteLoader::VERSION;
217 # Now the compile:
218 vprint 1, "Compiling...";
219 vprint 3, "Calling $command";
221 my ($output_r, $error_r) = spawnit($command);
223 if (@$error_r && $? != 0) {
224 _die("$0: $Input did not compile, which can't happen:\n@$error_r\n");
225 } else {
226 my @error = grep { !/^$Input syntax OK$/o } @$error_r;
227 warn "$0: Unexpected compiler output:\n@error" if @error;
230 # Write it and leave.
231 print OUT @$output_r or _die("can't write $Output: $!");
232 close OUT or _die("can't close $Output: $!");
234 # wait, how could it be anything but what you see next?
235 chmod 0777 & ~umask, $Output or _die("can't chmod $Output: $!");
236 exit 0;
239 sub compile_cstyle {
240 my $stash = grab_stash();
242 # What are we going to call our output C file?
243 my $lose = 0;
244 my ($cfh);
246 if (opt(S) || opt(c)) {
247 # We need to keep it.
248 if (opt(e)) {
249 $cfile = "a.out.c";
250 } else {
251 $cfile = $Input;
252 # File off extension if present
253 # hold on: plx is executable; also, careful of ordering!
254 $cfile =~ s/\.(?:p(?:lx|l|h)|m)\z//i;
255 $cfile .= ".c";
256 $cfile = $Output if opt(c) && $Output =~ /\.c\z/i;
258 check_write($cfile);
259 } else {
260 # Don't need to keep it, be safe with a tempfile.
261 $lose = 1;
262 ($cfh, $cfile) = tempfile("pccXXXXX", SUFFIX => ".c");
263 close $cfh; # See comment just below
265 vprint 1, "Writing C on $cfile";
267 my $max_line_len = '';
268 if ($^O eq 'MSWin32' && $Config{cc} =~ /^cl/i) {
269 $max_line_len = '-l2000,';
272 # This has to do the write itself, so we can't keep a lock. Life
273 # sucks.
274 my $command = "$BinPerl -MO=$Backend,$max_line_len$stash,-o$cfile $Input";
275 vprint 1, "Compiling...";
276 vprint 1, "Calling $command";
278 my ($output_r, $error_r) = spawnit($command);
279 my @output = @$output_r;
280 my @error = @$error_r;
282 if (@error && $? != 0) {
283 _die("$0: $Input did not compile, which can't happen:\n@error\n");
286 cc_harness($cfile,$stash) unless opt(c);
288 if ($lose) {
289 vprint 2, "unlinking $cfile";
290 unlink $cfile or _die("can't unlink $cfile: $!");
294 sub cc_harness {
295 my ($cfile,$stash)=@_;
296 use ExtUtils::Embed ();
297 my $command = ExtUtils::Embed::ccopts." -o $Output $cfile ";
298 $command .= " -DUSEIMPORTLIB";
299 $command .= " -I".$_ for split /\s+/, opt(I);
300 $command .= " -L".$_ for split /\s+/, opt(L);
301 my @mods = split /-?u /, $stash;
302 $command .= " ".ExtUtils::Embed::ldopts("-std", \@mods,['-lperl5_6_1']);
303 vprint 3, "running $Config{cc} $command";
304 system("$Config{cc} $command");
307 # Where Perl is, and which include path to give it.
308 sub yclept {
309 my $command = "$^X ";
311 # DWIM the -I to be Perl, not C, include directories.
312 if (opt(I) && $Backend eq "Bytecode") {
313 for (split /\s+/, opt(I)) {
314 if (-d $_) {
315 push @INC, $_;
316 } else {
317 warn "$0: Include directory $_ not found, skipping\n";
322 $command .= "-I$_ " for @INC;
323 return $command;
326 # Use B::Stash to find additional modules and stuff.
328 my $_stash;
329 sub grab_stash {
331 warn "already called get_stash once" if $_stash;
333 my $command = "$BinPerl -MB::Stash -c $Input";
334 # Filename here is perfectly sanitised.
335 vprint 3, "Calling $command\n";
337 my ($stash_r, $error_r) = spawnit($command);
338 my @stash = @$stash_r;
339 my @error = @$error_r;
341 if (@error && $? != 0) {
342 _die("$0: $Input did not compile:\n@error\n");
345 $stash[0] =~ s/,-u\<none\>//;
346 vprint 2, "Stash: ", join " ", split /,?-u/, $stash[0];
347 chomp $stash[0];
348 return $_stash = $stash[0];
353 # Check the consistency of options if -B is selected.
354 # To wit, (-B|-O) ==> no -shared, no -S, no -c
355 sub checkopts_byte {
357 _die("$0: Please choose one of either -B and -O.\n") if opt(O);
359 if (opt(shared)) {
360 warn "$0: Will not create a shared library for bytecode\n";
361 delete $Options->{shared};
364 for my $o ( qw[c S] ) {
365 if (opt($o)) {
366 warn "$0: Compiling to bytecode is a one-pass process--",
367 "-$o ignored\n";
368 delete $Options->{$o};
374 # Check the input and output files make sense, are read/writeable.
375 sub sanity_check {
376 if ($Input eq $Output) {
377 if ($Input eq 'a.out') {
378 _die("$0: Compiling a.out is probably not what you want to do.\n");
379 # You fully deserve what you get now. No you *don't*. typos happen.
380 } else {
381 warn "$0: Will not write output on top of input file, ",
382 "compiling to a.out instead\n";
383 $Output = "a.out";
388 sub check_read {
389 my $file = shift;
390 unless (-r $file) {
391 _die("$0: Input file $file is a directory, not a file\n") if -d _;
392 unless (-e _) {
393 _die("$0: Input file $file was not found\n");
394 } else {
395 _die("$0: Cannot read input file $file: $!\n");
398 unless (-f _) {
399 # XXX: die? don't try this on /dev/tty
400 warn "$0: WARNING: input $file is not a plain file\n";
404 sub check_write {
405 my $file = shift;
406 if (-d $file) {
407 _die("$0: Cannot write on $file, is a directory\n");
409 if (-e _) {
410 _die("$0: Cannot write on $file: $!\n") unless -w _;
412 unless (-w cwd()) {
413 _die("$0: Cannot write in this directory: $!\n");
417 sub check_perl {
418 my $file = shift;
419 unless (-T $file) {
420 warn "$0: Binary `$file' sure doesn't smell like perl source!\n";
421 print "Checking file type... ";
422 system("file", $file);
423 _die("Please try a perlier file!\n");
426 open(my $handle, "<", $file) or _die("XXX: can't open $file: $!");
427 local $_ = <$handle>;
428 if (/^#!/ && !/perl/) {
429 _die("$0: $file is a ", /^#!\s*(\S+)/, " script, not perl\n");
434 # File spawning and error collecting
435 sub spawnit {
436 my ($command) = shift;
437 my (@error,@output);
438 my $errname;
439 (undef, $errname) = tempfile("pccXXXXX");
441 open (S_OUT, "$command 2>$errname |")
442 or _die("$0: Couldn't spawn the compiler.\n");
443 @output = <S_OUT>;
445 open (S_ERROR, $errname) or _die("$0: Couldn't read the error file.\n");
446 @error = <S_ERROR>;
447 close S_ERROR;
448 close S_OUT;
449 unlink $errname or _die("$0: Can't unlink error file $errname");
450 return (\@output, \@error);
453 sub helpme {
454 print "perlcc compiler frontend, version $VERSION\n\n";
455 { no warnings;
456 exec "pod2usage $0";
457 exec "perldoc $0";
458 exec "pod2text $0";
462 sub relativize {
463 my ($args) = @_;
465 return() if ($args =~ m"^[/\\]");
466 return("./$args");
469 sub _die {
470 $logfh->print(@_) if opt('log');
471 print STDERR @_;
472 exit(); # should die eventually. However, needed so that a 'make compile'
473 # can compile all the way through to the end for standard dist.
476 sub _usage_and_die {
477 _die(<<EOU);
478 $0: Usage:
479 $0 [-o executable] [-r] [-O|-B|-c|-S] [-log log] [source[.pl] | -e oneliner]
483 sub run {
484 my (@commands) = @_;
486 print interruptrun(@commands) if (!opt('log'));
487 $logfh->print(interruptrun(@commands)) if (opt('log'));
490 sub interruptrun
492 my (@commands) = @_;
494 my $command = join('', @commands);
495 local(*FD);
496 my $pid = open(FD, "$command |");
497 my $text;
499 local($SIG{HUP}) = sub { kill 9, $pid; exit };
500 local($SIG{INT}) = sub { kill 9, $pid; exit };
502 my $needalarm =
503 ($ENV{PERLCC_TIMEOUT} &&
504 $Config{'osname'} ne 'MSWin32' &&
505 $command =~ m"(^|\s)perlcc\s");
507 eval
509 local($SIG{ALRM}) = sub { die "INFINITE LOOP"; };
510 alarm($ENV{PERLCC_TIMEOUT}) if ($needalarm);
511 $text = join('', <FD>);
512 alarm(0) if ($needalarm);
515 if ($@)
517 eval { kill 'HUP', $pid };
518 vprint 0, "SYSTEM TIMEOUT (infinite loop?)\n";
521 close(FD);
522 return($text);
525 END {
526 unlink $cfile if ($cfile && !opt(S) && !opt(c));
529 __END__
531 =head1 NAME
533 perlcc - generate executables from Perl programs
535 =head1 SYNOPSIS
537 $ perlcc hello # Compiles into executable 'a.out'
538 $ perlcc -o hello hello.pl # Compiles into executable 'hello'
540 $ perlcc -O file # Compiles using the optimised C backend
541 $ perlcc -B file # Compiles using the bytecode backend
543 $ perlcc -c file # Creates a C file, 'file.c'
544 $ perlcc -S -o hello file # Creates a C file, 'file.c',
545 # then compiles it to executable 'hello'
546 $ perlcc -c out.c file # Creates a C file, 'out.c' from 'file'
548 $ perlcc -e 'print q//' # Compiles a one-liner into 'a.out'
549 $ perlcc -c -e 'print q//' # Creates a C file 'a.out.c'
551 $ perlcc -r hello # compiles 'hello' into 'a.out', runs 'a.out'.
553 $ perlcc -r hello a b c # compiles 'hello' into 'a.out', runs 'a.out'.
554 # with arguments 'a b c'
556 $ perlcc hello -log c # compiles 'hello' into 'a.out' logs compile
557 # log into 'c'.
559 =head1 DESCRIPTION
561 F<perlcc> creates standalone executables from Perl programs, using the
562 code generators provided by the L<B> module. At present, you may
563 either create executable Perl bytecode, using the C<-B> option, or
564 generate and compile C files using the standard and 'optimised' C
565 backends.
567 The code generated in this way is not guaranteed to work. The whole
568 codegen suite (C<perlcc> included) should be considered B<very>
569 experimental. Use for production purposes is strongly discouraged.
571 =head1 OPTIONS
573 =over 4
575 =item -LI<library directories>
577 Adds the given directories to the library search path when C code is
578 passed to your C compiler.
580 =item -II<include directories>
582 Adds the given directories to the include file search path when C code is
583 passed to your C compiler; when using the Perl bytecode option, adds the
584 given directories to Perl's include path.
586 =item -o I<output file name>
588 Specifies the file name for the final compiled executable.
590 =item -c I<C file name>
592 Create C code only; do not compile to a standalone binary.
594 =item -e I<perl code>
596 Compile a one-liner, much the same as C<perl -e '...'>
598 =item -S
600 Do not delete generated C code after compilation.
602 =item -B
604 Use the Perl bytecode code generator.
606 =item -O
608 Use the 'optimised' C code generator. This is more experimental than
609 everything else put together, and the code created is not guaranteed to
610 compile in finite time and memory, or indeed, at all.
612 =item -v
614 Increase verbosity of output; can be repeated for more verbose output.
616 =item -r
618 Run the resulting compiled script after compiling it.
620 =item -log
622 Log the output of compiling to a file rather than to stdout.
624 =back
626 =cut