PAR-0.75 > PAR::Intro

名前

PAR::Intro - Introduction to Perl Archive Toolkit

PAR::Intro - Perl Archive Toolkit の導入

概要

# これはプレゼンテーションであって、モジュールではない。

Note that a more extensive tutorial is now available online as http://aut.dyndns.org/par-tutorial/ and has superceded materials in this introduction.

より発展的なチュートリアルはhttp://aut.dyndns.org/par-tutorial/ からオンラインで利用可能だ。これはこのイントロダクションの素材よりも できの良いものになってきている。

説明

PAR (Perl Archive Toolkit) とは何か?

  • Do what JAR (Java Archive) does for Perl

    JAR (Java Archive) がやることをPerlで行なう

    • Platform-independent, compressed file format (zip)

      プラットフォームに依存しない、圧縮ファイル形式(zip)

    • Aggregates modules, scripts and other files into one file

      モジュール、スクリプト、その他のファイルを一つのファイルにまとめる

    • Easy to generate, update and extract

      生成、更新、取り出しが容易

  • Benefits of using PAR:

    PARを利用する利点:

    • Reduced download and deployment time

      ダウンロードと展開の時間を短縮

    • Saves disk space by compression and selective packaging

      圧縮と選択的なパッケージ化によりディスクスペースを節約

    • Version consistency: solves forward-compatibility problems

      バージョンによらず一貫性が保たれる:前方互換の問題を解決

    • Community support: par@perl.org

      コミュニティによるサポート:par@perl.org

  • You can also turn a PAR file into a self-contained script

    PARファイルを自己完結なスクリプトにすることもできる

    • Bundles all necessary 3rd-party modules with it

      必要な全てのサードパーティモジュールを一緒にバンドル

    • Requires only core Perl to run on the target machine

      必要なのは、当該マシン上で実行されるコアなPerlのみ

    • If you use pp to compile the script...

      ppを使ってスクリプトをコンパイルすれば…

    • ...you get an executable not even needing core perl

      …コアとなるperlさえ必要としない実行ファイルを得る

Getting Started

  • First, generate a PAR file with modules in it:

    最初にモジュールの入ったPARファイルを生成する:

        % zip foo.par Hello.pm
        % zip -r foo.par lib/       # grab all modules in lib/
  • Using modules stored inside a PAR file:

    PARファイルの中に格納されたモジュールを使う:

        % perl -MPAR=./foo.par -MHello
        % perl -MPAR=./foo -MHello  # the .par part is optional
  • Or put it in @INC and use it just like a directory:

    あるいは@INC内にファイルを置き、ディレクトリのように利用する:

        % perl -MPAR -Ifoo.par -MHello
        % perl -MPAR -Ifoo -MHello  # 同上

コマンドラインツール

  • Use pp to scan scripts and store dependencies as a PAR file:

    ppを使ってスクリプトを走査し、PARファイルの依存関係にあるものを格納する:

        % pp -p source.pl           # makes 'source.par'
        % pp -B -p source.pl        # bundles core modules too
  • Use par.pl to run files from a Perl Archive:

    par.plを使ってPerlアーカイブからファイルを実行する:

        % par.pl foo.par            # looks for 'main.pl' by default
        % par.pl foo.par test.pl    # runs script/test.pl in foo.par
  • Use parl or parl.exe to run files from a Perl Archive:

    parlあるいはparl.exeを使ってPerlアーカイブからファイルを実行する:

        % parl foo.par
        % parl foo.par test.pl

バイナリ実行ファイルの作成 Making Binary Executables

  • The pp utility can also generate binary executables:

    ppユーティリティはバイナリ形式の実効ファイルも生成できる:

        % pp -o packed.exe source.pl    # self-contained .exe
        % packed.exe                    # runs anywhere with the same OS
  • You can also bundle additional modules:

    追加のモジュールをバンドルすることもできる:

        # packs CGI + its dependencies, too
        % pp -o packed.exe -M CGI source.pl
  • Or pack one-liners:

    あるいは一行スクリプトのパック:

        # turns one-liner into executable
        % pp -o packed.exe -e 'print "Hi!"'
  • Some notes:

    諸注意:

    • The command-line options of pp are almost identical to perlcc's

      ppのコマンドラインオプションはperlccのものとほぼ同じである

    • Modules are read directly from the PAR file, not extracted

      モジュールはPARファイルから直接読み込まれるのであって、展開されるのではない

    • Shared object files (aka dll) are extracted with File::Temp

      共有オブジェクトファイル(例えばdll)はFile::Tempを使って展開される

    • Tested on Win32, FreeBSD, Linux, AIX, Solaris, Darwin and Cygwin.

      Win32, FreeBSD, Linux, AIX, Solaris, Darwin そして Cygwinでテストされた

