xref: /onnv-gate/usr/src/cmd/perl/5.8.4/distrib/utils/perlcc.PL (revision 0:68f95e015346)
1*0Sstevel@tonic-gate#!/usr/local/bin/perl
2*0Sstevel@tonic-gate
3*0Sstevel@tonic-gateuse Config;
4*0Sstevel@tonic-gateuse File::Basename qw(&basename &dirname);
5*0Sstevel@tonic-gateuse File::Spec;
6*0Sstevel@tonic-gateuse Cwd;
7*0Sstevel@tonic-gate
8*0Sstevel@tonic-gate# List explicitly here the variables you want Configure to
9*0Sstevel@tonic-gate# generate.  Metaconfig only looks for shell variables, so you
10*0Sstevel@tonic-gate# have to mention them as if they were shell variables, not
11*0Sstevel@tonic-gate# %Config entries.  Thus you write
12*0Sstevel@tonic-gate#  $startperl
13*0Sstevel@tonic-gate# to ensure Configure will look for $Config{startperl}.
14*0Sstevel@tonic-gate# Wanted:  $archlibexp
15*0Sstevel@tonic-gate
16*0Sstevel@tonic-gate# This forces PL files to create target in same directory as PL file.
17*0Sstevel@tonic-gate# This is so that make depend always knows where to find PL derivatives.
18*0Sstevel@tonic-gate$origdir = cwd;
19*0Sstevel@tonic-gatechdir dirname($0);
20*0Sstevel@tonic-gate$file = basename($0, '.PL');
21*0Sstevel@tonic-gate$file .= '.com' if $^O eq 'VMS';
22*0Sstevel@tonic-gate
23*0Sstevel@tonic-gateopen OUT,">$file" or die "Can't create $file: $!";
24*0Sstevel@tonic-gate
25*0Sstevel@tonic-gateprint "Extracting $file (with variable substitutions)\n";
26*0Sstevel@tonic-gate
27*0Sstevel@tonic-gate# In this section, perl variables will be expanded during extraction.
28*0Sstevel@tonic-gate# You can use $Config{...} to use Configure variables.
29*0Sstevel@tonic-gate
30*0Sstevel@tonic-gateprint OUT <<"!GROK!THIS!";
31*0Sstevel@tonic-gate$Config{startperl}
32*0Sstevel@tonic-gate    eval 'exec $Config{perlpath} -S \$0 \${1+"\$@"}'
33*0Sstevel@tonic-gate    if \$running_under_some_shell;
34*0Sstevel@tonic-gate--\$running_under_some_shell;
35*0Sstevel@tonic-gate!GROK!THIS!
36*0Sstevel@tonic-gate
37*0Sstevel@tonic-gate# In the following, perl variables are not expanded during extraction.
38*0Sstevel@tonic-gate
39*0Sstevel@tonic-gateprint OUT <<'!NO!SUBS!';
40*0Sstevel@tonic-gate
41*0Sstevel@tonic-gate# Version 2.0, Simon Cozens, Thu Mar 30 17:52:45 JST 2000
42*0Sstevel@tonic-gate# Version 2.01, Tom Christiansen, Thu Mar 30 08:25:14 MST 2000
43*0Sstevel@tonic-gate# Version 2.02, Simon Cozens, Sun Apr 16 01:53:36 JST 2000
44*0Sstevel@tonic-gate# Version 2.03, Edward Peschko, Mon Feb 26 12:04:17 PST 2001
45*0Sstevel@tonic-gate# Version 2.04, Enache Adrian,Fri, 18 Jul 2003 23:15:37 +0300
46*0Sstevel@tonic-gate
47*0Sstevel@tonic-gateuse strict;
48*0Sstevel@tonic-gateuse warnings;
49*0Sstevel@tonic-gateuse 5.006_000;
50*0Sstevel@tonic-gate
51*0Sstevel@tonic-gateuse FileHandle;
52*0Sstevel@tonic-gateuse Config;
53*0Sstevel@tonic-gateuse Fcntl qw(:DEFAULT :flock);
54*0Sstevel@tonic-gateuse File::Temp qw(tempfile);
55*0Sstevel@tonic-gateuse Cwd;
56*0Sstevel@tonic-gateour $VERSION = 2.04;
57*0Sstevel@tonic-gate$| = 1;
58*0Sstevel@tonic-gate
59*0Sstevel@tonic-gate$SIG{INT} = sub { exit(); }; # exit gracefully and clean up after ourselves.
60*0Sstevel@tonic-gate
61*0Sstevel@tonic-gateuse subs qw{
62*0Sstevel@tonic-gate    cc_harness check_read check_write checkopts_byte choose_backend
63*0Sstevel@tonic-gate    compile_byte compile_cstyle compile_module generate_code
64*0Sstevel@tonic-gate    grab_stash parse_argv sanity_check vprint yclept spawnit
65*0Sstevel@tonic-gate};
66*0Sstevel@tonic-gatesub opt(*); # imal quoting
67*0Sstevel@tonic-gatesub is_win32();
68*0Sstevel@tonic-gatesub is_msvc();
69*0Sstevel@tonic-gate
70*0Sstevel@tonic-gateour ($Options, $BinPerl, $Backend);
71*0Sstevel@tonic-gateour ($Input => $Output);
72*0Sstevel@tonic-gateour ($logfh);
73*0Sstevel@tonic-gateour ($cfile);
74*0Sstevel@tonic-gateour (@begin_output); # output from BEGIN {}, for testsuite
75*0Sstevel@tonic-gate
76*0Sstevel@tonic-gate# eval { main(); 1 } or die;
77*0Sstevel@tonic-gate
78*0Sstevel@tonic-gatemain();
79*0Sstevel@tonic-gate
80*0Sstevel@tonic-gatesub main {
81*0Sstevel@tonic-gate    parse_argv();
82*0Sstevel@tonic-gate    check_write($Output);
83*0Sstevel@tonic-gate    choose_backend();
84*0Sstevel@tonic-gate    generate_code();
85*0Sstevel@tonic-gate    run_code();
86*0Sstevel@tonic-gate    _die("XXX: Not reached?");
87*0Sstevel@tonic-gate}
88*0Sstevel@tonic-gate
89*0Sstevel@tonic-gate#######################################################################
90*0Sstevel@tonic-gate
91*0Sstevel@tonic-gatesub choose_backend {
92*0Sstevel@tonic-gate    # Choose the backend.
93*0Sstevel@tonic-gate    $Backend = 'C';
94*0Sstevel@tonic-gate    if (opt(B)) {
95*0Sstevel@tonic-gate        checkopts_byte();
96*0Sstevel@tonic-gate        $Backend = 'Bytecode';
97*0Sstevel@tonic-gate    }
98*0Sstevel@tonic-gate    if (opt(S) && opt(c)) {
99*0Sstevel@tonic-gate        # die "$0: Do you want me to compile this or not?\n";
100*0Sstevel@tonic-gate        delete $Options->{S};
101*0Sstevel@tonic-gate    }
102*0Sstevel@tonic-gate    $Backend = 'CC' if opt(O);
103*0Sstevel@tonic-gate}
104*0Sstevel@tonic-gate
105*0Sstevel@tonic-gate
106*0Sstevel@tonic-gatesub generate_code {
107*0Sstevel@tonic-gate
108*0Sstevel@tonic-gate    vprint 0, "Compiling $Input";
109*0Sstevel@tonic-gate
110*0Sstevel@tonic-gate    $BinPerl  = yclept();  # Calling convention for perl.
111*0Sstevel@tonic-gate
112*0Sstevel@tonic-gate    if (opt(shared)) {
113*0Sstevel@tonic-gate        compile_module();
114*0Sstevel@tonic-gate    } else {
115*0Sstevel@tonic-gate        if ($Backend eq 'Bytecode') {
116*0Sstevel@tonic-gate            compile_byte();
117*0Sstevel@tonic-gate        } else {
118*0Sstevel@tonic-gate            compile_cstyle();
119*0Sstevel@tonic-gate        }
120*0Sstevel@tonic-gate    }
121*0Sstevel@tonic-gate    exit(0) if (!opt('r'));
122*0Sstevel@tonic-gate}
123*0Sstevel@tonic-gate
124*0Sstevel@tonic-gatesub run_code {
125*0Sstevel@tonic-gate    vprint 0, "Running code";
126*0Sstevel@tonic-gate    run("$Output @ARGV");
127*0Sstevel@tonic-gate    exit(0);
128*0Sstevel@tonic-gate}
129*0Sstevel@tonic-gate
130*0Sstevel@tonic-gate# usage: vprint [level] msg args
131*0Sstevel@tonic-gatesub vprint {
132*0Sstevel@tonic-gate    my $level;
133*0Sstevel@tonic-gate    if (@_ == 1) {
134*0Sstevel@tonic-gate        $level = 1;
135*0Sstevel@tonic-gate    } elsif ($_[0] =~ /^\d$/) {
136*0Sstevel@tonic-gate        $level = shift;
137*0Sstevel@tonic-gate    } else {
138*0Sstevel@tonic-gate        # well, they forgot to use a number; means >0
139*0Sstevel@tonic-gate        $level = 0;
140*0Sstevel@tonic-gate    }
141*0Sstevel@tonic-gate    my $msg = "@_";
142*0Sstevel@tonic-gate    $msg .= "\n" unless substr($msg, -1) eq "\n";
143*0Sstevel@tonic-gate    if (opt(v) > $level)
144*0Sstevel@tonic-gate    {
145*0Sstevel@tonic-gate         print        "$0: $msg" if !opt('log');
146*0Sstevel@tonic-gate	 print $logfh "$0: $msg" if  opt('log');
147*0Sstevel@tonic-gate    }
148*0Sstevel@tonic-gate}
149*0Sstevel@tonic-gate
150*0Sstevel@tonic-gatesub parse_argv {
151*0Sstevel@tonic-gate
152*0Sstevel@tonic-gate    use Getopt::Long;
153*0Sstevel@tonic-gate
154*0Sstevel@tonic-gate    # disallows using long arguments
155*0Sstevel@tonic-gate    # Getopt::Long::Configure("bundling");
156*0Sstevel@tonic-gate
157*0Sstevel@tonic-gate    Getopt::Long::Configure("no_ignore_case");
158*0Sstevel@tonic-gate
159*0Sstevel@tonic-gate    # no difference in exists and defined for %ENV; also, a "0"
160*0Sstevel@tonic-gate    # argument or a "" would not help cc, so skip
161*0Sstevel@tonic-gate    unshift @ARGV, split ' ', $ENV{PERLCC_OPTS} if $ENV{PERLCC_OPTS};
162*0Sstevel@tonic-gate
163*0Sstevel@tonic-gate    $Options = {};
164*0Sstevel@tonic-gate    Getopt::Long::GetOptions( $Options,
165*0Sstevel@tonic-gate        'L:s',          # lib directory
166*0Sstevel@tonic-gate        'I:s',          # include directories (FOR C, NOT FOR PERL)
167*0Sstevel@tonic-gate        'o:s',          # Output executable
168*0Sstevel@tonic-gate        'v:i',          # Verbosity level
169*0Sstevel@tonic-gate        'e:s',          # One-liner
170*0Sstevel@tonic-gate	'r',            # run resulting executable
171*0Sstevel@tonic-gate        'B',            # Byte compiler backend
172*0Sstevel@tonic-gate        'O',            # Optimised C backend
173*0Sstevel@tonic-gate        'c',            # Compile only
174*0Sstevel@tonic-gate        'h',            # Help me
175*0Sstevel@tonic-gate        'S',            # Dump C files
176*0Sstevel@tonic-gate	'r',            # run the resulting executable
177*0Sstevel@tonic-gate        'T',            # run the backend using perl -T
178*0Sstevel@tonic-gate        't',            # run the backend using perl -t
179*0Sstevel@tonic-gate        'static',       # Dirty hack to enable -shared/-static
180*0Sstevel@tonic-gate        'shared',       # Create a shared library (--shared for compat.)
181*0Sstevel@tonic-gate	'log:s',        # where to log compilation process information
182*0Sstevel@tonic-gate        'Wb:s',         # pass (comma-sepearated) options to backend
183*0Sstevel@tonic-gate        'testsuite',    # try to be nice to testsuite
184*0Sstevel@tonic-gate    );
185*0Sstevel@tonic-gate
186*0Sstevel@tonic-gate    $Options->{v} += 0;
187*0Sstevel@tonic-gate
188*0Sstevel@tonic-gate    if( opt(t) && opt(T) ) {
189*0Sstevel@tonic-gate        warn "Can't specify both -T and -t, -t ignored";
190*0Sstevel@tonic-gate        $Options->{t} = 0;
191*0Sstevel@tonic-gate    }
192*0Sstevel@tonic-gate
193*0Sstevel@tonic-gate    helpme() if opt(h); # And exit
194*0Sstevel@tonic-gate
195*0Sstevel@tonic-gate    $Output = opt(o) || ( is_win32 ? 'a.exe' : 'a.out' );
196*0Sstevel@tonic-gate    $Output = is_win32() ? $Output : relativize($Output);
197*0Sstevel@tonic-gate    $logfh  = new FileHandle(">> " . opt('log')) if (opt('log'));
198*0Sstevel@tonic-gate
199*0Sstevel@tonic-gate    if (opt(e)) {
200*0Sstevel@tonic-gate        warn "$0: using -e 'code' as input file, ignoring @ARGV\n" if @ARGV;
201*0Sstevel@tonic-gate        # We don't use a temporary file here; why bother?
202*0Sstevel@tonic-gate        # XXX: this is not bullet proof -- spaces or quotes in name!
203*0Sstevel@tonic-gate        $Input = is_win32() ? # Quotes eaten by shell
204*0Sstevel@tonic-gate            '-e "'.opt(e).'"' :
205*0Sstevel@tonic-gate            "-e '".opt(e)."'";
206*0Sstevel@tonic-gate    } else {
207*0Sstevel@tonic-gate        $Input = shift @ARGV;  # XXX: more files?
208*0Sstevel@tonic-gate        _usage_and_die("$0: No input file specified\n") unless $Input;
209*0Sstevel@tonic-gate        # DWIM modules. This is bad but necessary.
210*0Sstevel@tonic-gate        $Options->{shared}++ if $Input =~ /\.pm\z/;
211*0Sstevel@tonic-gate        warn "$0: using $Input as input file, ignoring @ARGV\n" if @ARGV;
212*0Sstevel@tonic-gate        check_read($Input);
213*0Sstevel@tonic-gate        check_perl($Input);
214*0Sstevel@tonic-gate        sanity_check();
215*0Sstevel@tonic-gate    }
216*0Sstevel@tonic-gate
217*0Sstevel@tonic-gate}
218*0Sstevel@tonic-gate
219*0Sstevel@tonic-gatesub opt(*) {
220*0Sstevel@tonic-gate    my $opt = shift;
221*0Sstevel@tonic-gate    return exists($Options->{$opt}) && ($Options->{$opt} || 0);
222*0Sstevel@tonic-gate}
223*0Sstevel@tonic-gate
224*0Sstevel@tonic-gatesub compile_module {
225*0Sstevel@tonic-gate    die "$0: Compiling to shared libraries is currently disabled\n";
226*0Sstevel@tonic-gate}
227*0Sstevel@tonic-gate
228*0Sstevel@tonic-gatesub compile_byte {
229*0Sstevel@tonic-gate    my $command = "$BinPerl -MO=Bytecode,-H,-o$Output $Input";
230*0Sstevel@tonic-gate    $Input =~ s/^-e.*$/-e/;
231*0Sstevel@tonic-gate
232*0Sstevel@tonic-gate    my ($output_r, $error_r) = spawnit($command);
233*0Sstevel@tonic-gate
234*0Sstevel@tonic-gate    if (@$error_r && $? != 0) {
235*0Sstevel@tonic-gate	_die("$0: $Input did not compile:\n@$error_r\n");
236*0Sstevel@tonic-gate    } else {
237*0Sstevel@tonic-gate	my @error = grep { !/^$Input syntax OK$/o } @$error_r;
238*0Sstevel@tonic-gate	warn "$0: Unexpected compiler output:\n@error" if @error;
239*0Sstevel@tonic-gate    }
240*0Sstevel@tonic-gate
241*0Sstevel@tonic-gate    chmod 0777 & ~umask, $Output    or _die("can't chmod $Output: $!");
242*0Sstevel@tonic-gate    exit 0;
243*0Sstevel@tonic-gate}
244*0Sstevel@tonic-gate
245*0Sstevel@tonic-gatesub compile_cstyle {
246*0Sstevel@tonic-gate    my $stash = grab_stash();
247*0Sstevel@tonic-gate    my $taint = opt(T) ? '-T' :
248*0Sstevel@tonic-gate                opt(t) ? '-t' : '';
249*0Sstevel@tonic-gate
250*0Sstevel@tonic-gate    # What are we going to call our output C file?
251*0Sstevel@tonic-gate    my $lose = 0;
252*0Sstevel@tonic-gate    my ($cfh);
253*0Sstevel@tonic-gate    my $testsuite = '';
254*0Sstevel@tonic-gate    my $addoptions = opt(Wb);
255*0Sstevel@tonic-gate
256*0Sstevel@tonic-gate    if( $addoptions ) {
257*0Sstevel@tonic-gate        $addoptions .= ',' if $addoptions !~ m/,$/;
258*0Sstevel@tonic-gate    }
259*0Sstevel@tonic-gate
260*0Sstevel@tonic-gate    if (opt(testsuite)) {
261*0Sstevel@tonic-gate        my $bo = join '', @begin_output;
262*0Sstevel@tonic-gate        $bo =~ s/\\/\\\\\\\\/gs;
263*0Sstevel@tonic-gate        $bo =~ s/\n/\\n/gs;
264*0Sstevel@tonic-gate        $bo =~ s/,/\\054/gs;
265*0Sstevel@tonic-gate        # don't look at that: it hurts
266*0Sstevel@tonic-gate        $testsuite = q{-fuse-script-name,-fsave-data,-fsave-sig-hash,}.
267*0Sstevel@tonic-gate            qq[-e"print q{$bo}",] .
268*0Sstevel@tonic-gate            q{-e"open(Test::Builder::TESTOUT\054 '>&STDOUT') or die $!",} .
269*0Sstevel@tonic-gate            q{-e"open(Test::Builder::TESTERR\054 '>&STDERR') or die $!",};
270*0Sstevel@tonic-gate    }
271*0Sstevel@tonic-gate    if (opt(S) || opt(c)) {
272*0Sstevel@tonic-gate        # We need to keep it.
273*0Sstevel@tonic-gate        if (opt(e)) {
274*0Sstevel@tonic-gate            $cfile = "a.out.c";
275*0Sstevel@tonic-gate        } else {
276*0Sstevel@tonic-gate            $cfile = $Input;
277*0Sstevel@tonic-gate            # File off extension if present
278*0Sstevel@tonic-gate            # hold on: plx is executable; also, careful of ordering!
279*0Sstevel@tonic-gate            $cfile =~ s/\.(?:p(?:lx|l|h)|m)\z//i;
280*0Sstevel@tonic-gate            $cfile .= ".c";
281*0Sstevel@tonic-gate            $cfile = $Output if opt(c) && $Output =~ /\.c\z/i;
282*0Sstevel@tonic-gate        }
283*0Sstevel@tonic-gate        check_write($cfile);
284*0Sstevel@tonic-gate    } else {
285*0Sstevel@tonic-gate        # Don't need to keep it, be safe with a tempfile.
286*0Sstevel@tonic-gate        $lose = 1;
287*0Sstevel@tonic-gate        ($cfh, $cfile) = tempfile("pccXXXXX", SUFFIX => ".c");
288*0Sstevel@tonic-gate        close $cfh; # See comment just below
289*0Sstevel@tonic-gate    }
290*0Sstevel@tonic-gate    vprint 1, "Writing C on $cfile";
291*0Sstevel@tonic-gate
292*0Sstevel@tonic-gate    my $max_line_len = '';
293*0Sstevel@tonic-gate    if ($^O eq 'MSWin32' && $Config{cc} =~ /^cl/i) {
294*0Sstevel@tonic-gate        $max_line_len = '-l2000,';
295*0Sstevel@tonic-gate    }
296*0Sstevel@tonic-gate
297*0Sstevel@tonic-gate    # This has to do the write itself, so we can't keep a lock. Life
298*0Sstevel@tonic-gate    # sucks.
299*0Sstevel@tonic-gate    my $command = "$BinPerl $taint -MO=$Backend,$addoptions$testsuite$max_line_len$stash,-o$cfile $Input";
300*0Sstevel@tonic-gate    vprint 1, "Compiling...";
301*0Sstevel@tonic-gate    vprint 1, "Calling $command";
302*0Sstevel@tonic-gate
303*0Sstevel@tonic-gate	my ($output_r, $error_r) = spawnit($command);
304*0Sstevel@tonic-gate	my @output = @$output_r;
305*0Sstevel@tonic-gate	my @error = @$error_r;
306*0Sstevel@tonic-gate
307*0Sstevel@tonic-gate    if (@error && $? != 0) {
308*0Sstevel@tonic-gate        _die("$0: $Input did not compile, which can't happen:\n@error\n");
309*0Sstevel@tonic-gate    }
310*0Sstevel@tonic-gate
311*0Sstevel@tonic-gate    is_msvc ?
312*0Sstevel@tonic-gate        cc_harness_msvc($cfile,$stash) :
313*0Sstevel@tonic-gate        cc_harness($cfile,$stash) unless opt(c);
314*0Sstevel@tonic-gate
315*0Sstevel@tonic-gate    if ($lose) {
316*0Sstevel@tonic-gate        vprint 2, "unlinking $cfile";
317*0Sstevel@tonic-gate        unlink $cfile or _die("can't unlink $cfile: $!");
318*0Sstevel@tonic-gate    }
319*0Sstevel@tonic-gate}
320*0Sstevel@tonic-gate
321*0Sstevel@tonic-gatesub cc_harness_msvc {
322*0Sstevel@tonic-gate    my ($cfile,$stash)=@_;
323*0Sstevel@tonic-gate    use ExtUtils::Embed ();
324*0Sstevel@tonic-gate    my $obj = "${Output}.obj";
325*0Sstevel@tonic-gate    my $compile = ExtUtils::Embed::ccopts." -c -Fo$obj $cfile ";
326*0Sstevel@tonic-gate    my $link = "-out:$Output $obj";
327*0Sstevel@tonic-gate    $compile .= " -I".$_ for split /\s+/, opt(I);
328*0Sstevel@tonic-gate    $link .= " -libpath:".$_ for split /\s+/, opt(L);
329*0Sstevel@tonic-gate    my @mods = split /-?u /, $stash;
330*0Sstevel@tonic-gate    $link .= " ".ExtUtils::Embed::ldopts("-std", \@mods);
331*0Sstevel@tonic-gate    $link .= " perl5$Config{PERL_VERSION}.lib kernel32.lib msvcrt.lib";
332*0Sstevel@tonic-gate    vprint 3, "running $Config{cc} $compile";
333*0Sstevel@tonic-gate    system("$Config{cc} $compile");
334*0Sstevel@tonic-gate    vprint 3, "running $Config{ld} $link";
335*0Sstevel@tonic-gate    system("$Config{ld} $link");
336*0Sstevel@tonic-gate}
337*0Sstevel@tonic-gate
338*0Sstevel@tonic-gatesub cc_harness {
339*0Sstevel@tonic-gate	my ($cfile,$stash)=@_;
340*0Sstevel@tonic-gate	use ExtUtils::Embed ();
341*0Sstevel@tonic-gate	my $command = ExtUtils::Embed::ccopts." -o $Output $cfile ";
342*0Sstevel@tonic-gate	$command .= " -I".$_ for split /\s+/, opt(I);
343*0Sstevel@tonic-gate	$command .= " -L".$_ for split /\s+/, opt(L);
344*0Sstevel@tonic-gate	my @mods = split /-?u /, $stash;
345*0Sstevel@tonic-gate	$command .= " ".ExtUtils::Embed::ldopts("-std", \@mods);
346*0Sstevel@tonic-gate        $command .= " -lperl";
347*0Sstevel@tonic-gate	vprint 3, "running $Config{cc} $command";
348*0Sstevel@tonic-gate	system("$Config{cc} $command");
349*0Sstevel@tonic-gate}
350*0Sstevel@tonic-gate
351*0Sstevel@tonic-gate# Where Perl is, and which include path to give it.
352*0Sstevel@tonic-gatesub yclept {
353*0Sstevel@tonic-gate    my $command = "$^X ";
354*0Sstevel@tonic-gate
355*0Sstevel@tonic-gate    # DWIM the -I to be Perl, not C, include directories.
356*0Sstevel@tonic-gate    if (opt(I) && $Backend eq "Bytecode") {
357*0Sstevel@tonic-gate        for (split /\s+/, opt(I)) {
358*0Sstevel@tonic-gate            if (-d $_) {
359*0Sstevel@tonic-gate                push @INC, $_;
360*0Sstevel@tonic-gate            } else {
361*0Sstevel@tonic-gate                warn "$0: Include directory $_ not found, skipping\n";
362*0Sstevel@tonic-gate            }
363*0Sstevel@tonic-gate        }
364*0Sstevel@tonic-gate    }
365*0Sstevel@tonic-gate
366*0Sstevel@tonic-gate    $command .= "-I$_ " for @INC;
367*0Sstevel@tonic-gate    return $command;
368*0Sstevel@tonic-gate}
369*0Sstevel@tonic-gate
370*0Sstevel@tonic-gate# Use B::Stash to find additional modules and stuff.
371*0Sstevel@tonic-gate{
372*0Sstevel@tonic-gate    my $_stash;
373*0Sstevel@tonic-gate    sub grab_stash {
374*0Sstevel@tonic-gate
375*0Sstevel@tonic-gate        warn "already called get_stash once" if $_stash;
376*0Sstevel@tonic-gate
377*0Sstevel@tonic-gate        my $taint = opt(T) ? '-T' :
378*0Sstevel@tonic-gate                    opt(t) ? '-t' : '';
379*0Sstevel@tonic-gate        my $command = "$BinPerl $taint -MB::Stash -c $Input";
380*0Sstevel@tonic-gate        # Filename here is perfectly sanitised.
381*0Sstevel@tonic-gate        vprint 3, "Calling $command\n";
382*0Sstevel@tonic-gate
383*0Sstevel@tonic-gate		my ($stash_r, $error_r) = spawnit($command);
384*0Sstevel@tonic-gate		my @stash = @$stash_r;
385*0Sstevel@tonic-gate		my @error = @$error_r;
386*0Sstevel@tonic-gate
387*0Sstevel@tonic-gate    	if (@error && $? != 0) {
388*0Sstevel@tonic-gate            _die("$0: $Input did not compile:\n@error\n");
389*0Sstevel@tonic-gate        }
390*0Sstevel@tonic-gate
391*0Sstevel@tonic-gate        # band-aid for modules with noisy BEGIN {}
392*0Sstevel@tonic-gate        foreach my $i ( @stash ) {
393*0Sstevel@tonic-gate            $i =~ m/-u(?:[\w:]+|\<none\>)$/ and $stash[0] = $i and next;
394*0Sstevel@tonic-gate            push @begin_output, $i;
395*0Sstevel@tonic-gate        }
396*0Sstevel@tonic-gate        chomp $stash[0];
397*0Sstevel@tonic-gate        $stash[0] =~ s/,-u\<none\>//;
398*0Sstevel@tonic-gate        $stash[0] =~ s/^.*?-u/-u/s;
399*0Sstevel@tonic-gate        vprint 2, "Stash: ", join " ", split /,?-u/, $stash[0];
400*0Sstevel@tonic-gate        chomp $stash[0];
401*0Sstevel@tonic-gate        return $_stash = $stash[0];
402*0Sstevel@tonic-gate    }
403*0Sstevel@tonic-gate
404*0Sstevel@tonic-gate}
405*0Sstevel@tonic-gate
406*0Sstevel@tonic-gate# Check the consistency of options if -B is selected.
407*0Sstevel@tonic-gate# To wit, (-B|-O) ==> no -shared, no -S, no -c
408*0Sstevel@tonic-gatesub checkopts_byte {
409*0Sstevel@tonic-gate
410*0Sstevel@tonic-gate    _die("$0: Please choose one of either -B and -O.\n") if opt(O);
411*0Sstevel@tonic-gate
412*0Sstevel@tonic-gate    if (opt(shared)) {
413*0Sstevel@tonic-gate        warn "$0: Will not create a shared library for bytecode\n";
414*0Sstevel@tonic-gate        delete $Options->{shared};
415*0Sstevel@tonic-gate    }
416*0Sstevel@tonic-gate
417*0Sstevel@tonic-gate    for my $o ( qw[c S] ) {
418*0Sstevel@tonic-gate        if (opt($o)) {
419*0Sstevel@tonic-gate            warn "$0: Compiling to bytecode is a one-pass process--",
420*0Sstevel@tonic-gate                  "-$o ignored\n";
421*0Sstevel@tonic-gate            delete $Options->{$o};
422*0Sstevel@tonic-gate        }
423*0Sstevel@tonic-gate    }
424*0Sstevel@tonic-gate
425*0Sstevel@tonic-gate}
426*0Sstevel@tonic-gate
427*0Sstevel@tonic-gate# Check the input and output files make sense, are read/writeable.
428*0Sstevel@tonic-gatesub sanity_check {
429*0Sstevel@tonic-gate    if ($Input eq $Output) {
430*0Sstevel@tonic-gate        if ($Input eq 'a.out') {
431*0Sstevel@tonic-gate            _die("$0: Compiling a.out is probably not what you want to do.\n");
432*0Sstevel@tonic-gate            # You fully deserve what you get now. No you *don't*. typos happen.
433*0Sstevel@tonic-gate        } else {
434*0Sstevel@tonic-gate            warn "$0: Will not write output on top of input file, ",
435*0Sstevel@tonic-gate                "compiling to a.out instead\n";
436*0Sstevel@tonic-gate            $Output = "a.out";
437*0Sstevel@tonic-gate        }
438*0Sstevel@tonic-gate    }
439*0Sstevel@tonic-gate}
440*0Sstevel@tonic-gate
441*0Sstevel@tonic-gatesub check_read {
442*0Sstevel@tonic-gate    my $file = shift;
443*0Sstevel@tonic-gate    unless (-r $file) {
444*0Sstevel@tonic-gate        _die("$0: Input file $file is a directory, not a file\n") if -d _;
445*0Sstevel@tonic-gate        unless (-e _) {
446*0Sstevel@tonic-gate            _die("$0: Input file $file was not found\n");
447*0Sstevel@tonic-gate        } else {
448*0Sstevel@tonic-gate            _die("$0: Cannot read input file $file: $!\n");
449*0Sstevel@tonic-gate        }
450*0Sstevel@tonic-gate    }
451*0Sstevel@tonic-gate    unless (-f _) {
452*0Sstevel@tonic-gate        # XXX: die?  don't try this on /dev/tty
453*0Sstevel@tonic-gate        warn "$0: WARNING: input $file is not a plain file\n";
454*0Sstevel@tonic-gate    }
455*0Sstevel@tonic-gate}
456*0Sstevel@tonic-gate
457*0Sstevel@tonic-gatesub check_write {
458*0Sstevel@tonic-gate    my $file = shift;
459*0Sstevel@tonic-gate    if (-d $file) {
460*0Sstevel@tonic-gate        _die("$0: Cannot write on $file, is a directory\n");
461*0Sstevel@tonic-gate    }
462*0Sstevel@tonic-gate    if (-e _) {
463*0Sstevel@tonic-gate        _die("$0: Cannot write on $file: $!\n") unless -w _;
464*0Sstevel@tonic-gate    }
465*0Sstevel@tonic-gate    unless (-w cwd()) {
466*0Sstevel@tonic-gate        _die("$0: Cannot write in this directory: $!\n");
467*0Sstevel@tonic-gate    }
468*0Sstevel@tonic-gate}
469*0Sstevel@tonic-gate
470*0Sstevel@tonic-gatesub check_perl {
471*0Sstevel@tonic-gate    my $file = shift;
472*0Sstevel@tonic-gate    unless (-T $file) {
473*0Sstevel@tonic-gate        warn "$0: Binary `$file' sure doesn't smell like perl source!\n";
474*0Sstevel@tonic-gate        print "Checking file type... ";
475*0Sstevel@tonic-gate        system("file", $file);
476*0Sstevel@tonic-gate        _die("Please try a perlier file!\n");
477*0Sstevel@tonic-gate    }
478*0Sstevel@tonic-gate
479*0Sstevel@tonic-gate    open(my $handle, "<", $file)    or _die("XXX: can't open $file: $!");
480*0Sstevel@tonic-gate    local $_ = <$handle>;
481*0Sstevel@tonic-gate    if (/^#!/ && !/perl/) {
482*0Sstevel@tonic-gate        _die("$0: $file is a ", /^#!\s*(\S+)/, " script, not perl\n");
483*0Sstevel@tonic-gate    }
484*0Sstevel@tonic-gate
485*0Sstevel@tonic-gate}
486*0Sstevel@tonic-gate
487*0Sstevel@tonic-gate# File spawning and error collecting
488*0Sstevel@tonic-gatesub spawnit {
489*0Sstevel@tonic-gate	my ($command) = shift;
490*0Sstevel@tonic-gate	my (@error,@output);
491*0Sstevel@tonic-gate	my $errname;
492*0Sstevel@tonic-gate	(undef, $errname) = tempfile("pccXXXXX");
493*0Sstevel@tonic-gate	{
494*0Sstevel@tonic-gate	open (S_OUT, "$command 2>$errname |")
495*0Sstevel@tonic-gate		or _die("$0: Couldn't spawn the compiler.\n");
496*0Sstevel@tonic-gate	@output = <S_OUT>;
497*0Sstevel@tonic-gate	}
498*0Sstevel@tonic-gate	open (S_ERROR, $errname) or _die("$0: Couldn't read the error file.\n");
499*0Sstevel@tonic-gate	@error = <S_ERROR>;
500*0Sstevel@tonic-gate	close S_ERROR;
501*0Sstevel@tonic-gate	close S_OUT;
502*0Sstevel@tonic-gate	unlink $errname or _die("$0: Can't unlink error file $errname");
503*0Sstevel@tonic-gate	return (\@output, \@error);
504*0Sstevel@tonic-gate}
505*0Sstevel@tonic-gate
506*0Sstevel@tonic-gatesub helpme {
507*0Sstevel@tonic-gate       print "perlcc compiler frontend, version $VERSION\n\n";
508*0Sstevel@tonic-gate       { no warnings;
509*0Sstevel@tonic-gate       exec "pod2usage $0";
510*0Sstevel@tonic-gate       exec "perldoc $0";
511*0Sstevel@tonic-gate       exec "pod2text $0";
512*0Sstevel@tonic-gate       }
513*0Sstevel@tonic-gate}
514*0Sstevel@tonic-gate
515*0Sstevel@tonic-gatesub relativize {
516*0Sstevel@tonic-gate	my ($args) = @_;
517*0Sstevel@tonic-gate
518*0Sstevel@tonic-gate	return() if ($args =~ m"^[/\\]");
519*0Sstevel@tonic-gate	return("./$args");
520*0Sstevel@tonic-gate}
521*0Sstevel@tonic-gate
522*0Sstevel@tonic-gatesub _die {
523*0Sstevel@tonic-gate    $logfh->print(@_) if opt('log');
524*0Sstevel@tonic-gate    print STDERR @_;
525*0Sstevel@tonic-gate    exit(); # should die eventually. However, needed so that a 'make compile'
526*0Sstevel@tonic-gate            # can compile all the way through to the end for standard dist.
527*0Sstevel@tonic-gate}
528*0Sstevel@tonic-gate
529*0Sstevel@tonic-gatesub _usage_and_die {
530*0Sstevel@tonic-gate    _die(<<EOU);
531*0Sstevel@tonic-gate$0: Usage:
532*0Sstevel@tonic-gate$0 [-o executable] [-r] [-O|-B|-c|-S] [-I /foo] [-L /foo] [-log log] [source[.pl] | -e oneliner]
533*0Sstevel@tonic-gateEOU
534*0Sstevel@tonic-gate}
535*0Sstevel@tonic-gate
536*0Sstevel@tonic-gatesub run {
537*0Sstevel@tonic-gate    my (@commands) = @_;
538*0Sstevel@tonic-gate
539*0Sstevel@tonic-gate    print interruptrun(@commands) if (!opt('log'));
540*0Sstevel@tonic-gate    $logfh->print(interruptrun(@commands)) if (opt('log'));
541*0Sstevel@tonic-gate}
542*0Sstevel@tonic-gate
543*0Sstevel@tonic-gatesub interruptrun
544*0Sstevel@tonic-gate{
545*0Sstevel@tonic-gate    my (@commands) = @_;
546*0Sstevel@tonic-gate
547*0Sstevel@tonic-gate    my $command = join('', @commands);
548*0Sstevel@tonic-gate    local(*FD);
549*0Sstevel@tonic-gate    my $pid = open(FD, "$command |");
550*0Sstevel@tonic-gate    my $text;
551*0Sstevel@tonic-gate
552*0Sstevel@tonic-gate    local($SIG{HUP}) = sub { kill 9, $pid; exit };
553*0Sstevel@tonic-gate    local($SIG{INT}) = sub { kill 9, $pid; exit };
554*0Sstevel@tonic-gate
555*0Sstevel@tonic-gate    my $needalarm =
556*0Sstevel@tonic-gate          ($ENV{PERLCC_TIMEOUT} &&
557*0Sstevel@tonic-gate	  $Config{'osname'} ne 'MSWin32' &&
558*0Sstevel@tonic-gate	  $command =~ m"(^|\s)perlcc\s");
559*0Sstevel@tonic-gate
560*0Sstevel@tonic-gate    eval
561*0Sstevel@tonic-gate    {
562*0Sstevel@tonic-gate         local($SIG{ALRM}) = sub { die "INFINITE LOOP"; };
563*0Sstevel@tonic-gate         alarm($ENV{PERLCC_TIMEOUT}) if ($needalarm);
564*0Sstevel@tonic-gate	 $text = join('', <FD>);
565*0Sstevel@tonic-gate	 alarm(0) if ($needalarm);
566*0Sstevel@tonic-gate    };
567*0Sstevel@tonic-gate
568*0Sstevel@tonic-gate    if ($@)
569*0Sstevel@tonic-gate    {
570*0Sstevel@tonic-gate        eval { kill 'HUP', $pid };
571*0Sstevel@tonic-gate        vprint 0, "SYSTEM TIMEOUT (infinite loop?)\n";
572*0Sstevel@tonic-gate    }
573*0Sstevel@tonic-gate
574*0Sstevel@tonic-gate    close(FD);
575*0Sstevel@tonic-gate    return($text);
576*0Sstevel@tonic-gate}
577*0Sstevel@tonic-gate
578*0Sstevel@tonic-gatesub is_win32() { $^O =~ m/^MSWin/ }
579*0Sstevel@tonic-gatesub is_msvc() { is_win32 && $Config{cc} =~ m/^cl/i }
580*0Sstevel@tonic-gate
581*0Sstevel@tonic-gateEND {
582*0Sstevel@tonic-gate    unlink $cfile if ($cfile && !opt(S) && !opt(c));
583*0Sstevel@tonic-gate}
584*0Sstevel@tonic-gate
585*0Sstevel@tonic-gate__END__
586*0Sstevel@tonic-gate
587*0Sstevel@tonic-gate=head1 NAME
588*0Sstevel@tonic-gate
589*0Sstevel@tonic-gateperlcc - generate executables from Perl programs
590*0Sstevel@tonic-gate
591*0Sstevel@tonic-gate=head1 SYNOPSIS
592*0Sstevel@tonic-gate
593*0Sstevel@tonic-gate    $ perlcc hello              # Compiles into executable 'a.out'
594*0Sstevel@tonic-gate    $ perlcc -o hello hello.pl  # Compiles into executable 'hello'
595*0Sstevel@tonic-gate
596*0Sstevel@tonic-gate    $ perlcc -O file            # Compiles using the optimised C backend
597*0Sstevel@tonic-gate    $ perlcc -B file            # Compiles using the bytecode backend
598*0Sstevel@tonic-gate
599*0Sstevel@tonic-gate    $ perlcc -c file            # Creates a C file, 'file.c'
600*0Sstevel@tonic-gate    $ perlcc -S -o hello file   # Creates a C file, 'file.c',
601*0Sstevel@tonic-gate                                # then compiles it to executable 'hello'
602*0Sstevel@tonic-gate    $ perlcc -c out.c file      # Creates a C file, 'out.c' from 'file'
603*0Sstevel@tonic-gate
604*0Sstevel@tonic-gate    $ perlcc -e 'print q//'     # Compiles a one-liner into 'a.out'
605*0Sstevel@tonic-gate    $ perlcc -c -e 'print q//'  # Creates a C file 'a.out.c'
606*0Sstevel@tonic-gate
607*0Sstevel@tonic-gate    $ perlcc -I /foo hello	# extra headers (notice the space after -I)
608*0Sstevel@tonic-gate    $ perlcc -L /foo hello	# extra libraries (notice the space after -L)
609*0Sstevel@tonic-gate
610*0Sstevel@tonic-gate    $ perlcc -r hello           # compiles 'hello' into 'a.out', runs 'a.out'.
611*0Sstevel@tonic-gate    $ perlcc -r hello a b c     # compiles 'hello' into 'a.out', runs 'a.out'.
612*0Sstevel@tonic-gate                                # with arguments 'a b c'
613*0Sstevel@tonic-gate
614*0Sstevel@tonic-gate    $ perlcc hello -log c       # compiles 'hello' into 'a.out' logs compile
615*0Sstevel@tonic-gate                                # log into 'c'.
616*0Sstevel@tonic-gate
617*0Sstevel@tonic-gate=head1 DESCRIPTION
618*0Sstevel@tonic-gate
619*0Sstevel@tonic-gateF<perlcc> creates standalone executables from Perl programs, using the
620*0Sstevel@tonic-gatecode generators provided by the L<B> module. At present, you may
621*0Sstevel@tonic-gateeither create executable Perl bytecode, using the C<-B> option, or
622*0Sstevel@tonic-gategenerate and compile C files using the standard and 'optimised' C
623*0Sstevel@tonic-gatebackends.
624*0Sstevel@tonic-gate
625*0Sstevel@tonic-gateThe code generated in this way is not guaranteed to work. The whole
626*0Sstevel@tonic-gatecodegen suite (C<perlcc> included) should be considered B<very>
627*0Sstevel@tonic-gateexperimental. Use for production purposes is strongly discouraged.
628*0Sstevel@tonic-gate
629*0Sstevel@tonic-gate=head1 OPTIONS
630*0Sstevel@tonic-gate
631*0Sstevel@tonic-gate=over 4
632*0Sstevel@tonic-gate
633*0Sstevel@tonic-gate=item -LI<library directories>
634*0Sstevel@tonic-gate
635*0Sstevel@tonic-gateAdds the given directories to the library search path when C code is
636*0Sstevel@tonic-gatepassed to your C compiler.
637*0Sstevel@tonic-gate
638*0Sstevel@tonic-gate=item -II<include directories>
639*0Sstevel@tonic-gate
640*0Sstevel@tonic-gateAdds the given directories to the include file search path when C code is
641*0Sstevel@tonic-gatepassed to your C compiler; when using the Perl bytecode option, adds the
642*0Sstevel@tonic-gategiven directories to Perl's include path.
643*0Sstevel@tonic-gate
644*0Sstevel@tonic-gate=item -o I<output file name>
645*0Sstevel@tonic-gate
646*0Sstevel@tonic-gateSpecifies the file name for the final compiled executable.
647*0Sstevel@tonic-gate
648*0Sstevel@tonic-gate=item -c I<C file name>
649*0Sstevel@tonic-gate
650*0Sstevel@tonic-gateCreate C code only; do not compile to a standalone binary.
651*0Sstevel@tonic-gate
652*0Sstevel@tonic-gate=item -e I<perl code>
653*0Sstevel@tonic-gate
654*0Sstevel@tonic-gateCompile a one-liner, much the same as C<perl -e '...'>
655*0Sstevel@tonic-gate
656*0Sstevel@tonic-gate=item -S
657*0Sstevel@tonic-gate
658*0Sstevel@tonic-gateDo not delete generated C code after compilation.
659*0Sstevel@tonic-gate
660*0Sstevel@tonic-gate=item -B
661*0Sstevel@tonic-gate
662*0Sstevel@tonic-gateUse the Perl bytecode code generator.
663*0Sstevel@tonic-gate
664*0Sstevel@tonic-gate=item -O
665*0Sstevel@tonic-gate
666*0Sstevel@tonic-gateUse the 'optimised' C code generator. This is more experimental than
667*0Sstevel@tonic-gateeverything else put together, and the code created is not guaranteed to
668*0Sstevel@tonic-gatecompile in finite time and memory, or indeed, at all.
669*0Sstevel@tonic-gate
670*0Sstevel@tonic-gate=item -v
671*0Sstevel@tonic-gate
672*0Sstevel@tonic-gateIncrease verbosity of output; can be repeated for more verbose output.
673*0Sstevel@tonic-gate
674*0Sstevel@tonic-gate=item -r
675*0Sstevel@tonic-gate
676*0Sstevel@tonic-gateRun the resulting compiled script after compiling it.
677*0Sstevel@tonic-gate
678*0Sstevel@tonic-gate=item -log
679*0Sstevel@tonic-gate
680*0Sstevel@tonic-gateLog the output of compiling to a file rather than to stdout.
681*0Sstevel@tonic-gate
682*0Sstevel@tonic-gate=back
683*0Sstevel@tonic-gate
684*0Sstevel@tonic-gate=cut
685*0Sstevel@tonic-gate
686*0Sstevel@tonic-gate!NO!SUBS!
687*0Sstevel@tonic-gate
688*0Sstevel@tonic-gateclose OUT or die "Can't close $file: $!";
689*0Sstevel@tonic-gatechmod 0755, $file or die "Can't reset permissions for $file: $!\n";
690*0Sstevel@tonic-gateexec("$Config{'eunicefix'} $file") if $Config{'eunicefix'} ne ':';
691*0Sstevel@tonic-gatechdir $origdir;
692