モダンPerlの世界へようこそ

第18回local::lib:ふだんと違う環境でPerlを使う

いつでも理想の環境を使えるとは限りません

「弘法筆を択ばず」ということわざもありますが、なんであれ手になじむまで使い込んだ道具を持っている人は、環境が変わってその道具が使えなくなるとやはりいらいらするものです。

Perlの場合もそう。日頃から自分の必要や興味に応じてがんがんCPANモジュールをインストールしていると、何らかの事情でまっさらに近いPerlを使わなければならなくなったとき、途方に暮れます。本来のコードを書き始める前に、モジュールのインストールだけで一日潰してしまった経験をお持ちの方も少なくないことでしょう。

今回は、そんな「ふだんと違う」環境でもなるべくストレスなくPerlを使えるようにするためのモダンな努力をいくつか紹介してみます。

PERL5LIBという環境変数を活用する

Perlはディストリビューションに同梱されているコアモジュールを保護するために、CPANからインストールするモジュールをコアモジュールとは別の場所(典型的にはsite/lib以下)に配置できるようになっています。このようにしておくことで、あとからsite/lib以下にインストールしたモジュールが何らかの理由で壊れても、もともとlib以下にインストールしてあったコアモジュールがバックアップの役割を果たせる、というのがそのねらいです。

同様に、Perlにはインストール済みのモジュールを保護するために、-IというスイッチやPERL5LIBという環境変数を利用してモジュールを読み込むパスを変更する仕組みがあります。これを使えば、⁠明示的にlibプラグマを追加するなどして)アプリケーションやインストール済みのモジュールを改変しなくても、特定の環境でのみ必要なモジュールを使うようにできます。

たとえば、/home/foo/myapp以下に5.7系列のMooseに対応していない)Catalystで開発したアプリケーションがあるとしましょう。これがCatalyst 5.8系列でも正しく動作するか確認したいとき、いきなりCPANでCatalystのバージョンアップをするのはやや乱暴なやり方です。このような場合はひとまず/home/foo/catalyst58以下にCatalyst 5.8系列の最新版をリポジトリからチェックアウトするなりtarballをダウンロード・展開するなりして、PERL5LIBに/home/foo/catalyst58/libをセットしてから、myappのテストを実行したり、開発用サーバを起動するのが常套手段。こうすればほかのアプリケーションにはまったく影響を与えず、もともとのコードにもいっさい手を加えずに、新しいモジュールを使ったテストを実行できます。 PERL5LIBに複数のパスを登録したい場合は、Unix系のOSならふつう「:⁠⁠、Windowsの場合は「;」で区切ります[1]⁠。また、コンパイルする必要があるモジュールの場合は、単にlibを追加するのではなく、コンパイル後にできるblib以下の各ディレクトリを(/home/foo/catalyst58/blib/lib:/home/foo/catalyst58/blib/archのように)登録します。

もっとも、この例のように外部のモジュールが少ない場合はともかく、大きなアプリケーションの移行テストをするときにPERL5LIBに何十個もパスを列挙するのは現実的ではありません。そのような場合は、どこか(ふだんモジュールをインストールしている場所とは異なる)特定のパスに複数のモジュールをインストールしておいて、そのパスをPERL5LIBに登録する方が簡単です。