PARファイル解剖

  • Modules can reside in different directories in a PAR file:

    モジュールはPARファイル内において様々なディレクトリに属する:

        /lib/                       # standard location
        /arch/                      # for creating from blib/ 
        /i386-freebsd/              # i.e. $Config{archname}
        /5.8.0/                     # i.e. Perl version number
        /5.8.0/i386-freebsd/        # combination of the two above
        /                           # casual packaging only
  • Scripts are stored in one of the two locations:

    スクリプトは次の二つのロケーションのうちの一つに格納される:

        /script/                    # standard location
        /                           # casual packaging only
  • Shared libraries may be architecture- or perl-version-specific:

    共有ライブラリはarchitecture-かperl-version-specificに:

        /shlib/(5.8.0/)?(i386-freebsd/)?
  • PAR files may recursively contain other PAR files:

    PARファイルは他のPARファイルを再帰的に含む:

        /par/(5.8.0/)?(i386-freebsd/)?
     
  • Special files:

    特殊なファイル:

        /MANIFEST                   # index of the PAR's contents
        /SIGNATURE                  # digital signature(s)
        /META.yml                   # dependency, license info, etc.
        /Build.PL                   # self-contained installer
  • Programs can use PAR::read_file($filename) to read file contents inside PAR

    プログラムはPAR::read_file($filename)を使ってPAR内の ファイルコンテンツを読むことが出来る

  • Programs can use PAR::reload_libs() to reload modules within changed PARs

    プログラムはPAR::reload_libs()を使って、変更されたPAR内のモジュールを 再読み込みすることができる。

派生モジュール

  • Apache::PAR

    • Nathan Byrd's attempt to make self-contained Perl Handlers

      Nathan Byrdによる自己完結したPerlハンドラ作成の試み

    • Same as the WAR files for Java Servlets

      Java ServletにおけるWARファイルと同じもの

    • Includes PerlRun and Registry handlers

      PerlRunとRegistryハンドラを含む

  • App::Packer::Backend::PAR

    • Support module of Mattia Barbon's App::Packer suite

      Mattia BarbonのApp::Packerセットのサポートモジュール

    • Makes it easy to pick-and-choose dependency scanners and packers

      依存関係のスキャナとパッカーを選びやすくする

    • Fine-tuned distribution and packaging controls

      よくチューニングされた配布物とパッケージ制御

  • CPANPLUS::Dist::PAR

    • Cross-platform PPM: Auto-generate PAR out of CPAN distributions

      クロスプラットフォームPPM:CPANディストリビューションから自動生成されたPAR

    • Use the bundled Build.PL to install PAR modules into system

      バンドルされたBuild.PLを使ってシステムにPARモジュールをインストールする

Apache::PARのデモ

  • In httpd.conf:

    httpd.conf

        <VirtualHost *>
            <IfDefine MODPERL2>
            PerlModule Apache::ServerUtil
            </IfDefine>
            PerlModule Apache::PAR
            PARDir /opt/myapp
            PARFile /opt/myapp/myapp.par
        </VirtualHost>
  • In web.conf inside myapp.par:

    myapp.par内のweb.conf

        Alias /myapp/static/ ##PARFILE##/
        <Location /myapp/static>
            SetHandler perl-script
            PerlHandler Apache::PAR::Static
            PerlAddVar PARStaticDirectoryIndex index.html
            PerlSetVar PARStaticDefaultMIME text/html
        </Location>
    
        Alias /myapp/cgi-perl/ ##PARFILE##/
        <Location /myapp/cgi-perl>
            Options +ExecCGI
            SetHandler perl-script
            PerlHandler Apache::PAR::Registry
        </Location>

