ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/App-Staticperl/bin/staticperl
Revision: 1.1
Committed: Mon Dec 6 19:33:58 2010 UTC (15 years, 9 months ago) by root
Branch: MAIN
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 #!/bin/sh
2    
3     #############################################################################
4     # configuration to fill in
5    
6     PERLVER=5.12.2 # 5.8.9 is also a good choice
7     STATICPERL=~/.staticperl
8     CPAN=http://mirror.netcologne.de/cpan/ # which mirror to use
9     EMAIL="read the documentation <rtfm@example.org>"
10    
11     MKBUNDLE="$STATICPERL/mkbundle"
12    
13     # perl build variables
14     PREFIX="$STATICPERL/perl" # where the perl gets installed
15     PERL_CPPFLAGS="-DPERL_DISABLE_PMC -DPERL_ARENA_SIZE=65536 -D_GNU_SOURCE -DNDEBUG -USITELIB_EXP -USITEARCHEXP -UARCHLIB_EXP"
16     PERL_OPTIMIZE="-Os -ffunction-sections -fdata-sections -finline-limit=8 -ffast-math"
17    
18     ARCH="$(uname -m)"
19    
20     case "$ARCH" in
21     i*86 | x86_64 | amd64 )
22     PERL_OPTIMIZE="$PERL_OPTIMIZE -mpush-args -mno-inline-stringops-dynamically -mno-align-stringops -mno-ieee-fp" # x86/amd64
23     case "$ARCH" in
24     i*86 )
25     PERL_OPTIMIZE="$PERL_OPTIMIZE -fomit-frame-pointer -march=pentium3 -mtune=i386" # x86 only
26     ;;
27     esac
28     ;;
29     esac
30    
31     # -Wl,--gc-sections makes it impossible to check for undefined references
32     # for some reason so we need to patch away the "-no" after Configure and before make :/
33     # -z muldefs is to work around uclibc's pthread static linking bug
34     PERL_LDFLAGS="-Wl,--no-gc-sections -z muldefs"
35     PERL_LIBS="-lm -lcrypt" # perl loves to add lotsa crap itself
36    
37     # some configuration options for modules
38     export PERL_MM_USE_DEFAULT=1
39     #export CORO_INTERFACE=p # needed without nptl on x86, due to bugs in linuxthreads - very slow
40     export EV_EXTRA_DEFS='-DEV_FEATURES=4+8+16+64 -DEV_USE_SELECT=0 -DEV_USE_POLL=1 -DEV_USE_EPOLL=1 -DEV_NO_LOOPS -DEV_COMPAT3=0'
41    
42     # which extra modules to install by default from CPAN that are
43     # required by mkbundle
44     EXTRA_MODULES="common::sense Pod::Strip PPI::XS Pod::Usage"
45    
46     # overridable functions
47     postconfigure() { : ; }
48     postbuild() { : ; }
49     postinstall() { : ; }
50    
51     # now source user config, if any
52     [ -r /etc/staticperlrc ] && . /etc/staticperlrc
53     [ -r ~/.staticperlrc ] && . ~/.staticperlrc
54     [ -r "$STATICPERL/rc" ] && . "$STATICPERL/rc"
55    
56     #############################################################################
57     # support
58    
59     # set version in a way that Makefile.PL can extract
60     VERSION=VERSION; eval \
61     $VERSION=0.1
62    
63     BZ2=bz2
64     BZIP2=bzip2
65    
66     fatal() {
67     printf -- "\nFATAL: %s\n\n" "$*" >&2
68     exit 1
69     }
70    
71     verbose() {
72     printf -- "%s\n" "$*"
73     }
74    
75     verblock() {
76     verbose
77     verbose "***"
78     while read line; do
79     verbose "*** $line"
80     done
81     verbose "***"
82     verbose
83     }
84    
85     rcd() {
86     cd "$1" || fatal "$1: cannot enter"
87     }
88    
89     trace() {
90     prefix="$1"; shift
91     # "$@" 2>&1 | while read line; do
92     # echo "$prefix: $line"
93     # done
94     "$@"
95     }
96    
97     trap wait 0
98    
99     #############################################################################
100     # clean
101    
102     distclean() {
103     verblock <<EOF
104     deleting everything installed by this script
105     EOF
106    
107     rm -rf "$STATICPERL"
108     }
109    
110     #############################################################################
111     # download/configure/compile/install perl
112    
113     clean() {
114     cd "$STATICPERL/src/perl-$PERLVER" 2>/dev/null || return
115    
116     rm -f staticstamp.configure
117     make distclean >/dev/null 2>&1
118     }
119    
120     fetch() {
121     rcd "$STATICPERL"
122    
123     mkdir -p src
124     rcd src
125    
126     if ! [ -d "perl-$PERLVER" ]; then
127     if ! [ -e "perl-$PERLVER.tar.$BZ2" ]; then
128    
129     URL="$CPAN/src/5.0/perl-$PERLVER.tar.$BZ2"
130    
131     verblock <<EOF
132     downloading perl
133     to manually download perl yourself, place
134     perl-$PERLVER.tar.$BZ2 in $STATICPERL
135     trying $URL
136     EOF
137    
138     curl >perl-$PERLVER.tar.$BZ2~ "$URL" \
139     || wget -O perl-$PERLVER.tar.$BZ2~ "$URL" \
140     || fatal "$URL: error during downloading"
141     mv perl-$PERLVER.tar.$BZ2~ perl-$PERLVER.tar.$BZ2
142     fi
143    
144     verblock <<EOF
145     unpacking perl
146     EOF
147    
148     mkdir -p unpack
149     $BZIP2 -d <perl-$PERLVER.tar.bz2 | tar xpC unpack \
150     || fatal "perl-$PERLVER.tar.bz2: error during unpacking"
151     mv unpack/perl-$PERLVER perl-$PERLVER
152     rmdir -p unpack
153     fi
154     }
155    
156     # similar to GNU-sed -i or perl -pi
157     sedreplace() {
158     sed -e "$1" <"$2" > "$2~" || fatal "error while running sed"
159     mv "$2~" "$2"
160     }
161    
162     configure() {
163     fetch
164    
165     rcd "$STATICPERL/src/perl-$PERLVER"
166    
167     [ -e staticstamp.configure ] && return
168    
169     verblock <<EOF
170     configuring $STATICPERL/src/perl-$PERLVER
171     EOF
172    
173     clean
174    
175     rm -f "$PREFIX/staticstamp.install"
176    
177     # I hate them
178     grep -q -- -fstack-protector Configure && \
179     sedreplace 's/-fstack-protector/-fno-stack-protector/g' Configure
180    
181     # trace configure \
182     sh Configure -Duselargefiles \
183     -Uuse64bitint \
184     -Dusemymalloc=n \
185     -Uusedl \
186     -Uusethreads \
187     -Uuseithreads \
188     -Uusemultiplicity \
189     -Duseperlio \
190     -Uusesfio \
191     -Uuseshrplib \
192     -Dcppflags="$PERL_CPPFLAGS" \
193     -Dccflags="-g2 -fno-strict-aliasing" \
194     -Doptimize="$PERL_OPTIMIZE" \
195     -Dldflags="$PERL_LDFLAGS" \
196     -Dlibs="$PERL_LIBS" \
197     -Dprefix="$PREFIX" \
198     -Dbin="$PREFIX/bin" \
199     -Dprivlib="$PREFIX/plib" \
200     -Darchlib="$PREFIX/plib" \
201     -Uusevendorprefix \
202     -Dsitelib="$PREFIX/plib" \
203     -Dsitearch="$PREFIX/plib" \
204     -Usitelibexp \
205     -Uman1dir \
206     -Uman3dir \
207     -Usiteman1dir \
208     -Usiteman3dir \
209     -Dpager=/usr/bin/less \
210     -Demail="$EMAIL" \
211     -Dcf_email="$EMAIL" \
212     -Dcf_by="$EMAIL" \
213     -dE || fatal "Configure failed"
214    
215     sedreplace '
216     s/-Wl,--no-gc-sections/-Wl,--gc-sections/g
217     s/ *-fno-stack-protector */ /g
218     ' config.sh
219    
220     sh Configure -S || fatal "Configure -S failed"
221    
222     postconfigure || fatal "postconfigure hook failed"
223    
224     touch staticstamp.configure
225     }
226    
227     build() {
228     configure
229    
230     rcd "$STATICPERL/src/perl-$PERLVER"
231    
232     verblock <<EOF
233     building $STATICPERL/src/perl-$PERLVER
234     EOF
235    
236     rm -f "$PREFIX/staticstamp.install"
237    
238     make || fatal "make: error while building perl"
239    
240     postbuild || fatal "postbuild hook failed"
241     }
242    
243     install() {
244     [ -e "$PREFIX/staticstamp.install" ] && return
245    
246     build
247    
248     verblock <<EOF
249     installing $STATICPERL/src/perl-$PERLVER
250     to $PREFIX
251     EOF
252    
253     rm -rf "$PREFIX"
254    
255     make install || fatal "make install: error while installing"
256    
257     # create a "make install" replacement for CPAN
258     cat >"$PREFIX"/bin/cpan-make-install <<EOF
259     make install UNINST=1
260     if find blib/arch/auto -type f | grep -q -v .exists; then
261     echo Probably an XS module, rebuilding perl
262     make perl
263     rm -f "$PREFIX"/bin/perl
264     make -f Makefile.aperl inst_perl
265     make -f Makefile.aperl map_clean
266     fi
267     EOF
268     chmod 755 "$PREFIX"/bin/cpan-make-install
269    
270     "$PREFIX"/bin/perl -MCPAN -e '
271     CPAN::Shell->o (conf => urllist => push => "'"$CPAN"'");
272     CPAN::Shell->o (conf => q<init>);
273     CPAN::Shell->o (conf => q<cpan_home>, "'"$STATICPERL"'/cpan");
274     CPAN::Shell->o (conf => q<build_dir>, "'"$STATICPERL"'/cpan/build");
275     CPAN::Shell->o (conf => q<prefs_dir>, "'"$STATICPERL"'/cpan/prefs");
276     CPAN::Shell->o (conf => q<histfile> , "'"$STATICPERL"'/cpan/histfile");
277     CPAN::Shell->o (conf => q<keep_source_where>, "'"$STATICPERL"'/cpan/sources");
278     CPAN::Shell->o (conf => q<make_install_make_command>, "'"$PREFIX"'/bin/cpan-make-install");
279     CPAN::Shell->o (conf => q<prerequisites_policy>, q<follow>);
280     CPAN::Shell->o (conf => q<build_requires_install_policy>, q<no>);
281     CPAN::Shell->o (conf => q<commit>);
282     ' || fatal "error while initialising CPAN"
283    
284     NOCHECK_INSTALL=+
285     instcpan $EXTRA_MODULES
286    
287     postinstall || fatal "postinstall hook failed"
288    
289     touch "$PREFIX/staticstamp.install"
290     }
291    
292     #############################################################################
293     # install a module from CPAN
294    
295     instcpan() {
296     [ $NOCHECK_INSTALL ] || install
297    
298     verblock <<EOF
299     installing modules from CPAN
300     $@
301     EOF
302    
303     for mod in "$@"; do
304     "$PREFIX"/bin/perl -MCPAN -e 'notest install => "'"$mod"'"' \
305     || fatal "$mod: unable to install from CPAN"
306     done
307     rm -rf "$STATICPERL/build"
308     }
309    
310     #############################################################################
311     # install a module from unpacked sources
312    
313     instsrc() {
314     [ $NOCHECK_INSTALL ] || install
315    
316     verblock <<EOF
317     installing modules from source
318     $@
319     EOF
320    
321     for mod in "$@"; do
322     echo
323     echo $mod
324     (
325     rcd $mod
326     make -f Makefile.aperl map_clean >/dev/null 2>&1
327     make distclean >/dev/null 2>&1
328     "$PREFIX"/bin/perl Makefile.PL || fatal "$mod: error running Makefile.PL"
329     make || fatal "$mod: error building module"
330     "$PREFIX"/bin/cpan-make-install || fatal "$mod: error installing module"
331     make distclean >/dev/null 2>&1
332     exit 0
333     ) || exit $?
334     done
335     }
336    
337     #############################################################################
338     # do schmorpy stuff
339    
340     MODSRCDIR=~/src
341    
342     instmodsrc() {
343     for mod in "$@"; do
344     instmod_src "$MODSRCDIR/$mod"
345     done
346     }
347    
348     install_schmorp() {
349     install
350    
351     instcpan Data::Dump Term::ReadLine::Perl Term::ANSIColor Term::ReadKey
352     instcpan Digest::SHA Digest::MD6 Digest::SHA256 Digest::MD4 Digest::HMAC_MD5 Digest::HMAC_MD6 Digest::FNV
353     #instcpan Net::SSLeay # requires static -ldl
354    
355     instmodsrc common-sense Crypt-Twofish2 Array-Heap Convert-Scalar Compress-LZF JSON-XS
356     instmodsrc EV Guard Async-Interrupt IO-AIO
357     instmodsrc AnyEvent AnyEvent-AIO Coro AnyEvent-HTTP
358     instmodsrc Linux-Inotify2 EV-Loop-Async
359    
360     instcpan AnyEvent::HTTPD
361     }
362    
363     #############################################################################
364     # main
365    
366     podusage() {
367     echo
368     if [ -e "$PREFIX/bin/perl" ]; then
369     "$PREFIX/bin/perl" -MPod::Usage -e \
370     'pod2usage -input => *STDIN, -output => *STDOUT, -verbose => '$1', -exitval => 0, -noperldoc => 1' <"$0" \
371     2>/dev/null && exit
372     fi
373     # try whatever perl we can find
374     perl -MPod::Usage -e \
375     'pod2usage -input => *STDIN, -output => *STDOUT, -verbose => '$1', -exitval => 0, -noperldoc => 1' <"$0" \
376     2>/dev/null && exit
377    
378     fatal "displaying documentation requires a working perl - try '$0 install' first"
379     }
380    
381     usage() {
382     podusage 0
383     }
384    
385     catmkbundle() {
386     {
387     read dummy
388     echo "#!$PREFIX/bin/perl"
389     cat
390     } <<'MKBUNDLE'
391     #!/opt/bin/perl
392    
393     #############################################################################
394     # cannot load modules till after the tracer BEGIN block
395    
396     our $VERBOSE = 1;
397     our $STRIP = "pod"; # none, pod or ppi
398     our $PERL = 0;
399     our $VERIFY = 0;
400     our $STATIC = 0;
401    
402     my $PREFIX = "bundle";
403     my $PACKAGE = "static";
404    
405     my %pm;
406     my @libs;
407     my @static_ext;
408     my $extralibs;
409    
410     @ARGV
411     or die "$0: use 'staticperl help' (or read the sources of staticperl)\n";
412    
413     $|=1;
414    
415     our ($TRACER_W, $TRACER_R);
416    
417     sub find_inc($) {
418     for (@INC) {
419     next if ref;
420     return $_ if -e "$_/$_[0]";
421     }
422    
423     undef
424     }
425    
426     BEGIN {
427     # create a loader process to detect @INC requests before we load any modules
428     my ($W_TRACER, $R_TRACER); # used by tracer
429    
430     pipe $R_TRACER, $TRACER_W or die "pipe: $!";
431     pipe $TRACER_R, $W_TRACER or die "pipe: $!";
432    
433     unless (fork) {
434     close $TRACER_R;
435     close $TRACER_W;
436    
437     unshift @INC, sub {
438     my $dir = find_inc $_[1]
439     or return;
440    
441     syswrite $W_TRACER, "-\n$dir\n$_[1]\n";
442    
443     open my $fh, "<:perlio", "$dir/$_[1]"
444     or warn "ERROR: $dir/$_[1]: $!\n";
445    
446     $fh
447     };
448    
449     while (<$R_TRACER>) {
450     if (/use (.*)$/) {
451     my $mod = $1;
452     eval "require $mod";
453     warn "ERROR: $@ (while loading '$mod')\n"
454     if $@;
455     syswrite $W_TRACER, "\n";
456     } elsif (/eval (.*)$/) {
457     my $eval = $1;
458     eval $eval;
459     warn "ERROR: $@ (in '$eval')\n"
460     if $@;
461     }
462     }
463    
464     exit 0;
465     }
466     }
467    
468     # module loading is now safe
469     use Config;
470    
471     sub trace_module {
472     syswrite $TRACER_W, "use $_[0]\n";
473    
474     for (;;) {
475     <$TRACER_R> =~ /^-$/ or last;
476     my $dir = <$TRACER_R>; chomp $dir;
477     my $name = <$TRACER_R>; chomp $name;
478    
479     $pm{$name} = "$dir/$name";
480    
481     if ($name =~ /^(.*)\.pm$/) {
482     my $auto = "auto/$1";
483     my $autodir = "$dir/$auto";
484    
485     if (-d $autodir) {
486     opendir my $dir, $autodir
487     or die "$autodir: $!\n";
488    
489     for (readdir $dir) {
490     # AutoLoader
491     $pm{"$auto/$_"} = "$autodir/$_"
492     if /\.(?:al|ix)$/;
493    
494     # static ext
495     if (/\Q$Config{_a}\E$/o) {
496     push @libs, "$autodir/$_";
497     push @static_ext, $name;
498     }
499    
500     # extralibs.ld
501     if ($_ eq "extralibs.ld") {
502     open my $fh, "<:perlio", "$autodir/$_"
503     or die "$autodir/$_";
504    
505     local $/;
506     $extralibs .= " " . <$fh>;
507     }
508    
509     # dynamic object
510     warn "WARNING: found shared object - can't link statically ($_)\n"
511     if /\.\Q$Config{dlext}\E$/o;
512    
513     #TODO: extralibs?
514     }
515     }
516     }
517     }
518     }
519    
520     sub trace_eval {
521     syswrite $TRACER_W, "eval $_[0]\n";
522     }
523    
524     sub trace_finish {
525     close $TRACER_W;
526     close $TRACER_R;
527     }
528    
529     #############################################################################
530     # now we can use modules
531    
532     use common::sense;
533     use Digest::MD5;
534    
535     sub dump_string {
536     my ($fh, $data) = @_;
537    
538     if (length $data) {
539     for (
540     my $ofs = 0;
541     length (my $substr = substr $data, $ofs, 80);
542     $ofs += 80
543     ) {
544     $substr =~ s/([^\x20-\x21\x23-\x5b\x5d-\x7e])/sprintf "\\%03o", ord $1/ge;
545     $substr =~ s/\?/\\?/g; # trigraphs...
546     print $fh " \"$substr\"\n";
547     }
548     } else {
549     print $fh " \"\"\n";
550     }
551     }
552    
553     # required for @INC loading, unfortunately
554     trace_module "PerlIO::scalar";
555    
556     #trace_module "Term::ReadLine::readline"; # Term::ReadLine::Perl dependency
557     # URI is difficult
558     #trace_module "URI::http";
559     #trace_module "URI::_generic";
560    
561     sub cmd_boot {
562     $pm{"//boot"} = $_[0];
563     }
564    
565     sub cmd_add {
566     $_[0] =~ /^(.*)(?:\s*(\S+))$/
567     or die "$_[0]: cannot parse";
568    
569     my $file = $1;
570     my $as = defined $2 ? $2 : "/$1";
571    
572     $pm{$as} = $file;
573     }
574    
575     sub cmd_file {
576     open my $fh, "<", $_[0]
577     or die "$_[0]: $!\n";
578    
579     while (<$fh>) {
580     chomp;
581     my ($cmd, $args) = split / /, $_, 2;
582    
583     if ($cmd eq "strip") {
584     $STRIP = $args;
585     } elsif ($cmd eq "eval") {
586     trace_eval $_;
587     } elsif ($cmd eq "use") {
588     trace_module $_
589     for split / /, $args;
590     } elsif ($cmd eq "boot") {
591     cmd_boot $args;
592     } elsif ($cmd eq "static") {
593     $STATIC = 1;
594     } elsif ($cmd eq "add") {
595     cmd_add $args;
596     } elsif (/^\s*#/) {
597     # comment
598     } elsif (/\S/) {
599     die "$_: unsupported directive\n";
600     }
601     }
602     }
603    
604     use Getopt::Long;
605    
606     Getopt::Long::Configure ("bundling", "no_auto_abbrev", "no_ignore_case");
607    
608     GetOptions
609     "strip=s" => \$STRIP,
610     "verbose|v" => sub { ++$VERBOSE },
611     "quiet|q" => sub { --$VERBOSE },
612     "perl" => \$PERL,
613     "eval=s" => sub { trace_eval $_[1] },
614     "use|M=s" => sub { trace_module $_[1] },
615     "boot=s" => sub { cmd_boot $_[1] },
616     "add=s" => sub { cmd_add $_[1] },
617     "static" => sub { $STATIC = 1 },
618     "<>" => sub { cmd_file $_[1] },
619     or exit 1;
620    
621     my $data;
622     my @index;
623     my @order = sort {
624     length $a <=> length $b
625     or $a cmp $b
626     } keys %pm;
627    
628     # sorting by name - better compression, but needs more metadata
629     # sorting by length - faster lookup
630     # usually, the metadata overhead beats the loss through compression
631    
632     for my $pm (@order) {
633     my $path = $pm{$pm};
634    
635     128 > length $pm
636     or die "$pm: path too long (only 128 octets supported)\n";
637    
638     my $src = ref $path
639     ? $$path
640     : do {
641     open my $pm, "<:perlio", $path
642     or die "$path: $!";
643    
644     local $/;
645    
646     <$pm>
647     };
648    
649     if ($pm =~ /^auto\/POSIX\/[^\/]+\.al$/) {
650     if ($src =~ /^ unimpl \"/m) {
651     warn "$pm: skipping (not implemented anyways).\n"
652     if $VERBOSE >= 2;
653     next;
654     }
655     }
656    
657     if ($STRIP =~ /ppi/i) {
658     require PPI;
659    
660     my $ppi = PPI::Document->new (\$src);
661     $ppi->prune ("PPI::Token::Comment");
662     $ppi->prune ("PPI::Token::Pod");
663    
664     # prune END stuff
665     for (my $last = $ppi->last_element; $last; ) {
666     my $prev = $last->previous_token;
667    
668     if ($last->isa (PPI::Token::Whitespace::)) {
669     $last->delete;
670     } elsif ($last->isa (PPI::Statement::End::)) {
671     $last->delete;
672     last;
673     } elsif ($last->isa (PPI::Token::Pod::)) {
674     $last->delete;
675     } else {
676     last;
677     }
678    
679     $last = $prev;
680     }
681    
682     # prune some but not all insignificant whitespace
683     for my $ws (@{ $ppi->find (PPI::Token::Whitespace::) }) {
684     my $prev = $ws->previous_token;
685     my $next = $ws->next_token;
686    
687     if (!$prev || !$next) {
688     $ws->delete;
689     } else {
690     if (
691     $next->isa (PPI::Token::Operator::) && $next->{content} =~ /^(?:,|=|!|!=|==|=>)$/ # no ., because of digits. == float
692     or $prev->isa (PPI::Token::Operator::) && $prev->{content} =~ /^(?:,|=|\.|!|!=|==|=>)$/
693     or $prev->isa (PPI::Token::Structure::)
694     # decrease size, decrease compressability
695     #or ($prev->isa (PPI::Token::Word::)
696     # && (PPI::Token::Symbol:: eq ref $next
697     # || $next->isa (PPI::Structure::Block::)
698     # || $next->isa (PPI::Structure::List::)
699     # || $next->isa (PPI::Structure::Condition::)))
700     ) {
701     $ws->delete;
702     } elsif ($prev->isa (PPI::Token::Whitespace::)) {
703     $ws->{content} = ' ';
704     $prev->delete;
705     } else {
706     $ws->{content} = ' ';
707     }
708     }
709     }
710    
711     # prune whitespace around blocks
712     if (0) {
713     # these usually decrease size, but decrease compressability more
714     for my $struct (PPI::Structure::Block::, PPI::Structure::Condition::) {
715     for my $node (@{ $ppi->find ($struct) }) {
716     my $n1 = $node->first_token;
717     my $n2 = $n1->previous_token;
718     $n1->delete if $n1->isa (PPI::Token::Whitespace::);
719     $n2->delete if $n2 && $n2->isa (PPI::Token::Whitespace::);
720     my $n1 = $node->last_token;
721     my $n2 = $n1->next_token;
722     $n1->delete if $n1->isa (PPI::Token::Whitespace::);
723     $n2->delete if $n2 && $n2->isa (PPI::Token::Whitespace::);
724     }
725     }
726    
727     for my $node (@{ $ppi->find (PPI::Structure::List::) }) {
728     my $n1 = $node->first_token;
729     $n1->delete if $n1->isa (PPI::Token::Whitespace::);
730     my $n1 = $node->last_token;
731     $n1->delete if $n1->isa (PPI::Token::Whitespace::);
732     }
733     }
734    
735     # reformat qw() lists which often have lots of whitespace
736     for my $node (@{ $ppi->find (PPI::Token::QuoteLike::Words::) }) {
737     if ($node->{content} =~ /^qw(.)(.*)(.)$/s) {
738     my ($a, $qw, $b) = ($1, $2, $3);
739     $qw =~ s/^\s+//;
740     $qw =~ s/\s+$//;
741     $qw =~ s/\s+/ /g;
742     $node->{content} = "qw$a$qw$b";
743     }
744     }
745    
746     $src = $ppi->serialize;
747     } elsif ($STRIP =~ /pod/i && $pm ne "Opcode.pm") { # opcode parses it's own pod
748     require Pod::Strip;
749    
750     my $stripper = Pod::Strip->new;
751    
752     my $out;
753     $stripper->output_string (\$out);
754     $stripper->parse_string_document ($src);
755     $src = $out;
756     }
757    
758     if ($VERIFY && $pm =~ /\.pm$/ && $pm ne "Opcode.pm") {
759     if (open my $fh, "-|") {
760     <$fh>;
761     } else {
762     eval "#line 1 \"$pm\"\n$src" or warn "\n\n\n$pm\n\n$src\n$@\n\n\n";
763     exit 0;
764     }
765     }
766    
767     # if ($pm eq "Opcode.pm") {
768     # open my $fh, ">x" or die; print $fh $src;#d#
769     # exit 1;
770     # }
771    
772     warn "adding $pm\n"
773     if $VERBOSE >= 2;
774    
775     push @index, ((length $pm) << 25) | length $data;
776     $data .= $pm . $src;
777     }
778    
779     length $data < 2**25
780     or die "bundle too large (only 32MB supported)\n";
781    
782     my $varpfx = "bundle_" . substr +(Digest::MD5::md5_hex $data), 0, 16;
783    
784     #############################################################################
785     # output
786    
787     print "generating $PREFIX.h... ";
788    
789     {
790     open my $fh, ">", "$PREFIX.h"
791     or die "$PREFIX.h: $!\n";
792    
793     print $fh <<EOF;
794     /* do not edit, automatically created by mkstaticbundle */
795     #include <EXTERN.h>
796     #include <perl.h>
797     #include <XSUB.h>
798    
799     /* public API */
800     EXTERN_C PerlInterpreter *staticperl;
801     EXTERN_C void staticperl_init (void);
802     EXTERN_C void staticperl_cleanup (void);
803     EOF
804     }
805    
806     print "\n";
807    
808     #############################################################################
809     # output
810    
811     print "generating $PREFIX.c... ";
812    
813     open my $fh, ">", "$PREFIX.c"
814     or die "$PREFIX.c: $!\n";
815    
816     print $fh <<EOF;
817     /* do not edit, automatically created by mkstaticbundle */
818    
819     #include <EXTERN.h>
820     #include <perl.h>
821     #include <XSUB.h>
822    
823     #include "bundle.h"
824    
825     /* public API */
826     PerlInterpreter *staticperl;
827    
828     EOF
829    
830     #############################################################################
831     # bundle data
832    
833     my $count = @index;
834    
835     print $fh <<EOF;
836     #include "bundle.h"
837    
838     /* bundle data */
839    
840     static const U32 $varpfx\_count = $count;
841     static const U32 $varpfx\_index [$count + 1] = {
842     EOF
843    
844     my $col;
845     for (@index) {
846     printf $fh "0x%08x,", $_;
847     print $fh "\n" unless ++$col % 10;
848    
849     }
850     printf $fh "0x%08x\n};\n", (length $data);
851    
852     print $fh "static const char $varpfx\_data [] =\n";
853     dump_string $fh, $data;
854    
855     print $fh ";\n\n";;
856    
857     #############################################################################
858     # bootstrap
859    
860     # boot file for staticperl
861     # this file will be eval'ed at initialisation time
862    
863     my $bootstrap = '
864     BEGIN {
865     package ' . $PACKAGE . ';
866    
867     PerlIO::scalar->bootstrap;
868    
869     @INC = sub {
870     my $data = find "$_[1]"
871     or return;
872    
873     $INC{$_[1]} = $_[1];
874    
875     open my $fh, "<", \$data;
876     $fh
877     };
878     }
879     ';
880    
881     $bootstrap .= "require '//boot';"
882     if exists $pm{"//boot"};
883    
884     $bootstrap =~ s/\s+/ /g;
885     $bootstrap =~ s/(\W) /$1/g;
886     $bootstrap =~ s/ (\W)/$1/g;
887    
888     print $fh "const char bootstrap [] = ";
889     dump_string $fh, $bootstrap;
890     print $fh ";\n\n";
891    
892     print $fh <<EOF;
893     /* search all bundles for the given file, using binary search */
894     XS(find)
895     {
896     dXSARGS;
897    
898     if (items != 1)
899     Perl_croak (aTHX_ "Usage: $PACKAGE\::find (\$path)");
900    
901     {
902     STRLEN namelen;
903     char *name = SvPV (ST (0), namelen);
904     SV *res = 0;
905    
906     int l = 0, r = $varpfx\_count;
907    
908     while (l <= r)
909     {
910     int m = (l + r) >> 1;
911     U32 idx = $varpfx\_index [m];
912     int comp = namelen - (idx >> 25);
913    
914     if (!comp)
915     {
916     int ofs = idx & 0x1FFFFFFU;
917     comp = memcmp (name, $varpfx\_data + ofs, namelen);
918    
919     if (!comp)
920     {
921     /* found */
922     int ofs2 = $varpfx\_index [m + 1] & 0x1FFFFFFU;
923    
924     ofs += namelen;
925     res = newSVpvn ($varpfx\_data + ofs, ofs2 - ofs);
926     goto found;
927     }
928     }
929    
930     if (comp < 0)
931     r = m - 1;
932     else
933     l = m + 1;
934     }
935    
936     XSRETURN (0);
937    
938     found:
939     ST (0) = res;
940     sv_2mortal (ST (0));
941     }
942    
943     XSRETURN (1);
944     }
945    
946     /* list all files in the bundle */
947     XS(list)
948     {
949     dXSARGS;
950    
951     if (items != 0)
952     Perl_croak (aTHX_ "Usage: $PACKAGE\::list");
953    
954     {
955     int i;
956    
957     EXTEND (SP, $varpfx\_count);
958    
959     for (i = 0; i < $varpfx\_count; ++i)
960     {
961     U32 idx = $varpfx\_index [i];
962    
963     PUSHs (newSVpvn ($varpfx\_data + (idx & 0x1FFFFFFU), idx >> 25));
964     }
965     }
966    
967     XSRETURN ($varpfx\_count);
968     }
969    
970     static char *args[] = {
971     "staticperl",
972     "-e",
973     "0"
974     };
975    
976     EOF
977    
978     #############################################################################
979     # xs_init
980    
981     print $fh <<EOF;
982     static void
983     xs_init (pTHX)
984     {
985     EOF
986    
987     @static_ext = ("DynaLoader", sort @static_ext);
988    
989     # prototypes
990     for (@static_ext) {
991     s/\.pm$//;
992     (my $cname = $_) =~ s/\//__/g;
993     print $fh " EXTERN_C void boot_$cname (pTHX_ CV* cv);\n";
994     }
995    
996     print $fh <<EOF;
997     char *file = __FILE__;
998     dXSUB_SYS;
999    
1000     newXSproto ("$PACKAGE\::find", find, file, "\$");
1001     newXSproto ("$PACKAGE\::list", list, file, "");
1002     EOF
1003    
1004     # calls
1005     for (@static_ext) {
1006     s/\.pm$//;
1007    
1008     (my $cname = $_) =~ s/\//__/g;
1009     (my $pname = $_) =~ s/\//::/g;
1010    
1011     my $bootstrap = $pname eq "DynaLoader" ? "boot" : "bootstrap";
1012    
1013     print $fh " newXS (\"$pname\::$bootstrap\", boot_$cname, file);\n";
1014     }
1015    
1016     print $fh <<EOF;
1017     Perl_av_create_and_unshift_one (&PL_preambleav, newSVpv (bootstrap, sizeof (bootstrap) - 1));
1018     }
1019     EOF
1020    
1021     #############################################################################
1022     # optional perl_init/perl_destroy
1023    
1024     if ($PERL) {
1025     print $fh <<EOF;
1026    
1027     int
1028     main (int argc, char *argv [])
1029     {
1030     extern char **environ;
1031     int exitstatus;
1032    
1033     PERL_SYS_INIT3 (&argc, &argv, &environ);
1034     staticperl = perl_alloc ();
1035     perl_construct (staticperl);
1036    
1037     PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
1038    
1039     exitstatus = perl_parse (staticperl, xs_init, argc, argv, environ);
1040     if (!exitstatus)
1041     perl_run (staticperl);
1042    
1043     exitstatus = perl_destruct (staticperl);
1044     perl_free (staticperl);
1045     PERL_SYS_TERM ();
1046    
1047     return exitstatus;
1048     }
1049     EOF
1050     } else {
1051     print $fh <<EOF;
1052    
1053     EXTERN_C void
1054     staticperl_init (void)
1055     {
1056     extern char **environ;
1057     int argc = sizeof (args) / sizeof (args [0]);
1058     char **argv = args;
1059    
1060     PERL_SYS_INIT3 (&argc, &argv, &environ);
1061     staticperl = perl_alloc ();
1062     perl_construct (staticperl);
1063     PL_origalen = 1;
1064     PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
1065     perl_parse (staticperl, xs_init, argc, argv, environ);
1066    
1067     perl_run (staticperl);
1068     }
1069    
1070     EXTERN_C void
1071     staticperl_cleanup (void)
1072     {
1073     perl_destruct (staticperl);
1074     perl_free (staticperl);
1075     staticperl = 0;
1076     PERL_SYS_TERM ();
1077     }
1078     EOF
1079     }
1080    
1081     print -s "$PREFIX.c", " octets (", (length $data) , " data octets).\n\n";
1082    
1083     #############################################################################
1084     # libs, cflags
1085    
1086     {
1087     print "generating $PREFIX.ccopts... ";
1088    
1089     my $str = "$Config{ccflags} $Config{optimize} $Config{cppflags} -I$Config{archlibexp}/CORE";
1090     $str =~ s/([\(\)])/\\$1/g;
1091    
1092     print "$str\n\n";
1093    
1094     open my $fh, ">$PREFIX.ccopts"
1095     or die "$PREFIX.ccopts: $!";
1096     print $fh $str;
1097     }
1098    
1099     {
1100     print "generating $PREFIX.ldopts... ";
1101    
1102     my $str = $STATIC ? "--static " : "";
1103    
1104     $str .= "$Config{ccdlflags} $Config{ldflags} @libs $Config{archlibexp}/CORE/$Config{libperl} $Config{perllibs}";
1105    
1106     my %seen;
1107     $str .= " $_" for grep !$seen{$_}++, ($extralibs =~ /(\S+)/g);
1108    
1109     $str =~ s/([\(\)])/\\$1/g;
1110    
1111     print "$str\n\n";
1112    
1113     open my $fh, ">$PREFIX.ldopts"
1114     or die "$PREFIX.ldopts: $!";
1115     print $fh $str;
1116     }
1117    
1118     if ($PERL) {
1119     system "$Config{cc} \$(cat bundle.ccopts\) -o perl bundle.c \$(cat bundle.ldopts\)";
1120    
1121     unlink "$PREFIX.$_"
1122     for qw(ccopts ldopts c h);
1123     }
1124    
1125     MKBUNDLE
1126     }
1127    
1128     bundle() {
1129     catmkbundle >"$MKBUNDLE~" || fatal "$MKBUNDLE~: cannot create"
1130     chmod 755 "$MKBUNDLE~" && mv "$MKBUNDLE~" "$MKBUNDLE"
1131     "$PREFIX/bin/perl" -- "$MKBUNDLE" "$@"
1132     }
1133    
1134     if [ $# -gt 0 ]; then
1135     while [ $# -gt 0 ]; do
1136     mkdir -p "$STATICPERL" || fatal "$STATICPERL: cannot create"
1137     mkdir -p "$PREFIX" || fatal "$PREFIX: cannot create"
1138    
1139     command="${1#--}"; shift
1140     case "$command" in
1141     fetch | configure | build | install | clean | distclean)
1142     verblock <<EOF
1143     $command
1144     EOF
1145     "$command"
1146     ;;
1147     instsrc )
1148     instsrc "$@"
1149     exit
1150     ;;
1151     instcpan )
1152     instcpan "$@"
1153     exit
1154     ;;
1155     instschmorp )
1156     install_schmorp
1157     ;;
1158     cpan )
1159     install
1160     "$PREFIX/bin/cpan" "$@"
1161     exit
1162     ;;
1163     mkbundle )
1164     install
1165     bundle "$@"
1166     exit
1167     ;;
1168     mkperl )
1169     install
1170     bundle --perl "$@"
1171     exit
1172     ;;
1173     help )
1174     podusage 2
1175     ;;
1176     * )
1177     exec 1>&2
1178     echo
1179     echo "Unknown command: $command"
1180     podusage 0
1181     ;;
1182     esac
1183     done
1184     else
1185     usage
1186     fi
1187    
1188     exit 0
1189    
1190     =head1 NAME
1191    
1192     staticperl - perl, libc, 50 modules all in one 500kb file
1193    
1194     =head1 SYNOPSIS
1195    
1196     staticperl help # print the embedded documentation
1197     staticperl fetch # fetch and unpack perl sources
1198     staticperl configure # fetch and then configure perl
1199     staticperl build # configure and then build perl
1200     staticperl install # build and then install perl
1201     staticperl clean # clean most intermediate files (restart at configure)
1202     staticperl distclean # delete everything installed by this script
1203     staticperl cpan # invoke CPAN shell
1204     staticperl instmod path... # install unpacked modules
1205     staticperl instcpan modulename... # install modules from CPAN
1206     staticperl mkbundle <bundle-args...> # see documentation
1207     staticperl mkperl <bundle-args...> # see documentation
1208    
1209     Typical Examples:
1210    
1211     staticperl install # fetch, configure, build and install perl
1212     staticperl cpan # run interactive cpan shell
1213     staticperl mkperl -M '"Config_heavy.pl"' # build a perl that supports -V
1214     staticperl mkperl -MAnyEvent::Impl::Perl -MAnyEvent::HTTPD -MURI -MURI::http
1215     # build a perl with the above modules linked in
1216    
1217     =head1 DESCRIPTION
1218    
1219     This script helps you creating single-file perl interpreters, or embedding
1220     a pelr interpreter in your apps. Single-file means that it is fully
1221     self-contained - no separate shared objects, no autoload fragments, no .pm
1222     or .pl files are needed. And when linking statically, you can create (or
1223     embed) a single file that contains perl interpreter, libc, all the modules
1224     you need and all the libraries you need.
1225    
1226     With uclibc and upx on x86, you can create a single 500kb binary that
1227     contains perl and 50 modules such as AnyEvent, EV, IO::AIO, Coro and so
1228     on. Or any other choice of modules.
1229    
1230     The created files do not need write access to the filesystem (like PAR
1231     does). In fact, since this script is in many ways similar to PAR::Packer,
1232     here are the differences:
1233    
1234     =over 4
1235    
1236     =item * The generated executables are much smaller than PAR created ones.
1237    
1238     Shared objects and the perl binary contain a lot of extra info, while
1239     the static nature of F<staticperl> allows the linker to remove all
1240     functionality and meta-info not required by the final executable. Even
1241     extensions statically compiled into perl at build time will only be
1242     present in the final executable when needed.
1243    
1244     In addition, F<staticperl> can strip perl sources much more effectively
1245     than PAR.
1246    
1247     =item * The generated executables start much faster.
1248    
1249     There is no need to unpack files, or even to parse Zip archives (which is
1250     slow and memory-consuming business).
1251    
1252     =item * The generated executables don't need a writable filesystem.
1253    
1254     F<staticperl> loads all required files directly from memory. There is no
1255     need to unpack files into a temporary directory.
1256    
1257     =item * More control over included files.
1258    
1259     PAR tries to be maintainance and hassle-free - it tries to include more files
1260     than necessary to make sure everything works out of the box. The extra files
1261     (such as the unicode database) can take substantial amounts of memory and filesize.
1262    
1263     With F<staticperl>, the burden is mostly with the developer - only direct
1264     compile-time dependencies and L<AutoLoader> are handled automatically.
1265     This means the modules to include often need to be tweaked manually.
1266    
1267     =item * PAR works out of the box, F<staticperl> does not.
1268    
1269     Maintaining your own custom perl build can be a pain in the ass, and while
1270     F<staticperl> tries to make this easy, it still requires a custom perl
1271     build and possibly fiddling with some modules. PAR is likely to produce
1272     results faster.
1273    
1274     =back
1275    
1276     =head1 HOW DOES IT WORK?
1277    
1278     Simple: F<staticperl> downloads, compile and installs a perl version of
1279     your choice in F<~/.staticperl>. You can add extra modules either by
1280     letting F<staticperl> install them for you automatically, or by using CPAN
1281     and doing it interactively. This usually takes 5-10 minutes, depending on
1282     the speed of your computer and your internet conenction.
1283    
1284     It is possible to do program development at this stage, too.
1285    
1286     Afterwards, you create a list of files and modules you want to include,
1287     and then either build a new perl binary (that acts just like a normla perl
1288     except everything is compiled in), or you create bundle files (basically C
1289     sources you can use to embed all files into your project).
1290    
1291     This step is very fast (a few seconds if PPI is not used for stripping,
1292     more seconds otherwise, as PPI is very slow), and can be tweaked and
1293     repeated as often as necessary.
1294    
1295     =head1 THE F<STATICPERL> SCRIPT
1296    
1297     This module installs a script called F<staticperl> into your perl
1298     binary directory. The script is fully self-contained, and can be used
1299     without perl (for example, in an uClibc chroot environment). In fact,
1300     it can be extracted from the C<App::Staticperl> distribution tarball as
1301     F<bin/staticperl>, without any installation.
1302    
1303     F<staticperl> interprets the first argument as a command to execute,
1304     optionally followed by any parameters.
1305    
1306     There are two command categories: the "phase 1" commands which deal with
1307     installing perl and perl modules, and the "phase 2" commands, which deal
1308     with creating binaries and bundle files.
1309    
1310     =head2 PHASE 1 COMMANDS: INSTALLING PERL
1311    
1312     The most important command is F<install>, which does basically
1313     everything. The default is to download and install perl 5.12.2 and a few
1314     modules required by F<staticperl> itself, but all this can (and should) be
1315     changed - see L<CONFIGURATION>, below.
1316    
1317     The command
1318    
1319     staticperl install
1320    
1321     Is normally all you need: It installs the perl interpreter in
1322     F<~/.staticperl/perl>. It downloads, configures, builds and installs the
1323     perl interpreter if required.
1324    
1325     Most of the following commands simply run one or more steps of this
1326     sequence.
1327    
1328     To force recompilation or reinstalaltion, you need to run F<staticperl
1329     distclean> first.
1330    
1331     =over 4
1332    
1333     =item F<staticperl fetch>
1334    
1335     Runs only the download and unpack phase, unless this has already happened.
1336    
1337     =item F<staticperl configure>
1338    
1339     Configures the unpacked perl sources, potentially after downloading them first.
1340    
1341     =item F<staticperl build>
1342    
1343     Builds the configured perl sources, potentially after automatically
1344     configuring them.
1345    
1346     =item F<staticperl install>
1347    
1348     Wipes the perl installation directory (usually F<~/.staticperl/perl>) and installs
1349     the perl distribution, potentially aftering building it first.
1350    
1351     =item F<staticperl cpan> [args...]
1352    
1353     Starts an interactive CPAN shell that you cna use to install further
1354     modules. Installs the perl first if neccessary, but apart from that,
1355     no magic is involved: you could just as well run it manually via
1356     F<~/.staticperl/perl/bin/cpan>.
1357    
1358     Any additional arguments are simply passed to the F<cpan> command.
1359    
1360     =item F<staticperl instcpan> module...
1361    
1362     Tries to install all the modules given and their dependencies, using CPAN.
1363    
1364     Example:
1365    
1366     staticperl instcpan EV AnyEvent::HTTPD Coro
1367    
1368     =item F<staticperl instsrc> directory...
1369    
1370     In the unlikely case that you have unpacked perl modules around and want
1371     to install from these instead of from CPAN, you cna do this using this
1372     command by specifying all the directories with modules in them that you
1373     want to have built.
1374    
1375     =item F<staticperl clean>
1376    
1377     Runs F<make distclean> in the perl source directory (and potentially
1378     cleans up other intermediate files). This can be used to clean up
1379     intermediate files without removing the installed perl interpreter.
1380    
1381     =item F<staticperl distclean>
1382    
1383     This wipes your complete F<~/.staticperl> directory. Be careful with this,
1384     it nukes your perl download, perl sources, perl distribution and any
1385     installed modules. It is useful if you wish to start over "from scratch"
1386     or when you want to uninstall F<staticperl>.
1387    
1388     =back
1389    
1390     =head2 PHASE 2 COMMANDS: BUILDING PERL BUNDLES
1391    
1392     Building (linking) a new F<perl> binary is handled by a separate
1393     script. To make it easy to use F<staticperl> from a F<chroot>, the script
1394     is embedded into F<staticperl>, which will write it out and call for you
1395     with any arguments you pass:
1396    
1397     staticperl mkbundle mkbundle-args...
1398    
1399     In the oh so unlikely case of something not working here, you
1400     cna run the script manually as well (by default it is written to
1401     F<~/.staticperl/mkbundle>).
1402    
1403     F<mkbundle> is a more conventional command and expect the argument
1404     syntax commonly used on unix clones. For example, this command builds
1405     a new F<perl> binary and includes F<Config.pm> (for F<perl -V>),
1406     F<AnyEvent::HTTPD>, F<URI> and a custom F<httpd> script (from F<eg/httpd>
1407     in this distribution):
1408    
1409     # first make sure we have perl and the required modules
1410     staticperl instcpan AnyEvent::HTTPD
1411    
1412     # now build the perl
1413     staticperl mkperl -M'"Config_heavy.pl"' -MAnyEvent::Impl::Perl \
1414     -MAnyEvent::HTTPD -MURI::http \
1415     --add 'eg/httpd httpd.pm'
1416    
1417     # finally, invoke it
1418     ./perl -Mhttpd
1419    
1420     As you can see, things
1421    
1422    
1423    
1424     "strip=s" => \$STRIP,
1425     "verbose|v" => sub { ++$VERBOSE },
1426     "quiet|q" => sub { --$VERBOSE },
1427     "perl" => \$PERL,
1428     "eval=s" => sub { trace_eval $_[1] },
1429     "use|M=s" => sub { trace_module $_[1] },
1430     "boot=s" => sub { cmd_boot $_[1] },
1431     "add=s" => sub { cmd_add $_[1] },
1432     "static" => sub { $STATIC = 1 },
1433     "<>" => sub { cmd_file $_[1] },
1434    
1435     =head2 CONFIGURATION AND HOOKS
1436    
1437     =head1 AUTHOR
1438    
1439     Marc Lehmann <schmorp@schmorp.de>
1440     http://software.schmorp.de/pkg/staticperl.html
1441    
1442    
1443    
1444