Catalystにはデフォルトでcatalyst_parというディレクティブが備え付けられていて、Makefile.PLで
...
catalyst_par;
...
WriteAll;
とすると後のmake時にPAR形式のファイルを作れるようになる機能があります。このPARファイルを作成するには
make catalyst_par
とするわけですが、アプリケーションができあがって、「さあPARでも作るか!」と言った皆さんはおおむね以下のような意味の分からないエラーに悩まされてきたのではないでしょうか:
Writing PAR "wifigadgets-control.par"
make: *** [catalyst_par] Error 25
この訳の分からない動作不具合、根本的な問題は二つあります。一つにはこのcatalyst_parでPARファイルを作成するモジュールがどういう理由かかなり意図的にエラーをユーザーに見せないように操作しているのです。該当モジュールはModule::Install::Catalystのこのあたり:
local $SIG{__WARN__} = sub { };
open my $olderr, '>&STDERR';
open STDERR, '>', File::Spec->devnull;
my %opt = (
'x' => 1,
'n' => 0,
'o' => $par,
'a' => [ grep( !/par.pl/, glob '.' ) ],
'p' => 1,
'B' => $CORE,
'm' => $MULTIARCH
);
App::Packer::PAR->new(
frontend => 'Module::ScanDeps',
backend => 'PAR::Packer',
frontopts => \%opt,
backopts => \%opt,
args => ['par.pl'],
)->go;
open STDERR, '>&', $olderr;
うひゃ、STDERRを完全にブロックしてやがる><
さて、これを取り除いてやるとエラーの内容がだんだんわかってきます。最初はmmap_cache.cでassert()が落ちてるとか、なんかようわからんエラーだったわけですが。これをよくよく考えてみたら、どうもMyApp->setup()がPARファイルを作成するときに呼ばれ、アプリケーション内で使われているモジュールの初期化ルーチンが実行されているみたい。
つまり、PARを作るときにrequire MyApp;が一度走るわけです。その時にMyApp.pmに、Catalystの一般的な作法である以下のコードがおいてあると、setup()が実行されちゃうわけですな
ということはこのコードをとにかく実行させなければよろしい。色んな方法があると思いますが、とりあえずあまり妙な事はしたくないので、環境変数に頼ることにしました:
package MyApp;
...
if ($ENV{ CATALYST_DEPLOY }) {
__PACKAGE__->config( ... );
__PACKAGE__->setup( qw( ... ) );
}
こうすると、script/内のスクリプトを実行する時もenv CATALYST_DEPLOY=1 とかしないといけないので、その辺りはもう少し頭良くできるかとは思いますが、とりあえず動きます。これでPARも期待通り動くようになります。
あと、もしPARにCatalyst::Plugin系のモジュールも見つけて欲しいのであれば(つまり、違うホストで実行した時にこのファイルをインストールする必要がないようにしたい場合)、setup()で呼ぶだけでなくてuseしてやる必要がありますので注意。
package MyApp;
....
use Catalyst::Plugin::ConfigLoader;
use Catalyst::Plugin::Static::Simple;
...
これはニーズに合わせて調整してください。
コメント