今後の開発

  • Polish pp's features

    ppの機能に磨きをかける

    • Handles corner dependency cases for LWP, Tk, DBI...

      LWP, Tk, DBI...に対するcorner dependencyなケースの処理

    • Optional encryption support (but *not* obscuring)

      暗号化オプションのサポート(オブスキュアリングではない)

    • Become a worthy competitor to PerlApp and Perl2Exe

      PerlAppとPerl2Exeに対抗できるぐらいにする

  • Learning from JAR

    JARから学ぶ

    • Making par.pl's command line interface in sync with jar's

      par.plのコマンドラインインターフェースをjarのものと同期させる

    • Digital signatures for PAR packages using Module::Signature

      Module::Signatureを使ってPARパッケージ用のデジタル署名

    • File layout compatibility?

      ファイルレイアウトの互換性?

  • Learning from FreeBSD Bento

    FreeBSDのBentoから学ぶ

    • Smoke test and make PAR automatically for each CPAN upload

      CPAN uploadのための自動的なスモークテストとPARの作成

    • Provide binary packages for users without a compiler

      コンパイラを持っていないユーザーのためにバイナリファイルの提供

PAR.pmの実装に関する概観

  • Here begins the scary part

    ここより危険地帯

    • Grues, Dragons and Jabberwocks abound...

      グルー、ドラゴン、ジャバウォックがいっぱい…

    • You are going to learn unpleasant things about Perl internals

      あなたはPerlの内部に関する喜ばしくないものを学ぼうとしている

    • Go home now if you have heart condition or digest problems

      心臓に持病があるか胃の調子が悪いなら今すぐお帰りなさい

  • PAR invokes five areas of Perl arcana:

    PARはPerl奥義の5つの領域を召還する

    • @INC code references

      @INCコードリファレンス

    • On-the-fly source filtering

      オンザフライなソースフィルタリング

    • Faking <DATA> filehandle with PerlIO::scalar and IO::Scalar

      PerlIO::scalarとIO::Scalarを使って<DATA>ファイルハンドリングをだます

    • Overriding DynaLoader::bootstrap to handle XS modules

      DynaLoader::bootstrapをオーバーライドしてXSモジュールを操作

    • Making self-bootstrapping binary executables

      自己ブートストラップ型バイナリ実行ファイルの生成

  • The first two only works on 5.6 or later

    最初の二つは5.6以降でのみ動作する

    • PerlIO::scalar is 5.8-specific; IO::scalar only needs 5.005

      PerlIO::scalaは5.8の仕様;IO::scalaは5.005を必要とするだけ

    • DynaLoader and %INC are there since Perl 5 was born

      DynaLoader と %INC は Perl 5 以降存在している

    • PAR currently needs 5.6, but a 5.005 port is possible

      PARは現在5.6が必要だが、5.005ポートは可能

@INC内のコードリファレンス

  • On 1999-07-19, Ken Fox submitted a patch to P5P

    1999-07-19 に Ken Fox がP5Pにパッチを提起した

    • To "enable using remote modules" by putting hooks in @INC

      @INCにフックを置くことでリモートにあるモジュールを利用できるようにする

    • It's accepted to come in Perl 5.6, but only get documented by 5.8

      Perl 5.6で受け入れられたが、5.8になってからドキュメント化された

    • Type 'perldoc -f require' to read the nitty-gritty details

      'perldoc -f require'とタイプすれば詳細を読むことができる

  • Code references in @INC may return a filehandle, or undef to 'pass':

    @INC内のコードリファレンスは'pass'に対してファイルハンドルかundefを返す:

        push @INC, \&my_sub;
        sub my_sub {
            my ($coderef, $filename) = @_;  # $coderef は \&my_sub
            open my $fh, "wget http://example.com/$filename |";
            return $fh;     # リモートホストのモジュールを使う、本当に!
        }
  • Perl 5.8 let you open a file handle to a string, so we just use that:

    Perl 5.8では、文字列へのファイルファンドルをオープンできる。 よって次のように:

        open my $fh, '<', \($zip->memberNamed($filename)->contents);
        return $fh;
  • But Perl 5.6 does not have that, and I don't want to use temp files...

    しかしPerl 5.6ではできない。一時ファイルは使いたくないし…

