※このエントリは Perl Advent Calendar 2016 の15日目のエントリです。
どーも、わいとんです。
早速ですが、みなさんはPerlのライブラリパスをどんな風に指定していますか?
そもそもスクリプト内で指定してない?絶対パスで直接指定?それともFindBinを使ってる?
今回はわいとんがよくやっているFile::SpecとFile::Basenameを使ったライブラリパス指定の方法を紹介します。
例
以下のようなプロジェクトがあったとします。
1 | ./ |
cpanfileは以下のような内容です。
1 | requires 'perl', '5.008001'; |
これをcpm installなんてやった場合、local/lib/perl5配下に依存ライブラリがどんどん入ってきます。(cpmについてはskajiさんのエントリを参照してください。)
で、bin/run.plからMyProj::Client->new(...);なんてやりたいなぁって思った時に、以下のように書くと思います。
1 | use strict; |
でもって、実行時に
1 | perl -Ilib -Ilocal/lib/perl5 ./bin/run.pl |
なぁんて書くと思います。別に悪くないけど、面倒ですよね。
ちょっと賢くFindBinを使う
で、use libとFindBinを組み合わせて、以下のようにしたりしますよね。(しますよね?したことありません?)
1 | use strict; |
実行時にはこんな感じで。
1 | perl ./bin/run.pl |
楽になりましたね!でもでもでもでもチョッッット待ってwww それってカレントディレクトリがプロジェクトフォルダの直下にないと動かなくないっすか?(動かないですよね?)あとそれWindowsじゃ動かなくないですか?(Windowsなんか使わない?あ、すみませんww)
File::SpecとFile::BasenameとFILEを使う
まあそこで出てくるのがFile::SpecとFile::Basenameなんですね。
超雑に解説すると、File::SpecってのはOS間で異なるパス表現(¥とか/とかそういうやつ)を吸収してくれるライブラリで、File::Basenameてのは、食わせた文字列をパス表現文字列とみなしてざっくりパーズし、フォルダまでのパスとかファイル名とかをよしなに引っ張ってきてくれるライブラリです。
あと__FILE__っていうのは実は組みこみ関数でして、__FILE__が記述されているファイルのパス(つまり実行されるスクリプトのパスそのもの)を返してくれます。
んで、こいつらを使ってさっきのbin/run.plを書き換えると、こんな感じになります。
1 | use strict; |
若干冗長ですが、実行時は常にスクリプトを正しく指定するだけでOK。
1 | perl ./bin/run.pl |
例えばlib/MyProj/からでも
1 | perl ../../bin/run.pl |
と実行できます。
少し補足。 File::Spec->catdir(...)は、引数にリストを食わせることで、実行環境に応じたパス文字列を仕立て上げてくれます。dirname(...)は与えられたパス文字列のディレクトリパスを返してくれます。
これらを組み合わせて、どの環境でどのパスから実行されても、読み取りたいライブラリパスがずれずに利用可能となる、と。こういうわけです。
何より、File::SpecもFile::Basenameもコアモジュールなので、Perl5が入っていればまず使えないってことはないんじゃないでしょうか。→ツッコミ参照ください
まとめ
- ライブラリパスをがっちりつかんで離さないスクリプトを書くための方法を紹介しました。
File::SpecとFile::Basenameを使うぞって言いながら__FILE__も使いました。- きっとWindowsの人もニッコリ。
cpmかわいいよcpm
ツッコミもらいました
@ytnobody local/lib/perl5にFile::Specが入っていてuse libの段階ではFile::Spec使えないことがありました…
— Shoichi Kaji (@shoichikaji) December 16, 2016
@ytnobody ちょっと前のPath::TinyがFile::Spec 3.40をrequireしていたので結構起きてました。https://t.co/C7rGuQD215
— Shoichi Kaji (@shoichikaji) December 16, 2016
だそうです。。。skajiさん、ありがとうございますm(_ _)m