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