Filter::* モジュールを使わないソースフィルタリング

  • ... Undocumented features to the rescue!

    …救済のための機能がドキュメント化されていない!

    • It turns out that @INC hooks can return *two* values

      結局@INCのフックは*2つ*の値を返すことがわかる

    • The first is still the file handle

      一番目はファイルファンドル

    • The second is a code reference for line-by-line source filtering!

      二番目は一行毎のソースフィルタリングのためのコードリファレンス!

  • This is how Acme::use::strict::with::pride works:

    これはAcme::use::strict::with::prideの動作の仕方:

        # 全てのモジュールにstrictとwarningsを使わせる
        open my $fh, "<", $filename or return;
        my @lines = ("use strict; use warnings;\n", "#line 1 \"$full\"\n");
        return ($fh, sub {
            return 0 unless @lines; 
            push @lines, $_; $_ = shift @lines; return length $_;
        });
  • But we don't really have a filehandle for anything

    しかし我々は何らかのものに対するファイルハンドルを本当に持っていない

    • Another undocumented feature to the rescue

      もう一つのドキュメント化されていない救済機能

    • We can actually omit the first return value altogether:

      我々は一番目の戻り値を全て捨てることが実際可能だ:

          # PAR内のファイルから一行毎に内容を全て返す
          my @lines = split /(?<=\n)/, $zip->memberNamed($filename)->contents;
          return (sub { $_ = shift(@lines); return length $_ });

