Perl Hackers Hub

第21回 Carton & cpanm―Perlモジュール管理最新事情(3)

この記事を読むのに必要な時間:およそ 2 分

(1)こちら⁠2)こちらから。

Carton

Cartonもcpanmと同様に,宮川達彦さんを中心に開発しているツールです。Cartonがどんなツールかについては,PODにズバリな一文があるので引用します。

carton is a command line tool to track the Perl module dependencies for your Perl application.

「Cartonとは,アプリケーションにおけるPerlモジュールの依存関係を管理するコマンドラインツール」というわけです。

また,PODのNAMEセクションには次の記述があります。

Carton - Perl module dependency manager (aka Bundler for Perl)

Rubyでお馴染みのBundlerという単語が出てきました。Rubyを使う人にはこちらのほうがピンとくるのではないでしょうか。BundlerはRubyのモジュール管理ツールとして有名で,CartonはBundlerにインスパイアされて開発されています。

どのように動くのか

それでは,Cartonとはどのように動くツールなのかを見ていきます。

そもそもPerlモジュールのインストールにはメタデータが必要です。メタデータとは,Makefile.PLや Build.PL のことで,ExtUtils::MakeMakerModule::BuildあるいはModule::Installといったツールチェイン注2と協調して動くものです。ここにモジュール名や作者情報,そしてモジュールの依存関係などを書くようになっていて,その書き方はツールチェインごとに異なります。

Cartonはここで定義された依存関係を解決し,それらモジュールを一括で,アプリケーション単位で独立した場所にインストールしたりダウンロードしたりできます。また,ここで独立してインストールしたモジュールを使うようにPerlを実行できます。

次のセクションで解説しますが,Carton 0.9.4まではMakefile.PLやBuild.PLに書かれた依存関係を読んで実行していましたが,0.9_5以降ではcpanfileという新しいフォーマットのみをサポートするように変更されました。

なお,以降の説明では特にことわりがない場合,Carton 0.9.15を例に使い方を説明します。

注2)
プログラムを作成するために必要なツールのことです。ここではExtUtils::MakeMakerやModule::Buildなどのモジュールを指します。

cpanfile

cpanfileとは,モジュールの依存関係を定義するファイルです。RubyでいうGemfileと同じ役割を持っています。BundlerがGemfileからモジュール依存関係を解決するように,Cartonはcpanfileを使うことで同様のことを行います。

前述のとおり,以前はcpanfileは存在せずMakefile.PLなどを直接読むようになっていましたが,なぜcpanfileというフォーマットが新規に作成され,そしてCartonではそれをサポートするようになったのでしょうか。cpanfile-faqの記載を抜粋すると,次のような理由によります。

CPANにアップロードしないプロダクトの考慮
たとえばアプリケーションプロジェクトでは,依存関係の定義だけが欲しいので,Makefile.PLやBuild.PLをあえて作成する必要はない
より正確な依存関係の解析
モジュールのビルドそのものに必要となるconfigureフェーズも,正確に定義・解析できるようになる(後述)
CPAN Meta Spec v2のサブセットとなるDSLDo main Specific Languageドメイン特化言語)のサポート
Module::InstallライクなDSLに加えて,CPAN Meta Spec v2の機能であるバージョンの範囲指定などもサポートされる

既存のMakefile.PLなどをそのまま利用するのでは,CPAN Meta Spec v2の完全なサポートが難しいなど制約が残ります。既存のツールチェインを無理矢理ハックして利用するのは筋が悪いですし,そのせいでCartonの新機能開発にも制約が出てしまったりもするので,cpanfileという新規フォーマットを使ってCartonの利用シーンに合ったやるべきことを実現するというアプローチは,お互いにとって良いことだと言えるでしょう。

cpanfileの書き方

cpanfileは前述のとおりModule::Installによく似たDSLで依存関係を定義します。PODからcpanfileの例を引用します。

requires 'Catalyst', '5.8000'; # 5.8000 or newer
requires 'Catalyst::View::JSON', '>= 0.30, < 0.40';

recommends 'JSON::XS', '2.0';
conflicts 'JSON', '< 1.0';

on 'test' => sub {
  requires 'Test::More', '>= 0.96, < 2.0';
  recommends 'Test::TCP', '1.12';
};

on 'develop' => sub {
  recommends 'Devel::NYTProf';
};

requiresrecommendsはModule::Installでも使われており,それぞれ必須モジュールおよび推奨モジュールを書きます。ほかにconflictssuggestsもありますので,詳しくはCPAN::Meta::Specを参照してください。ちなみにCarton 0.9.15でサポートされているのはrequiresのみです。

これらの引数は以下のように指定でき,モジュール名は必須ですが,バージョン定義部分は省略すると取得できる最新バージョンとして解釈されます。バージョン部分を指定する場合は,最低バージョン,範囲指定,あるいは特定バージョンというようにさまざまな書き方ができます。

requires 'Module::Name';
requires 'Module::Name', 'MINIMUM VERSION';
requires 'Module::Name', '>= MINIMUM, < MAXIMUM';
requires 'Module::Name', '== SPECIFIC VERSION';
フェーズ

on 'PHASE'という記法で,モジュール定義の動作フェーズを限定できます。フェーズにはconfigurebuildtestruntimedevelopの5つがあります。上記例のようにフェーズ指定がない場合は,runtimeフェーズとして扱われます。

テストのみで必要なモジュールはtestフェーズで,モジュール開発者のみ必要なモジュールはdevelopフェーズで,ビルド実行前にツールチェインレベルで必要なモジュールはconfigureフェーズで,というように使い分けることができます。

on 'confgure' => sub {
  requires 'Module::Build', '0.40';
  requires 'Module::CPANfile', '0.9031';
};

on 'test' => sub {
  requires 'Test::More', '>= 0.96, < 2.0';
};

on 'develop' => sub {
  recommends 'Devel::NYTProf';
};

著者プロフィール

中川勝樹(なかがわまさき)

1980年北海道生まれ。

株式会社ディー・エヌ・エー,プラットフォームシステム部所属。テストエンジニアとしてモバゲープラットフォームのテスト周り全般を担当。PerlやRubyによる自動テストの整備が主な業務。

「YAPC::Asia」や「Yokohama.pm」でスピーカーをするなど,Perl関連のコミュニティに積極的に参加している。

URL:http://ikasama.hateblo.jp/
Twitter:@ikasam_a

コメント

コメントの記入