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

第24回CPAN:Perl界の水先案内人

CPANが生まれるまで

その昔、Perlのスクリプトやライブラリは作者のサイトなどから個別にダウンロードしてくるものでした。古くからのユーザであればcgi-lib.plやjcode.pl、mimew.plといったライブラリのことを懐かしく思い出すでしょうし、いちいち名前はあげませんが、CGI経由で(あるいはCGIを利用せずに)実行できる各種スクリプトを落としてきて設置したことのある方も少なくないことでしょう。ライブラリだけでなく、前回紹介したデータベースに対応したPerl 4バイナリや非Unix環境向けのPerlバイナリの場合も同じです。入手先の情報などはニュースグループで共有されていましたが、ツールやライブラリが各地に分散していると必要な情報を探して環境を構築するだけでも結構な手間になってしまうため、まとめサイトとして誕生したのがCPANことComprehensive Perl Archive Networkでした。

CPANの構想自体はPerl 4時代の1993年にさかのぼれますが、最初の実装が行われたのはPerl 5.001時代の1995年8月のこと。当初はハードウェア的な制約もあってPerl本体のソースコードや、非Unix環境用のバイナリ、ドキュメント、各種スクリプト類のみの収集にとどめ、ライブラリ(モジュール)類については扱わない予定だったそうですが、アンドレアス・ケーニヒ(Andreas König)氏がSymdumpモジュールを自作のPAUSE(Perl programming Authors Upload Server)と呼ばれるリポジトリに登録したのをきっかけに世界各地からモジュールが集まり、同年10月26日の正式公開時にはすでに60を越すモジュールが登録されていました(そのなかには1995年9月1日にOZAWA Sakuro氏が登録したRomanも含まれていました⁠⁠。

CPANはその後も順調に成長を続け、1996年末までには300強のモジュールが登録されていたのですが、このようにモジュールの数が増えてくると、いちいちブラウザなどでCPAN内部の階層を行ったり来たりするのは面倒になってきます。どのみちダウンロードしたあとはかならずお決まりの手順(perl Makefile.PL && make && make test && make install)でインストールするのですから、できればダウンロードからインストールまで一手に引き受けてくれるツールがほしい――そのような声を受けて誕生したのが最初の専用クライアントであるCPAN.pmでした。

これはPAUSEの管理人でもあるアンドレアス・ケーニヒ氏が作ったものだけに、単なるインストーラにとどまらず、サーバ側で用意したインデックス類を利用して柔軟な検索が可能になっていたのが特徴で、当時からいまと変わらずモジュール名やディストリビューション名を区別せずにインストールができるようになっていました。使い方の自由度も高く、ワンライナーを使いたければこう書けますし、

> perl -MCPAN -e 'install Foo::Bar'

独自のシェルを起動すれば(Perlコードの実行も含めて)よりきめ細かい対応ができるようになっていました。

> perl -MCPAN -e shell
cpan> !$CPAN::DEBUG=1
cpan> i /^Foo/
cpan> install Foo::Bar

このCPAN.pmは1996年4月にPerl 5 Porters向けに限定公開され、1996年12月にリリースされたPerl 5.003_12からコアモジュール入りして、その後のPerlの発展に大きく寄与していくのですが、前回取り上げたExtUtils::MakeMakerModule::Buildという対抗馬があらわれたように、CPAN.pmにもCPANPLUSという対抗馬があらわれます。今回はその経緯を追いかけながら、前回取り上げなかったいまどきのMakefile.PL/Build.PLの書き方についてもまとめてみます。

See PANTS

20世紀が終わったとき、CPANには2500個強のモジュールが登録されていました。CPANには事前審査の仕組みがないのでモジュールの品質管理は基本的に個々の作者の手にゆだねられているのですが、当時はまさにドットコムバブルの時代で、過去の経緯を知らない新しいPerlユーザも激増していましたから、品質上の問題を抱えたモジュールが登録されることもあったのでしょう。2001年のYAPC::Europeではおなじみマイケル・シュワーン氏が「See PANTS[1]⁠」というセクハラまがいのネタとともにCPANTSことCPAN Testing Serviceというプロジェクトの構想を発表します。

このプロジェクトは、CPANモジュールの全体的な品質を担保するため、必要なファイルは揃っているか、用意されているテストは正しく(しかもさまざまな環境で)実行できるか、といったテストをすべてのモジュールに対して定期的に実行し、その結果を分析することで、個々のモジュールやその作者を適切に評価したり、コミュニティの支援が必要なモジュールを客観的な指標をもとに検出したりできるようにする、と謳って多くの賛同を得たのですが、実際にこのようなテスティングサービスを実現するためにはいくつかの障害がありました。そのひとつは前回紹介したExtUtils::MakeMakerの拡張性の問題でしたが、CPAN.pmも基本的にはインタラクティブに使うことを前提に書かれていたため、自動処理用のAPIなどがこなれていないという問題がありました[2]⁠。

また、当時のCPAN.pmは単一ファイル内で30回以上もpackageが切り替わるという非常に複雑な構成になっていたため、CPANTS対応に必要なパッチを作るどころか、コードを追うだけでも大変だったという問題もありました。もともとCPAN.pmはPerl 5.003の時代から本体部分だけで2500行ほどもある大きなモジュールでしたが(PODを除くと2200行ほど。そのほかに300行ほどの初期設定用コードがありました⁠⁠、その後も新しい機能や移植用のコードを吸収しながら順調に成長を続けた結果、2000年にリリースされたPerl 5.6.0の時点では本体部分だけで4500行ほどの巨大なモジュールになっていました。のべ行数では6500行ほどもあったCGI.pmのほうが上でしたが、CGI.pmは半分近くがPODですから、単一ファイルのコード量としてはCPAN.pmが当時のコアモジュールでは最大のものだったのです(ディストリビューション単位で合計すると前回取り上げたExtUtils::MakeMakerが首位に立ちます⁠⁠。

そのため、ケン・ウイリアムズ氏がExtUtils::MakeMakerに見切りをつけてModule::Buildを書き始めたように、CPANTSへの協力を申し出ていたヨス・バウマンス(Jos Boumans)氏も、CPAN.pmを直すよりは新しいものを書いたほうが早いのではないかと考えて、コミュニティ最大のモジュールを一から書き直す作業に取りかかります。その成果が、Perl 5.8リリースも間近に迫った2002年3月にリリースされたCPAN++ことCPANPLUSでした。

CPANPLUS

CPANPLUSもModule::Buildと同じく最終的には先行モジュールを置き換えることを目標として生まれたものですが、当初はCPAN.pmの持つ機能のすべてが実装されていたわけではなかったため、一般ユーザがふつうのインストーラとして使う分にはそれほど興味深い選択肢ではありませんでした[3]⁠。

ただし、CPANPLUSはもともとCPANTSで使うことを前提に機能を分割しながら書かれていたため、CPANにあるパッケージや情報を利用して何かを実現したいという層には受けがよく、同年4月には早くもCPANPLUS::Backendという開発者向けのAPIを利用したスモークテスト用のスクリプトが贈られていますし、同月末にはperl.comにBecoming a CPAN Tester with CPANPLUSという紹介記事が登場しています。

そんな開発者向けのCPANPLUSが本当に広く使われるようになったのは、アンドレアス・ケーニヒ氏が多忙のため2003年の9月からほぼ2年間(言い方をかえればPerl 5.8.1のリリース直後からPerl 5.8.7のリリース後まで)CPAN.pmの更新をできなかったからでした。これはちょうどModule::BuildやModule::Installが台頭する時期とも重なるのですが、当時Module::Buildに対応していたのはCPANPLUSだけだったので、ExtUtils::MakeMakerからModule::Buildへと移行を奨励することは、CPANからCPANPLUSへの乗り換えを奨励することにもなったのです(もっとも、CPANPLUS自身はModule::BuildではなくExtUtils::AutoInstallや、それを呑み込んだModule::Installを採用していました⁠⁠。また、インストールする手間がかかるとはいえ、いつまでも1.76_01のまま停滞しているCPAN.pmに比べて、Perlのバージョンアップとともに成長していたCPANPLUSのほうがイメージがよく見えたのも否めませんし、Perl 5.10ではコアモジュールに入ることが決まったことも移行の後押しをしたといってよいでしょう。

もっとも、CPANPLUSの開発はそれほど順調に進行したわけではありません。2002年11月にリリースされた0.040シリーズでも、2004年12月にリリースされた0.050シリーズでも、多くのコードが書き換えになりましたし、とりわけ0.050シリーズではAPIの互換性が失われたことや、従来スタイルガイドとして「Perl 5.005_03のコアに入っていないモジュールは使わない」と謳っていた方針を転換して多くの外部モジュールを同梱した(結果、コアモジュールがいたずらに増えることになった)ことから、一部の顰蹙を買いました。また、開発者向けに公開されているAPIもそれほど多くなく、説明も不足していたため、少し複雑なことをしようと思うと結局ソースを読み解いてプライベートメソッドを使わなければならないという批判もあり、当初期待されていたほど便利にはならなかったという一面もありました。

それでもこの時期以降、CPANTSがらみの多くのツールが新しいAPIにあわせて作り直されていったのですが、CPANPLUSへの関心は、アンドレアス・ケーニヒ氏が復帰してCPAN.pmの開発が再開されると徐々に下火になっていきました。Module::BuildやTest::Reporterへの対応など、それまでCPANPLUSでしかできなかったことの大半はCPAN.pmでもできるようになりましたし、CPANPLUSの開発が停滞しているうちにCPAN.pmでしかできないことも増えてきたためです。

distroprefs

なかでもCPANTS界にとりわけ大きな影響を与えたのが、2006年10月に導入されたdistroprefsというシステムでした。

もともとCPANクライアントは2000年頃にはもう依存モジュールの解決を自動的に行ってくれていたので、適切に設定を行えば、インストールコマンドひとつで依存モジュールから何からすべて全自動でインストールできるようになっていました。CPAN.pmの場合、CPANシェルから次のような設定変更コマンドを実行することで、依存モジュールのインストールを自動化できます[4]⁠。

cpan> o conf prerequisites_policy follow

ただし、これらのポリシーはあくまでもCPAN.pmのフロー管理でしかありません。そのため、さまざまな理由からMakefile.PL/Build.PL実行時に独自のプロンプトを出してユーザの判断をあおぐようになっているモジュールがあると、インストールがそこで中断してしまう、という問題がありました。典型的な例が、Module::BuildやModule::Installが導入した「recommends」というオプションです。これはユーザに機能の取捨選択を認めるという意味では非常に便利な機能でしたが、CPANTS的には自動処理をさまたげる困った機能でもあったため、早くからデフォルトの選択を用意して、自動処理中はそちらを優先するよう求められてきました。ExtUtils::AutoInstallやModule::Installではperl Makefile.PL実行時に「--defaultdeps」「--checkdeps」などの引数をつけることでその問題を解決できるようになっていますが、CPANクライアントから実行する際にはいちいちそのような引数を設定してはいられませんし[5]⁠、それはあくまでもModule::Installの問題を解決するにすぎません。

そこで、CPAN.pmではより汎用的に、各ディストリビューションのMakefile.PL/Build.PLの処理を監視し、期待した文字列が表示されたら自動的に求められている値を入力できるような仕組みを導入しました。それが、ディストリビューションごとの(distro)設定(preferences)を略したdistroprefsです。

このdistroprefsは、事前にMakefile.PL/Build.PLの出力を把握しておく必要があるため、一度インストールすればおしまいという一般的なユーザにとってはそれほど役に立つわけではありませんが、大量にテストを実行するCPANテスターや、各種パッケージを作成するシステム管理者にとってはいちいち決まり切ったプロンプトで処理をとめられることがなくなるため、各地で重宝されるようになりました。CPAN.pmには精力的なCPANテスターでもあるアンドレアス・ケーニヒ氏が利用しているdistroprefsが同梱されているので一度確認してみるとよいでしょう。

モジュールを書く人ができること

もっとも、最近ではいちいちプロンプトを出すより、モジュール作者のほうでMakefile.PL/Build.PLを作成するときに適切なデフォルト値を用意すべきだというのがCPANTS界の論調となっています(recommendsやそれをまとめるfeaturesといったModule::Build/Module::Installの拡張機能は避けるべきものとされています⁠⁠。どうしても独自のプロンプトを出したい場合は、自分で実装するのではなく、ExtUtils::MakeMakerがエクスポートしているpromptのように、特定の環境変数(この場合はPERL_MM_USE_DEFAULT)を設定することで選択をスキップできるようなものを利用するのが好ましいとされています(最近ではAUTOMATED_TESTINGという環境変数を利用して、自動テストの際には特殊な処理をスキップするような書き方も行われるようになってきました⁠⁠。

また、最近のCPAN.pmではコマンドラインから「cpan . 」を実行することでローカルのMakefile.PLを利用してインストールを実行できるようになったため、Module::Installの長所とされてきたauto_installの存在意義はほとんどなくなりました。前回も紹介したように、この機能は過去にCPAN.pmやCPANPLUSの依存解決処理を乱してきた実績もあるため、現在は廃止の対象となっています(CPAN.pmの復活以後対策がとられましたが、一時期はCPAN.pmを利用してインストールしていたはずのモジュールがいつの間にかCPANPLUSでインストールされていた、ということもあったのです⁠⁠。

このように、2000年代初頭によかれと思って追加された機能の多くがいまでは自動化をさまたげる障害物として非推奨となっているのですが、なかには最近対応が進んで、より適切な指定ができるようになってきたものもあります。特に、Makefile.PL/Build.PLの実行に必要なモジュールを指定するconfigure_requiresと、ビルド時(通常はテスト時)にのみ必要なbuild_requiresの指定ができるようになったことは、無闇に依存関係を増やしたくない外部のバイナリパッケージ管理ツールの作者にとっては朗報だったようです(CPAN.pm、CPANPLUSともにこられの指定は理解しますが、Perlの場合はあれこれ言わずにインストールしてしまったほうがテストのたびに(configure|build)_requiresなモジュールのインストールを見なくてすむので結局安上がりになります⁠⁠。

このようなベストプラクティスは、もちろん覚えておくにこしたことはありませんが、はじめてモジュールを書く人にいきなりそのすべてを理解して適切な設定を書きなさいと強要するのも無茶な話。次回はこのようなときに便利に使えるツールを紹介することにしましょう。

おすすめ記事

記事・ニュース一覧