<DATA>ハンドルをだます

  • The @INC filter stops when it sees __END__ or __DATA__

    @INCフィルタは__END____DATA__を見つけるとストップする

    • All contents below are lost

      そこから下の内容は全て失われる

    • Breaks modules that read from the <DATA> filehandle

      <DATA>ファイルハンドルから読み込むモジュールを壊してしまう

    • The same problem appears when we eval the main.pl script

      同様の問題がmain.plスクリプトをevalするときに現れる

  • Therefore, we insert a line before the final token to fake *DATA

    それゆえ、最後のトークンの前に一行挿入して*DATAをごまかす

    • It has to be the final line to belong to the correct package

      正しいパッケージに属する最終行でなければならない

    • It has to happen in compile time but not inside a BEGIN block

      コンパイル時に発生しなければならないが、BEGINブロックの中でではない

    • Here is what I came up with (but no longer needed in recent versions):

      私が考え出しのはこのような方法だ(だがもはや最近のバージョンでは必要ない):

          $DATACache{$file} = $1 if ($program =~ s/^__DATA__\n?(.*)//ms);
          if (eval {require PerlIO::scalar; 1}) {
              "use PerlIO::scalar".
              "  ( open(*DATA, '<:scalar', \\\$PAR::DATACache{'$key'}) ? () : () )";
          }
          elsif (eval {require IO::Scalar; 1}) {
              # This will first load IO::Scalar, *then* tie the handles.
              "use IO::Scalar".
              "  ( tie(*DATA, 'IO::Scalar', \\\$PAR::DATACache{'$key'}) ? () : () )";
          }
          else {
              # only dies when it's used
              "use PAR (tie(*DATA, 'PAR::_data') ? () : ())\n";
          }
          sub PAR::_data::TIEHANDLE { return bless({}, shift) }
          sub PAR::_data::AUTOLOAD { die "Please install IO::Scalar first!\n" }

DynaLoader::bootstrapのオーバーライド

  • XS modules have dynamically loaded libraries (.so or .dll)

    XSモジュールは動的にライブラリ(.so.dll)をロードする

    • They cannot be loaded as part of a zip file, so we extract them out

      それらはzipファイルの一部としてロードされない。だから展開すことになる

    • But I don't want to make any temporary auto/ directories

      だが、一時的なauto/ディレクトリはつくりたくない

    • So we have to intercept DynaLoader's library-finding process

      そこでDynaLoaderのライブラリ探査処理を横取りしなければならない

  • Module names are passed to bootstrap for XS loading

    モジュール名はXSローディングのためにbootstrapに渡される

    • During the process, it calls dl_findfile to locate the file

      この処理の間に、ファイルの位置を把握するためdl_findfileを呼び出す

    • So we wrap around both functions:

      そのために両関数をラップする:

          no strict 'refs'; no warnings 'redefine';
          $bootstrap   = \&DynaLoader::bootstrap;
          $dl_findfile = \&DynaLoader::dl_findfile;
          *{'DynaLoader::bootstrap'}   = \&_bootstrap;
          *{'DynaLoader::dl_findfile'} = \&_dl_findfile;
  • Our _bootstrap just checks if the library is in PARs

    我々の_bootstrapは、PARの中にライブラリがあるかどうかチェックを行なう

    • If yes, extract it to a File::Temp temp file

      もしあるなら、File::Tempの一時ファイルに展開される

      • The file will be automatically cleaned up when the program ends

        プログラムが終わると、ファイルは自動的にクリンナップされる

    • It then pass the arguments to the original $bootstrap

      それから引数は元の$bootstrapに渡される

    • Finally, our _dl_findfile intercepts known filenames and return it

      最後に、我々の_dl_findfileは知ったファイル名を補足し、それを返す

自己内包型PAR実行ファイルの解剖

  • The par script ($0) itself

    parスクリプト($0)自身は

    • May be in plain-text (par.pl)

      プレインテキスト(par.pl)

    • Or native executable format (par or par.exe)

      あるいは実行可能形式(parやpar.exe)である

  • Any number of embedded files

    任意の数のファイルを埋め込める

    • Typically used for bootstrapping PAR's various XS dependencies

      典型的にはPARの様々なXSの依存関係物をブートストラップするために利用される

    • Each section begins with the magic string "FILE"

      各セクションはマジック文字列"FILE"で始まる

    • Length of filename in pack('N') format and the filename (auto/.../)

      pack(N)形式のファイル名の長さとファイル名(auto/.../)

    • File length in pack('N') and the file's content(not compressed)

      pack(N)されたファイルサイズとファイルの内容(圧縮されない)

  • One PAR file

    一つのPARファイル

    • This is just a zip file as usual

      これは単に普通のzipファイルだ

    • Beginning with the magic string "PK\003\004"

      マジック文字列"PK\003\004"で始まる

  • Ending section

    終了セクション

    • A pack('N') number of the total length of FILE and PAR sections

      ファイルとPARセクション全体のサイズをpack('N')した数

    • Finally, there must be a 8-bytes magic string: "\012PAR.pm\012"

      最後に、8バイトのマジック文字列がなければならない:"\012PAR.pm\012"

Self-Bootstrappingのトリック

  • All we can expect is a working perl interpreter

    期待することはperlインタプリタとして動作することだ

    • The self-contained script *must not* use any modules at all

      自己完結的スクリプトはどんなモジュールも使っては*ならない*

    • Not even strict.pm or DynaLoader.pm

      strict.pmやDynaLoader.pmでさえもだめだ

    • But to process PAR files, we need XS modules like Compress::Zlib

      しかしPARファイルを処理するためにはCompress::ZlibのようなXSモジュールが必要だ

    • A chicken-egg problem

      鶏が先か卵が先か

  • Solution: bundle all module and object files needed by PAR.pm

    解決方法:PAR.pmによって必要とされる 全てのモジュールとオブジェクトファイルをバンドルする

    • That's what the FILE section in the previous slide is for

      先のスライドにおけるFILEセクションはこのためのものであった

    • Load modules to memory, and write object files to disk

      メモリにモジュールをロードし、オブジェクトファイルをディスクに書き込む

    • Then use a local @INC hook to load them on demand

      そして必要なときにローカルな@INCフックを使用してそれらをロードする

  • We want to minimize the amount of temporary files

    一時ファイルの量は最小化したいものだ

    • First, try getting PerlIO::scalar loaded

      まず最初に、PerlIO::scalarのロードを試してみる

      • So everything else can be in-memory

        そうすれば全部メモリ内における

    • Next, try getting File::Temp loaded for better tempfile()

      次に、tempfile()よりも良いFile::Tempをロードするのを試みる

    • Set up an END hook to unlink all temp files up to this point

      ENDフックをセットアップして、この時点までの一時ファイルを全てunlinkする

    • Load all other bundled files

      その他の全てのバンドルされているファイルをロードする

    • Finally we are able to look in the compressed PAR section

      最終的に、圧縮されたPARセクションを見ることができる

  • This can be so much easier if we have a pure-perl inflate()

    もしピュアPerlのinflate()を持っているなら、もっと簡単にできる

    • Patches welcome!

      パッチ大歓迎!

SEE ALSO

http://www.autrijus.org/par-tutorial/

http://www.autrijus.org/par-intro/ (English version)

http://www.autrijus.org/par-intro.zh/ (Chinese version)

PAR, pp, par.pl, parl

ex::lib::zip, Acme::use::strict::with::pride

App::Packer, Apache::PAR, CPANPLUS, Module::Install

作者

Autrijus Tang <autrijus@autrijus.org>

http://par.perl.org/ is the official PAR website. You can write to the mailing list at <par@perl.org>, or send an empty mail to <par-subscribe@perl.org> to participate in the discussion.

Please submit bug reports to <bug-par@rt.cpan.org>.

著作権

Copyright 2002, 2003 by Autrijus Tang <autrijus@autrijus.org>.

This document is free documentation; you can redistribute it and/or modify it under the same terms as Perl itself.

See http://www.perl.com/perl/misc/Artistic.html