mod_perl2
日付どころか月まで変わっているけれども、引き続きの話題なので。。。
ちょっと経緯をすっ飛ばしたので、説明しますと、うちのwebサイト(不思議な話リンク集)の更新をすると、一気に十数ページのHTMLが増えるんですよ。
で、これまでは「メモ帳」に手打ちでHTMLのタグを書いていたのだけれども、perlを使えば、もっと簡単に更新できるのかな?って考えて。
で、perlのCGIモジュールにたどり着いたのですが。
これまでも完全には手入力ではなく、SEDコマンドを使っていたのですが、そのため、sedとかのUNIX系コマンドを使うために、cygwinを入れていました。
で、perlもcygwinのperl使ってます。
やっと本題。
で、perlのCGI.pmって遅いらしい。
手入力していた私からすると、別に遅いとか思わないけれども。
で、偶然見つけたのがCGI::Fast
cpan CGI::Fast
だけで手に入った。
use CGI::Fast qw/:standard :no_xhtml/; my $q = CGI::Fast->new; print $q->start_html(-lang => '', -head=>[meta({-http_equiv => 'Content-Type', -content => 'text/html; charset=Shift_JIS'}) ], -title=>'タイトル');
で
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html><head><title>タイトル</title> <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"> </head>
普通のCGIモジュールと同じになる。で、実際、速い。
で、さっき「perlでHTMLを編集」と書いたので、「perl自体では編集は出来ないだろ」と思った方もおられると思うのですが、「自分のPCでperlのCGIを使ってajaxにHTMLを編集」という、斜め上な目標でやってます。
ので、cygwinでApache2サーバを立ち上げました。 ApacheサーバーのMakeは==>こちら
httpd.confに
Listen localhost:80
って入れて、安全を確保したつもり。
で、タイトルの話になるのですが、Apache2にmod_perl2ってゆうモジュールを追加すると、さらにperlのCGIが速くなるという話を見つけた。
cpan Apache2::MPM
でやって、最初につまずいたのは、"apxs"が無いというエラー。
cygwinのsetup.exeを使って"apache2-devel"をインストールすると、
/usr/sbin/apxs2
というのが出来る。
これで、やっと安心かと思いきや、次は"apr-config"が無いというエラー。
これは、またcgywinのsetup.exeで、今度は"libapr1-devel"をインストールすると
/bin/apr-1-config
というのが出来る。
今度こそ、と思ったら"gcc-4"が無いというエラー。
またcgywinのsetup.exeで、今度は"gcc4"をインストールする。
しかし、makeでエラーが出る。
エラーをパッと見た感じでは、「今度はbase64を入れないといけないのか?」と思ったが、"libapr1-devel"をインストールした時点でapr-base64.hはインストールされている。
エラーをよく読むと、
/.cpan/build/mod_perl-2.0.4-tvjBdJ/xs/modperl_xs_typedefs.h:67行
にエラーがあると言っている。ググると、[Perl][Apache]mod_perl2.0.4のビルド中、modperl_xs_typedefs.hでエラーが出る場合の対処法を発見。
その通りに2個のファイルを書き換えて、
cd /.cpan/build/mod_perl-2.0.4-dMqEoV perl Makefile.PL make install
で、無事インストール出来ました。
で、httpd.confに
LoadModule perl_module lib/apache2/mod_perl.so
を追加。Apache2を起動。すると、error_logに。
Apache/2.2.6 (Unix) mod_ssl/2.2.6 OpenSSL/0.9.8o DAV/2 mod_perl/2.0.4 Perl/v5.10.1 configured -- resuming normal operations
をを、ちゃんと読み込まれている。で、さらにhttpd.confをいじって
<IfModule mod_perl.c> <Files ~ "\.pl$"> SetHandler perl-script AddHandler perl-script .pl PerlHandler ModPerl::Registry </Files> </IfModule>
と書いて、起動して、*.plなCGIファイルをブラウザで開くと、
をを、動いた。
で、さらにhttpd.confを
<IfModule mod_perl.c> <Files ~ "\.pl$"> SetHandler modperl AddHandler modperl .pl PerlOptions +GlobalRequest PerlHandler ModPerl::Registry </Files> </IfModule>
と書き換えて、同じ*.plなCGIファイルをブラウザで開くと、"500 Internal Server Error"
error_logを見ると、
[error] Can't call method "header" on an undefined value
*.plなCGIスクリプトのCGIモジュールの"$q->header();が解釈できずに、エラーに。
しかたがないので、前のコンフィグに戻してみた。
が、同じエラーが出現。
で、ふと、*.plなCGIスクリプトを
use CGI::Fast qw(:standard :no_xhtml);
に書き換えると、1回目は動いた。が、2度目に同じエラーが出現。
"CGI header error"でググると、外人が、日本人ではちょっと見ない書き方でCGIモジュールを使っているのに遭遇。
まねして、書いた
use CGI::Fast qw(:standard :no_xhtml); print start_html(-lang => '', -head=>[meta({-http_equiv => 'Content-Type', -content => 'text/html; charset=Shift_JIS'}) ], -title=>'タイトル');
そう、"my $q = new CGI::Fast;"ってやってない。でも動いた。これだとmod_perlでのエラーもなくなった。
10/11追記
自分みたいに、ローカルな開発環境でmod_perlを動かすと、あるperlのスクリプトをテストして、駄目だった場合、スクリプトを書き直してテストしようとしても、前のスクリプトが読み込まれたままで、新しいスクリプトは実行されない。
何度もトライアンドエラー出来るのがインタプリタ言語の利点だと思うので、これはちょっと嫌な感じ。
で、この問題を解決するには、Apache2::Reloadを使えば良いらしい。
ただし、安易に使うとパフォーマンスが落ちてmod_Perlの意味がなくなるので注意。
Apache2::Reloadはmod_Perlのパッケージ自体には入っていないので、
cpan Apache2::Reload
で入手。
httpd.confを書き換える。
<IfModule mod_perl.c> PerlModule Apache2::Reload PerlInitHandler Apache2::Reload PerlSetVar ReloadDirectories "(perlスクリプトのある場所)" <Files ~ "\.pl$"> SetHandler perl-script AddHandler perl-script .pl PerlOptions +GlobalRequest PerlHandler ModPerl::Registry Order allow,deny Allow from all </Files> </IfModule>
これで、"/usr/sbin/apachectl2 -t"で"Syntax OK"だったので、Apache2起動。
うむ、書き直すと即座に反映される。
でも、mod_perlは初回実行時と2回目以降で挙動が変わるので、同じスクリプトのテストを数回やってみないとバグが判らない罠。。。
以下、10/1追記分
話が変わるけれども、mod_perlにしてからglob();の動きがおかしい。
ググるとmod_perl時の注意点というページに、perl実行時のカレントディレクトリがperlスクリプトのある場所じゃないと書かれている
そのページにある確認用スクリプトを借用して
#!/usr/bin/perl my $r =shift; $r->content_type('text/html'); $r->headers_out->add('charset'=>'Shift_JIS'); print "カレントディレクトリ : " . `pwd` . "\n";
というCGIを書いて、ブラウザで開いたところ、
カレントディレクトリ : /cygdrive/c/WINDOWS/system32
 これにはずっこけた。
なので、全ての*.plなCGIスクリプトの最初の行に
chdir $(ファイルあるパス);
を追加した。のだが、ここで問題が。
さっきのまま手を加えていない確認用スクリプトを、何気なく実行すると、
カレントディレクトリ : /cygdrive/c/(perlファイルのあるパス)
に変わっていた。1つのスクリプト内でchdirを実行するだけで、mod_perlシステム全体のカレントディレクトリが変わってしまい、保持されるようだ。
これはヒドイ
ので、perlのCGIは同じディレクトリにまとめておかないといけない。
10/9追記
MOD_Perlを再ビルドした時に「ソースはそのまま残してある」とサラッと書いたのですが、これは実はとても重要。
libapreq2をビルドしようといろいろやっていた時に見つけた情報。
/lib/perl5/site_perl/5.10/i686-cygwin/Apache2/BuildConfig.pm
の中に、MAKEしたパスがフルパスで記録されているのです。
なので、MOD_Perlのライブラリ"libaprext.a"は、デフォルトでは
/usr/include/apache2/libaprext.a
にインストールされる。なんでこんな場所なのか。
で、"/usr/lib"にコピーした場合、必ずBuildConfig.pmの中も書き換えないといけないらしい。