lib - モジュールを色んな場所から読み込む

  1. モジュールを読み込む方法

  2. Perlではモジュールの読み込みにuse関数や、require関数を使います。

    例えば、

    use Time::Piece;
    my $time = localtime();
    print $time->ymd;
    と書きます。

    単に、use関数の引数としてモジュール名を指定しているだけです。では、Perlはどうやって実際のモジュールファイル(拡張子が.pmのファイル)を見つけるのでしょうか?
    それには@INCという特殊変数にからくりが有ります。

  3. 特殊変数「@INC」とは?

  4. @INCは、Perl実行時点で用意されている特殊変数です。@INCの中身を見るために、下記の様なワンライナーを実行してみます。

    $ perl -e 'print $i++ . ":" . "$_\n" foreach @INC'
    0:/usr/local/lib/perl5/site_perl/5.12.1/i686-linux
    1:/usr/local/lib/perl5/site_perl/5.12.1
    2:/usr/local/lib/perl5/5.12.1/i686-linux
    3:/usr/local/lib/perl5/5.12.1
    4:.
    この結果はUbuntu上で独自にビルドしたPerlの時の結果ですが、他の環境でもバージョン番号(5.12.1)や、アーキテクチャ名(i686-linux)が異なるだけで構成は同じです。

    では、先ほど使ったTime::Pieceはどこに有るのでしょうか?
    検索すると、/usr/local/lib/perl5/5.12.1/i686-linux/Time/Piece.pmが見つかりました。

    Perlは指定されたモジュールの「::」をファイルパスの区切り文字とみなして、@INCのパス上でファイルを検索します。Linuxのファイルパスの区切り文字はスラッシュなので、「/usr/local/lib/perl5/5.12.1/i686-linux/」と、「Time/Piece.pm」を連結して検索するわけです。

    検索は、@INCに最初に格納されているパスから順に行われ、検索しているファイルが見つかった段階で読み込みは完了します。今回の例で言えば、

    Step1:/usr/local/lib/perl5/site_perl/5.12.1/i686-linux/Time/Piece.pm → 存在しない
    Step2:/usr/local/lib/perl5/site_perl/5.12.1/Time/Piece.pm → 存在しない
    Step3:/usr/local/lib/perl5/5.12.1/i686-linux/Time/Piece.pm → 存在する!読み込み!
    
    となり、ここで検索は打ち切られます。
    つまり、/usr/local/lib/perl5/5.12.1/Time/Piece.pmや、./Time/Piece.pmは検索されません。

    これがPerlにおけるモジュールの読み込みパスの考え方の基本です。

    なお、@INCの最後に出てくるピリオドは、実行しているスクリプトファイルのカレントディレクトリを表します。つまり、スクリプトが置かれているディレクトリもモジュールの検索対象になります。

  5. libプラグマ

  6. @INCの内容はPerlが実行される時点で決まっていますが、スクリプトの中でも変更することができます。

    特に独自モジュールや、アプリケーション固有のモジュールを別のディレクトリにインストールしたい場合は、初期設定のままではデフォルトで@INCに設定されているパス以外ではモジュールを検索することができません。

    例えば、こんなフォルダ構成が有ったとします。

    Foo
    ├── bin
    └── lib
    binディレクトリ配下に実行スクリプトが入っていますが、必要なモジュールはlibディレクトリ配下に入っています。

    こんな時はlibプラグマを使って@INCを拡張します。

    use FindBin;
    use lib "$FindBin::Bin/../lib";

    FindBinモジュールは、実行しているスクリプト自身を格納しているディレクトリを取得する標準モジュールです。取得した結果は$FindBinで参照することができます。

    ../で一つ上のディレクトリを参照するので、libプラグマの引数に"$FindBin::Bin/../lib"を指定することで、binディレクトリと同じ階層にあるlibディレクトリを参照できるようになるわけです。

  7. libプラグマを使わずに@INCを拡張する

  8. libプラグマ以外にも@INCを拡張する方法が有ります。

    • PERL5LIB環境変数をセットする
    • @INCの内容は環境変数のPERL5LIBに予めセットされています。そのため、Perl実行前にPERL5LIBにパスを追加すれば@INCにもパスが追加されます。

    • BEGIN句の中で@INCを自前で拡張する
    • 実はlibプラグマがやっている事は、以下のコードとほぼ等価です。

      BEGIN { unshift(@INC, LIST) }

      libプラグマの方が少し親切で、Perlのバージョンナンバーやアーキテクチャ名付きのディレクトリまで検索してくれます。詳しくはヘルプを見て下さい。

    • コマンドラインオプションの-I引数を指定する
    • コマンドラインでPerlの実行オプションとして-Iオプションにパスを指定することでも@INCを拡張できます。しかし、起動時の実行指定なので、かなり使い勝手は悪いと思われます。

    • local::libを使う
    • 標準モジュールではありませんが、local::libは任意のディレクトリへPerlのモジュールをインストールし、利用するためのとても便利なモジュールです。特にレンタルサーバや、同一サーバ上で複数のアプリケーションを実行する様な環境では環境構築のやり易さを飛躍的に向上させてくれます。

libプラグマを使えば、モジュールを好きな場所に配置しても読み込む事ができます。特に自作モジュールを用意する場合は必須のpragmaと言えるでしょう。


→Perl To The Peopleのインデックスページへ戻る

トラックバックURL

このエントリーのトラックバックURL:
http://ash.roova.jp/mt/mt-tb.cgi/208

コメントする