たとえば、先ほどの/home/foo/myapp以下のアプリケーションを、Catalyst 5.8だけでなく、MooseやClass::MOPの開発版も入れた状態でテストしたいとしましょう。もちろんPERL5LIBに/home/foo/catalyst58/lib、/home/foo/moose/lib、/home/foo/class-mop/blib/lib、/home/foo/class-mop/blib/archという4つのバスを登録してもよいのですが(Class::MOPはコンパイルが必要なモジュールなので、/home/foo/class-mop/libではなくblib以下のディレクトリを登録する必要があります⁠⁠、それよりは、少しだけ手間はかかりますが、Catalyst 5.8やMooseのディレクトリでもmakeを実行しておいて、/home/foo/catalyst58/blib、/home/foo/moose/blib、/home/foo/class-mop/blibの中身をすべて/home/foo/extlibs以下にコピーし、PERL5LIBには/home/foo/extlibs/libと/home/foo/extlibs/archのみ指定するようにしたほうが便利です。

旧来の設定の保存の仕方

とはいえ、外部ファイルを更新するたびにいちいちお決まりのコピー先を指定してコピーするのは面倒な話ですし、Perl的ではありません。このような作業はもちろんもっと簡単にできるようになっています。

たとえば、Makefile.PLがExtUtils::MakeMaker(や、それを裏で使っているModule::Installを使って書かれている場合、⁠perl Makefile.PL」を実行するときにこのようなオプションを与えておくと、わざわざ自分でblibディレクトリ以下をコピーしなくても、いつものようにmake installすれば指定したディレクトリにインストールできるようになります。

> perl Makefile.PL PREFIX=/home/foo/extlibs
> make
> make install  # /home/foo/extlibs以下にインストール

ExtUtils::MakeMakerが十分新しければ、PREFIXのかわりにINSTALL_BASEなどのオプションを与えることもできます(こちらのほうがパスがより直感的なものになります⁠⁠。また、これらのオプションはPERL_MM_OPTという環境変数に保存しておくこともできます。この環境変数が定義されていると、直接perl Makefile.PLを実行したときだけでなく、CPANシェルなどからインストールする場合も指定したディレクトリにモジュールをインストールできるようになります(詳細はExtUtils::MakeMakerのPODをご覧ください⁠⁠。

Module::Buildを使っているモジュールの場合は、インストール時に--install_baseなどのオプションを指定することで同じような処理を行うことができます。

> perl Build.PL
> ./Build
> ./Build install --install_base /home/foo/extlibs

また、MODULEBUILDRCという環境変数を利用すると、Module::Build用のオプションをファイルに保存しておくことができます(こちらも詳細はModule::BuildのPODをご覧ください。なお、Module::Buildの次のバージョンではExtUtils::MakeMakerのようにPERL_MB_OPTという環境変数もサポートされることになっています⁠⁠。

これらのオプションは、環境変数だけでなく、CPANCPANPLUS(一時的ないし恒久的な)設定として保存することもできます。はじめてCPANシェルを起動したときにこのようなメッセージが出ていたのを覚えている方もいることでしょう。これや、これに続く関連した設定を切り替えることで、いちいち環境変数を設定しなくても、実験的なモジュールだけ別の場所に仮インストールすることができるようになります。

Every Makefile.PL is run by perl in a separate process. Likewise we
run 'make' and 'make install' in separate processes. If you have
any parameters (e.g. PREFIX, UNINST or the like) you want to
pass to the calls, please specify them here.

If you don't understand this question, just press ENTER.

Typical frequently used settings:

    PREFIX=~/perl    # non-root users (please see manual for more hints)

 
Parameters for the 'perl Makefile.PL' command? [INSTALLDIRS=site]

local::libを使って楽をする

これらの機能は、適切に組み合わせれば非常に便利なものです。makeなどの開発用ツールが用意されていれば管理者権限がないレンタルサーバなどでもユーザ領域にCPANモジュールをインストールできるようになりますし、アプリケーションを配布・展開する際にも、必要な依存モジュールだけを特定のディレクトリにインストールしておけば、Perl関係のディレクトリを丸ごとコピーしてまわるより早く展開できます。インストール済みのCPANモジュールをすべてバージョン管理システムに放り込むのはあまり現実的ではありませんが、特定のアプリケーションの依存モジュールだけならバイナリごとバージョン管理してしまってもよいでしょう。

ただ、このような環境変数の設定を毎回手作業で行っているようでは怠惰さが足りません。また、実際にいくつかの環境で設定してみればわかることですが、PERL5LIBに登録すべきディレクトリ階層はインストールされているPerlの設定によってかわります。先ほどの例のようにいつもlibとarchのみ追加すればよいということはなく、Perlのバージョンがパスに埋め込まれていたり、アーキテクチャごとにディレクトリがわかれていたりしますし、このような設定を繰り返していくうちにCPANシェルの設定とPERL_MM_OPTの設定が食い違ったりするようなことも起こりえます。

そのような問題のひとつの解決策として生まれたのが、2007年にマット・トラウト氏がリリースしたlocal::libです。このモジュールは、CPANシェルからインストールするより、自分でtarballを落としてきて手作業でインストールしたほうが便利です。perl Makefile.PLを実行するときに「--bootstrap」というオプションをつけてください。PERL5LIBをはじめとするいくつかの環境変数などの設定を自動的に行ってくれます[2]⁠。

> perl Makefile.PL --bootstrap

設定が済んで、make && make installしたら、ドキュメントを参考にしながら.bashrcなどの設定ファイルに環境変数を有効にするために必要な処理を書き込みます。Windowsユーザであればプロンプトだけでなく、コントロールパネル経由でシステムの設定をいじってログイン時に環境変数が有効になるようにする必要もあるでしょう。⁠perl -Mlocal::lib」を実行すると必要な設定が出力されるので参考にしてください。

リロケータブルPerl

local::libはライブラリの置き場所を変えるためのものでしたが、場合によっては(特にPerlのメジャーバージョンアップのときなどは)複数のperlバイナリを切り替えて使いたくなることもあります。

このとき、日頃からライブラリのアーキテクチャに依存する部分をきちんと分けて管理していればsymlinkの切り替えなどで対応できることもありますが、perlバイナリのなかにはコンパイル時にいくつかのパスが埋め込まれているため、既存のバイナリを一時別の場所に移動して、別の(問題になるのはたいていバイナリパッケージの、でしょうが)perlバイナリを決められた場所にインストールする、ということがしづらくなっています。

そのため、昔は再配置の必要があるときはperlバイナリ(や、Config.pm等の設定ファイル)にパッチをあてるというハックが使われてきたのですが、Perl 5.10系列ではコンパイル時にPerlをリロケータブルにするオプションを選択できるようになりました(詳しくはperl594deltaなどをご覧ください。この変更は5.8.9にもバックポートされています⁠⁠。もう少し具体的に書くと、PerlをConfigureするときに-Duserelocatableincしておくと、@INC(や、%Configに含まれるパス)の値が、実行時に$^X(実行中のperlバイナリの位置)からの相対パスとして計算できるような形で保存されるようになりました。その結果、perlバイナリ(と、それに関連したライブラリ群)をインストールした場所とは異なる任意の場所に移動しても、⁠インストールした位置にあったライブラリでなく)連れてきたライブラリをロードできますし、Configモジュールなどに保存されている設定に依存しているモジュールも正しく動作するようになっています。

Perl on a Stick

もっとも、このリロケータブルPerlは当然ながら実行時に余計な計算が増えます。だから、今後もOS付属のパッケージ管理システムなどに登録されるPerlがリロケータブルになることはあまり期待できませんし、どのみちコンパイルしなおす必要があるのなら、わざわざリロケータブルにしなくても、最初からインストール先を別のディレクトリにしておけばよいだけのようにも思えます。

が、たしかにこのようなリロケータブルPerlが役に立ちそうな局面はあります。

たとえば、USBメモリにPerlをインストールする例を考えてみましょう。カンファレンスで、研修で、あるいは得意先でプレゼンテーションなりデモなりを行うとします。適当なマシンにUSBメモリを指して、どのドライブ、どのパスにマウントされるかはわかりませんが、そこに移動して、USBメモリ内にインストールしておいたPerlを使ってアプリケーションを実行できれば、わざわざ重たいノートパソコンを持ち歩く必要はありません。アーキテクチャさえ一致していれば、相手先のPC(やPerl)の設定によらず動作することが期待できますし、USBメモリなら安価ですからそのまま納品物として渡してしまっても懐は痛みません。もちろん仮想マシンを丸ごとUSBメモリに放り込めば似たようなことはできますが、Perlと必要なライブラリだけ入れておくのとどちらが楽かは言うまでもないでしょう。十分な容量があるなら、USBメモリ上にCPAN::MiniによるCPANのスナップショットも構築しておけば、ネットワークにつなげない場所でも自由にPerlアプリケーションの開発を進められます――

といった思惑のもと、2008年にPerl Foundationの助成金を受けて、いまもなお開発が進められているのが、Perl on a Stickという、おもにStrawberry Perlをポータブルにするためのプロジェクトです。

このPerl on a Stickの根幹となっているStrawberry Perl自体はいまのところuserelocatableincを使ってコンパイルされているわけではないのですが(現時点ではuserelocatableincはUnix系のOSでしかサポートされていないようです⁠⁠、本稿執筆時点ではConfig、CPAN、File::HomeDirCPAN::Miniという4つのモジュールをポータブルにするPortableというディストリビューションを同梱してポータブルなモジュールのロードなどに対応しています。

興味のある方はStrawberry PerlのサイトからPerl 5.10.1のリロケータブル版がダウンロードできますのでお試しあれ。適当なディレクトリに解凍して、perlバイナリや同梱されているMinGWのバイナリがあるディレクトリのパスを通してやれば、ふつうに使えるはずです。

ガジェットとPerl

gihyo.jpでも昨年たのしいchumbyと題した連載がありましたから覚えている方も多いと思いますが、歴史が古く、どこにでも入っているPerl(とPython)は、ときおりガジェット類との組み合わせで話題になることもあります。

2009年4月に開催されたShibuya Perl Mongersのテクニカルトークでは、ジェシー・ヴィンセント氏が最近国内でも入手できるようになったKindleという電子ブックリーダー上でPerlをコンパイルするというネタのさわりの部分を紹介していました。このときは残念ながら時間切れで肝心のところまでたどりつけませんでしたが、slideshareにはそのときのスライドが公開されています。だれもが真似できるようなものではありませんが、今度はどんなガジェットでPerlが使えるというネタが出てくるのか、楽しみなことですね。

おすすめ記事

記事・ニュース一覧