ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Perl-Strip/bin/perlstrip
Revision: 1.2
Committed: Mon Jan 23 02:24:31 2012 UTC (12 years, 4 months ago) by root
Branch: MAIN
CVS Tags: rel-1_1, rel-1_2, HEAD
Changes since 1.1: +1 -1 lines
Log Message:
1.1

File Contents

# Content
1 #!/opt/bin/perl
2
3 =head1 NAME
4
5 perlstrip - make perl sources smaller by removing comments, pod, whitespace...
6
7 =head1 SYNOPSIS
8
9 perlstrip file...
10 perlstrip --size --cache file...
11
12 -v verbose
13 --size optimise for size (also: -s)
14 --cache use a cache (also: -c)
15 --cache-dir path cache directory to use
16 --output path output file for next input file (also: -o)
17
18 WARNING: like its counterpart strip, by default files are overwritten!
19
20 =head1 DESCRIPTION
21
22 This program can be used to reduce the filesize of perl sources, for
23 example, before bundling them using L<PAR>, L<App::Staticperl>, or when
24 using them in a situation where disk space is premium (such as within
25 firmwares, boot floppies etc.).
26
27 It does this by removing unnecessary whitespace, commands, POD and a few
28 other things.
29
30 By default, it works through the list of files given on the commandline,
31 strips them and writes them again. This can be influenced via switches.
32
33 =head2 OPTIONS
34
35 =over 4
36
37 =item C<--verbose>
38
39 =item C<-v>
40
41 Increases verbosity - highly recommended for interactive use.
42
43 =item C<--output> path
44
45 =item C<-o> path
46
47 Write the stripped contents of the I<following> files on the commandline
48 to this path, instead of overwriting the original file. This can be used
49 to copy files instead of (destructively) overwriting them, by specifying
50 C<-o> before each file, e.g.:
51
52 perlstrip -o strippedfile origsource
53
54 =item C<--size>
55
56 =item C<-s>
57
58 Optimise for size instead of for compressibility - the default is to
59 optimise the file for later compression. Optimising for size makes the raw
60 file size smaller, but might compress a bit worse.
61
62 =item C<--cache>
63
64 =item C<-c>
65
66 Stripping files can take a very long time. When this option is enabled,
67 then C<perlstrip> will cache larger files in a special directory
68 (default: F<~/.cache/perlstrip>), to improve repeated calls to strip
69 sources.
70
71 This is mainly useful when you strip a whole perl installation repeatedly.
72
73 =item C<--cache-dir> path
74
75 Enables caching, but uses an alternative cache directory (which will be
76 created if it doesn't exist yet).
77
78 =back
79
80 =head1 SEE ALSO
81
82 L<App::Staticperl>, L<Perl::Squish>.
83
84 =head1 AUTHOR
85
86 Marc Lehmann <schmorp@schmorp.de>
87 http://software.schmorp.de/pkg/staticperl.html
88
89 =cut
90
91 use Perl::Strip;
92 use Getopt::Long;
93 use common::sense;
94
95 our $VERBOSE;
96 our $OPTIMISE_SIZE;
97 our $CACHE;
98 our $CACHEDIR;
99 our $OUTPUT;
100
101 $|=1;
102
103 sub usage {
104 require Pod::Usage;
105
106 Pod::Usage::pod2usage (-output => *STDOUT, -verbose => 1, -exitval => 1, -noperldoc => 1);
107 }
108
109 sub process {
110 my $file = shift;
111
112 # GetOotions apparently wraps us into an eval :/
113 eval {
114 my @cache;
115
116 if (defined $CACHEDIR) {
117 @cache = (cache => $CACHEDIR);
118 } elsif ($CACHE) {
119 mkdir "$ENV{HOME}/.cache";
120 @cache = (cache => "$ENV{HOME}/.cache/perlstrip");
121 }
122
123 print "$file... " if $VERBOSE;
124
125 my $output = defined $OUTPUT ? $OUTPUT : $file;
126
127 my $src = do {
128 open my $fh, "<:perlio", $file
129 or die "$file: $!\n";
130
131 local $/;
132 <$fh>
133 };
134
135 printf "%d ", length $src if $VERBOSE;
136
137 $src = (new Perl::Strip @cache, optimise_size => $OPTIMISE_SIZE)->strip ($src);
138
139 printf "to %d bytes... ", length $src if $VERBOSE;
140 print $output eq $file ? "writing... " : "saving as $output... " if $VERBOSE;
141
142 open my $fh, ">:perlio", "$output~"
143 or die "$output~: $!\n";
144 length $src == syswrite $fh, $src
145 or die "$output~: $!\n";
146 close $fh;
147 rename "$output~", $output;
148
149 print "ok\n" if $VERBOSE;
150 };
151
152 if ($@) {
153 print STDERR "$@\n";
154 exit 2;
155 }
156 }
157
158 @ARGV
159 or usage;
160
161 Getopt::Long::Configure ("bundling", "no_auto_abbrev", "no_ignore_case");
162
163 GetOptions
164 "cache|c" => \$CACHE,
165 "cache-dir=s" => \$CACHEDIR,
166 "verbose|v" => sub { ++$VERBOSE },
167 "quiet|q" => sub { --$VERBOSE },
168 "size|s" => \$OPTIMISE_SIZE,
169 "output|o=s" => \$OUTPUT,
170 "<>" => \&process,
171 or usage;
172
173 __END__
174
175
176 die "cannot specify both --app and --perl\n"
177 if $PERL and defined $APP;
178
179 # required for @INC loading, unfortunately
180 trace_module "PerlIO::scalar";
181
182 #############################################################################
183 # apply include/exclude
184
185 {
186 my %pmi;
187
188 for (@incext) {
189 my ($inc, $glob) = @$_;
190
191 my @match = grep /$glob/, keys %pm;
192
193 if ($inc) {
194 # include
195 @pmi{@match} = delete @pm{@match};
196
197 print "applying include $glob - protected ", (scalar @match), " files.\n"
198 if $VERBOSE >= 5;
199 } else {
200 # exclude
201 delete @pm{@match};
202
203 print "applying exclude $glob - removed ", (scalar @match), " files.\n"
204 if $VERBOSE >= 5;
205 }
206 }
207
208 my @pmi = keys %pmi;
209 @pm{@pmi} = delete @pmi{@pmi};
210 }
211
212 #############################################################################
213 # scan for AutoLoader, static archives and other dependencies
214
215 sub scan_al {
216 my ($auto, $autodir) = @_;
217
218 my $ix = "$autodir/autosplit.ix";
219
220 print "processing autoload index for '$auto'\n"
221 if $VERBOSE >= 6;
222
223 $pm{"$auto/autosplit.ix"} = $ix;
224
225 open my $fh, "<:perlio", $ix
226 or die "$ix: $!";
227
228 my $package;
229
230 while (<$fh>) {
231 if (/^\s*sub\s+ ([^[:space:];]+) \s* (?:\([^)]*\))? \s*;?\s*$/x) {
232 my $al = "auto/$package/$1.al";
233 my $inc = find_inc $al;
234
235 defined $inc or die "$al: autoload file not found, but should be there.\n";
236
237 $pm{$al} = $inc;
238 print "found autoload function '$al'\n"
239 if $VERBOSE >= 6;
240
241 } elsif (/^\s*package\s+([^[:space:];]+)\s*;?\s*$/) {
242 ($package = $1) =~ s/::/\//g;
243 } elsif (/^\s*(?:#|1?\s*;?\s*$)/) {
244 # nop
245 } else {
246 warn "WARNING: $ix: unparsable line, please report: $_";
247 }
248 }
249 }
250
251 for my $pm (keys %pm) {
252 if ($pm =~ /^(.*)\.pm$/) {
253 my $auto = "auto/$1";
254 my $autodir = find_inc $auto;
255
256 if (defined $autodir && -d $autodir) {
257 # AutoLoader
258 scan_al $auto, $autodir
259 if -f "$autodir/autosplit.ix";
260
261 # extralibs.ld
262 if (open my $fh, "<:perlio", "$autodir/extralibs.ld") {
263 print "found extralibs for $pm\n"
264 if $VERBOSE >= 6;
265
266 local $/;
267 $extralibs .= " " . <$fh>;
268 }
269
270 $pm =~ /([^\/]+).pm$/ or die "$pm: unable to match last component";
271
272 my $base = $1;
273
274 # static ext
275 if (-f "$autodir/$base$Config{_a}") {
276 print "found static archive for $pm\n"
277 if $VERBOSE >= 3;
278
279 push @libs, "$autodir/$base$Config{_a}";
280 push @static_ext, $pm;
281 }
282
283 # dynamic object
284 die "ERROR: found shared object - can't link statically ($_)\n"
285 if -f "$autodir/$base.$Config{dlext}";
286
287 if ($PACKLIST && open my $fh, "<:perlio", "$autodir/.packlist") {
288 print "found .packlist for $pm\n"
289 if $VERBOSE >= 3;
290
291 while (<$fh>) {
292 chomp;
293 s/ .*$//; # newer-style .packlists might contain key=value pairs
294
295 # only include certain files (.al, .ix, .pm, .pl)
296 if (/\.(pm|pl|al|ix)$/) {
297 for my $inc (@INC) {
298 # in addition, we only add files that are below some @INC path
299 $inc =~ s/\/*$/\//;
300
301 if ($inc eq substr $_, 0, length $inc) {
302 my $base = substr $_, length $inc;
303 $pm{$base} = $_;
304
305 print "+ added .packlist dependency $base\n"
306 if $VERBOSE >= 3;
307 }
308
309 last;
310 }
311 }
312 }
313 }
314 }
315 }
316 }
317
318 #############################################################################
319
320 print "processing bundle files (try more -v power if you get bored waiting here)...\n"
321 if $VERBOSE >= 1;
322
323 my $data;
324 my @index;
325 my @order = sort {
326 length $a <=> length $b
327 or $a cmp $b
328 } keys %pm;
329
330 # sorting by name - better compression, but needs more metadata
331 # sorting by length - faster lookup
332 # usually, the metadata overhead beats the loss through compression
333
334 for my $pm (@order) {
335 my $path = $pm{$pm};
336
337 128 > length $pm
338 or die "ERROR: $pm: path too long (only 128 octets supported)\n";
339
340 my $src = ref $path
341 ? $$path
342 : do {
343 open my $pm, "<", $path
344 or die "$path: $!";
345
346 local $/;
347
348 <$pm>
349 };
350
351 my $size = length $src;
352
353 unless ($pmbin{$pm}) { # only do this unless the file is binary
354 if ($pm =~ /^auto\/POSIX\/[^\/]+\.al$/) {
355 if ($src =~ /^ unimpl \"/m) {
356 print "$pm: skipping (raises runtime error only).\n"
357 if $VERBOSE >= 3;
358 next;
359 }
360 }
361
362 $src = cache +($STRIP eq "ppi" ? "$UNISTRIP,$OPTIMISE_SIZE" : undef), $src, sub {
363 if ($UNISTRIP && $pm =~ /^unicore\/.*\.pl$/) {
364 print "applying unicore stripping $pm\n"
365 if $VERBOSE >= 6;
366
367 # special stripping for unicore swashes and properties
368 # much more could be done by going binary
369 $src =~ s{
370 (^return\ <<'END';\n) (.*?\n) (END(?:\n|\Z))
371 }{
372 my ($pre, $data, $post) = ($1, $2, $3);
373
374 for ($data) {
375 s/^([0-9a-fA-F]+)\t([0-9a-fA-F]+)\t/sprintf "%X\t%X", hex $1, hex $2/gem
376 if $OPTIMISE_SIZE;
377
378 # s{
379 # ^([0-9a-fA-F]+)\t([0-9a-fA-F]*)\t
380 # }{
381 # # ww - smaller filesize, UU - compress better
382 # pack "C0UU",
383 # hex $1,
384 # length $2 ? (hex $2) - (hex $1) : 0
385 # }gemx;
386
387 s/#.*\n/\n/mg;
388 s/\s+\n/\n/mg;
389 }
390
391 "$pre$data$post"
392 }smex;
393 }
394
395 if ($STRIP =~ /ppi/i) {
396 require PPI;
397
398 if (my $ppi = PPI::Document->new (\$src)) {
399 $ppi->prune ("PPI::Token::Comment");
400 $ppi->prune ("PPI::Token::Pod");
401
402 # prune END stuff
403 for (my $last = $ppi->last_element; $last; ) {
404 my $prev = $last->previous_token;
405
406 if ($last->isa (PPI::Token::Whitespace::)) {
407 $last->delete;
408 } elsif ($last->isa (PPI::Statement::End::)) {
409 $last->delete;
410 last;
411 } elsif ($last->isa (PPI::Token::Pod::)) {
412 $last->delete;
413 } else {
414 last;
415 }
416
417 $last = $prev;
418 }
419
420 # prune some but not all insignificant whitespace
421 for my $ws (@{ $ppi->find (PPI::Token::Whitespace::) }) {
422 my $prev = $ws->previous_token;
423 my $next = $ws->next_token;
424
425 if (!$prev || !$next) {
426 $ws->delete;
427 } else {
428 if (
429 $next->isa (PPI::Token::Operator::) && $next->{content} =~ /^(?:,|=|!|!=|==|=>)$/ # no ., because of digits. == float
430 or $prev->isa (PPI::Token::Operator::) && $prev->{content} =~ /^(?:,|=|\.|!|!=|==|=>)$/
431 or $prev->isa (PPI::Token::Structure::)
432 or ($OPTIMISE_SIZE &&
433 ($prev->isa (PPI::Token::Word::)
434 && (PPI::Token::Symbol:: eq ref $next
435 || $next->isa (PPI::Structure::Block::)
436 || $next->isa (PPI::Structure::List::)
437 || $next->isa (PPI::Structure::Condition::)))
438 )
439 ) {
440 $ws->delete;
441 } elsif ($prev->isa (PPI::Token::Whitespace::)) {
442 $ws->{content} = ' ';
443 $prev->delete;
444 } else {
445 $ws->{content} = ' ';
446 }
447 }
448 }
449
450 # prune whitespace around blocks
451 if ($OPTIMISE_SIZE) {
452 # these usually decrease size, but decrease compressability more
453 for my $struct (PPI::Structure::Block::, PPI::Structure::Condition::) {
454 for my $node (@{ $ppi->find ($struct) }) {
455 my $n1 = $node->first_token;
456 my $n2 = $n1->previous_token;
457 $n1->delete if $n1->isa (PPI::Token::Whitespace::);
458 $n2->delete if $n2 && $n2->isa (PPI::Token::Whitespace::);
459 my $n1 = $node->last_token;
460 my $n2 = $n1->next_token;
461 $n1->delete if $n1->isa (PPI::Token::Whitespace::);
462 $n2->delete if $n2 && $n2->isa (PPI::Token::Whitespace::);
463 }
464 }
465
466 for my $node (@{ $ppi->find (PPI::Structure::List::) }) {
467 my $n1 = $node->first_token;
468 $n1->delete if $n1->isa (PPI::Token::Whitespace::);
469 my $n1 = $node->last_token;
470 $n1->delete if $n1->isa (PPI::Token::Whitespace::);
471 }
472 }
473
474 # reformat qw() lists which often have lots of whitespace
475 for my $node (@{ $ppi->find (PPI::Token::QuoteLike::Words::) }) {
476 if ($node->{content} =~ /^qw(.)(.*)(.)$/s) {
477 my ($a, $qw, $b) = ($1, $2, $3);
478 $qw =~ s/^\s+//;
479 $qw =~ s/\s+$//;
480 $qw =~ s/\s+/ /g;
481 $node->{content} = "qw$a$qw$b";
482 }
483 }
484
485 $src = $ppi->serialize;
486 } else {
487 warn "WARNING: $pm{$pm}: PPI failed to parse this file\n";
488 }
489 } elsif ($STRIP =~ /pod/i && $pm ne "Opcode.pm") { # opcode parses its own pod
490 require Pod::Strip;
491
492 my $stripper = Pod::Strip->new;
493
494 my $out;
495 $stripper->output_string (\$out);
496 $stripper->parse_string_document ($src)
497 or die;
498 $src = $out;
499 }
500
501 if ($VERIFY && $pm =~ /\.pm$/ && $pm ne "Opcode.pm") {
502 if (open my $fh, "-|") {
503 <$fh>;
504 } else {
505 eval "#line 1 \"$pm\"\n$src" or warn "\n\n\n$pm\n\n$src\n$@\n\n\n";
506 exit 0;
507 }
508 }
509
510 $src
511 };
512
513 # if ($pm eq "Opcode.pm") {
514 # open my $fh, ">x" or die; print $fh $src;#d#
515 # exit 1;
516 # }
517 }
518
519 print "adding $pm (original size $size, stored size ", length $src, ")\n"
520 if $VERBOSE >= 2;
521
522 push @index, ((length $pm) << 25) | length $data;
523 $data .= $pm . $src;
524 }
525
526 length $data < 2**25
527 or die "ERROR: bundle too large (only 32MB supported)\n";
528
529 my $varpfx = "bundle_" . substr +(Digest::MD5::md5_hex $data), 0, 16;
530
531 #############################################################################
532 # output
533
534 print "generating $PREFIX.h... "
535 if $VERBOSE >= 1;
536
537 {
538 open my $fh, ">", "$PREFIX.h"
539 or die "$PREFIX.h: $!\n";
540
541 print $fh <<EOF;
542 /* do not edit, automatically created by mkstaticbundle */
543
544 #include <EXTERN.h>
545 #include <perl.h>
546 #include <XSUB.h>
547
548 /* public API */
549 EXTERN_C PerlInterpreter *staticperl;
550 EXTERN_C void staticperl_xs_init (pTHX);
551 EXTERN_C void staticperl_init (void);
552 EXTERN_C void staticperl_cleanup (void);
553
554 EOF
555 }
556
557 print "\n"
558 if $VERBOSE >= 1;
559
560 #############################################################################
561 # output
562
563 print "generating $PREFIX.c... "
564 if $VERBOSE >= 1;
565
566 open my $fh, ">", "$PREFIX.c"
567 or die "$PREFIX.c: $!\n";
568
569 print $fh <<EOF;
570 /* do not edit, automatically created by mkstaticbundle */
571
572 #include "bundle.h"
573
574 /* public API */
575 PerlInterpreter *staticperl;
576
577 EOF
578
579 #############################################################################
580 # bundle data
581
582 my $count = @index;
583
584 print $fh <<EOF;
585 #include "bundle.h"
586
587 /* bundle data */
588
589 static const U32 $varpfx\_count = $count;
590 static const U32 $varpfx\_index [$count + 1] = {
591 EOF
592
593 my $col;
594 for (@index) {
595 printf $fh "0x%08x,", $_;
596 print $fh "\n" unless ++$col % 10;
597
598 }
599 printf $fh "0x%08x\n};\n", (length $data);
600
601 print $fh "static const char $varpfx\_data [] =\n";
602 dump_string $fh, $data;
603
604 print $fh ";\n\n";
605
606 #############################################################################
607 # bootstrap
608
609 # boot file for staticperl
610 # this file will be eval'ed at initialisation time
611
612 my $bootstrap = '
613 BEGIN {
614 package ' . $PACKAGE . ';
615
616 PerlIO::scalar->bootstrap;
617
618 @INC = sub {
619 my $data = find "$_[1]"
620 or return;
621
622 $INC{$_[1]} = $_[1];
623
624 open my $fh, "<", \$data;
625 $fh
626 };
627 }
628 ';
629
630 $bootstrap .= "require '//boot';"
631 if exists $pm{"//boot"};
632
633 $bootstrap =~ s/\s+/ /g;
634 $bootstrap =~ s/(\W) /$1/g;
635 $bootstrap =~ s/ (\W)/$1/g;
636
637 print $fh "const char bootstrap [] = ";
638 dump_string $fh, $bootstrap;
639 print $fh ";\n\n";
640
641 print $fh <<EOF;
642 /* search all bundles for the given file, using binary search */
643 XS(find)
644 {
645 dXSARGS;
646
647 if (items != 1)
648 Perl_croak (aTHX_ "Usage: $PACKAGE\::find (\$path)");
649
650 {
651 STRLEN namelen;
652 char *name = SvPV (ST (0), namelen);
653 SV *res = 0;
654
655 int l = 0, r = $varpfx\_count;
656
657 while (l <= r)
658 {
659 int m = (l + r) >> 1;
660 U32 idx = $varpfx\_index [m];
661 int comp = namelen - (idx >> 25);
662
663 if (!comp)
664 {
665 int ofs = idx & 0x1FFFFFFU;
666 comp = memcmp (name, $varpfx\_data + ofs, namelen);
667
668 if (!comp)
669 {
670 /* found */
671 int ofs2 = $varpfx\_index [m + 1] & 0x1FFFFFFU;
672
673 ofs += namelen;
674 res = newSVpvn ($varpfx\_data + ofs, ofs2 - ofs);
675 goto found;
676 }
677 }
678
679 if (comp < 0)
680 r = m - 1;
681 else
682 l = m + 1;
683 }
684
685 XSRETURN (0);
686
687 found:
688 ST (0) = res;
689 sv_2mortal (ST (0));
690 }
691
692 XSRETURN (1);
693 }
694
695 /* list all files in the bundle */
696 XS(list)
697 {
698 dXSARGS;
699
700 if (items != 0)
701 Perl_croak (aTHX_ "Usage: $PACKAGE\::list");
702
703 {
704 int i;
705
706 EXTEND (SP, $varpfx\_count);
707
708 for (i = 0; i < $varpfx\_count; ++i)
709 {
710 U32 idx = $varpfx\_index [i];
711
712 PUSHs (newSVpvn ($varpfx\_data + (idx & 0x1FFFFFFU), idx >> 25));
713 }
714 }
715
716 XSRETURN ($varpfx\_count);
717 }
718
719 EOF
720
721 #############################################################################
722 # xs_init
723
724 print $fh <<EOF;
725 void
726 staticperl_xs_init (pTHX)
727 {
728 EOF
729
730 @static_ext = ("DynaLoader", sort @static_ext);
731
732 # prototypes
733 for (@static_ext) {
734 s/\.pm$//;
735 (my $cname = $_) =~ s/\//__/g;
736 print $fh " EXTERN_C void boot_$cname (pTHX_ CV* cv);\n";
737 }
738
739 print $fh <<EOF;
740 char *file = __FILE__;
741 dXSUB_SYS;
742
743 newXSproto ("$PACKAGE\::find", find, file, "\$");
744 newXSproto ("$PACKAGE\::list", list, file, "");
745 EOF
746
747 # calls
748 for (@static_ext) {
749 s/\.pm$//;
750
751 (my $cname = $_) =~ s/\//__/g;
752 (my $pname = $_) =~ s/\//::/g;
753
754 my $bootstrap = $pname eq "DynaLoader" ? "boot" : "bootstrap";
755
756 print $fh " newXS (\"$pname\::$bootstrap\", boot_$cname, file);\n";
757 }
758
759 print $fh <<EOF;
760 Perl_av_create_and_unshift_one (&PL_preambleav, newSVpv (bootstrap, sizeof (bootstrap) - 1));
761 }
762 EOF
763
764 #############################################################################
765 # optional perl_init/perl_destroy
766
767 if ($APP) {
768 print $fh <<EOF;
769
770 int
771 main (int argc, char *argv [])
772 {
773 extern char **environ;
774 int exitstatus;
775
776 static char *args[] = {
777 "staticperl",
778 "-e",
779 "0"
780 };
781
782 PERL_SYS_INIT3 (&argc, &argv, &environ);
783 staticperl = perl_alloc ();
784 perl_construct (staticperl);
785
786 PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
787
788 exitstatus = perl_parse (staticperl, staticperl_xs_init, sizeof (args) / sizeof (*args), args, environ);
789 if (!exitstatus)
790 perl_run (staticperl);
791
792 exitstatus = perl_destruct (staticperl);
793 perl_free (staticperl);
794 PERL_SYS_TERM ();
795
796 return exitstatus;
797 }
798 EOF
799 } elsif ($PERL) {
800 print $fh <<EOF;
801
802 int
803 main (int argc, char *argv [])
804 {
805 extern char **environ;
806 int exitstatus;
807
808 PERL_SYS_INIT3 (&argc, &argv, &environ);
809 staticperl = perl_alloc ();
810 perl_construct (staticperl);
811
812 PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
813
814 exitstatus = perl_parse (staticperl, staticperl_xs_init, argc, argv, environ);
815 if (!exitstatus)
816 perl_run (staticperl);
817
818 exitstatus = perl_destruct (staticperl);
819 perl_free (staticperl);
820 PERL_SYS_TERM ();
821
822 return exitstatus;
823 }
824 EOF
825 } else {
826 print $fh <<EOF;
827
828 EXTERN_C void
829 staticperl_init (void)
830 {
831 extern char **environ;
832 int argc = sizeof (args) / sizeof (args [0]);
833 char **argv = args;
834
835 static char *args[] = {
836 "staticperl",
837 "-e",
838 "0"
839 };
840
841 PERL_SYS_INIT3 (&argc, &argv, &environ);
842 staticperl = perl_alloc ();
843 perl_construct (staticperl);
844 PL_origalen = 1;
845 PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
846 perl_parse (staticperl, staticperl_xs_init, argc, argv, environ);
847
848 perl_run (staticperl);
849 }
850
851 EXTERN_C void
852 staticperl_cleanup (void)
853 {
854 perl_destruct (staticperl);
855 perl_free (staticperl);
856 staticperl = 0;
857 PERL_SYS_TERM ();
858 }
859 EOF
860 }
861
862 print -s "$PREFIX.c", " octets (", (length $data) , " data octets).\n\n"
863 if $VERBOSE >= 1;
864
865 #############################################################################
866 # libs, cflags
867
868 {
869 print "generating $PREFIX.ccopts... "
870 if $VERBOSE >= 1;
871
872 my $str = "$Config{ccflags} $Config{optimize} $Config{cppflags} -I$Config{archlibexp}/CORE";
873 $str =~ s/([\(\)])/\\$1/g;
874
875 open my $fh, ">$PREFIX.ccopts"
876 or die "$PREFIX.ccopts: $!";
877 print $fh $str;
878
879 print "$str\n\n"
880 if $VERBOSE >= 1;
881 }
882
883 {
884 print "generating $PREFIX.ldopts... ";
885
886 my $str = $STATIC ? "-static " : "";
887
888 $str .= "$Config{ccdlflags} $Config{ldflags} @libs $Config{archlibexp}/CORE/$Config{libperl} $Config{perllibs}";
889
890 my %seen;
891 $str .= " $_" for grep !$seen{$_}++, ($extralibs =~ /(\S+)/g);
892
893 for (@staticlibs) {
894 $str =~ s/(^|\s) (-l\Q$_\E) ($|\s)/$1-Wl,-Bstatic $2 -Wl,-Bdynamic$3/gx;
895 }
896
897 $str =~ s/([\(\)])/\\$1/g;
898
899 open my $fh, ">$PREFIX.ldopts"
900 or die "$PREFIX.ldopts: $!";
901 print $fh $str;
902
903 print "$str\n\n"
904 if $VERBOSE >= 1;
905 }
906
907 if ($PERL or defined $APP) {
908 $APP = "perl" unless defined $APP;
909
910 print "building $APP...\n"
911 if $VERBOSE >= 1;
912
913 system "$Config{cc} \$(cat bundle.ccopts\) -o \Q$APP\E bundle.c \$(cat bundle.ldopts\)";
914
915 unlink "$PREFIX.$_"
916 for qw(ccopts ldopts c h);
917
918 print "\n"
919 if $VERBOSE >= 1;
920 }
921