Perlbrew で同じバージョンの Perl を別名で複数インストールする方法
Perl のバージョン管理ツール Perlbrew で、既にインストールしている Perl のバージョンを別名で新規にインストールしたい場合、--as
オプションを使うことで別名を付けられる。 (いつもわからなくなって id:aereal 氏に教えてもらってばかりいるのでいい加減書き残しておく。)
perlbrew install perl-5.8.8 --as perl-hoge
perlbrew --help
すればすぐ下のような情報が出てくるんだけど、何故かいつも --help
を見ずにぐぐっていい情報が出てこなくて悩む、みたいなことをしてる。
--as Install the given version of perl by a name. ex. C<perlbrew install perl-5.6.2 --as legacy-perl>
Perl においてサブルーチンがどのパッケージで定義されているのかを調べる方法
Perl で、とあるパッケージの中で使用できるサブルーチン (あるいはメソッド、関数、CODE ref) がどこで定義されているのかわからないということがたまにあります。 use を使って別のパッケージのサブルーチンをインポートした場合などがその最たる例でしょう。
Devel::Sub::Which
パッケージを使用してサブルーチンの定義場所を調べる
CPAN モジュールの Devel::Sub::Which を使用すると、指定したサブルーチンが定義されたパッケージがわかります。
use Devel::Sub::Which qw( which ); # AAA::BBB::CCC パッケージで使用できる createXXX というサブルーチンがどこで定義されているのか調べる warn which( 'AAA::BBB::CCC', 'createXXX' ); # CODE ref が定義されたパッケージも調べることができる my $codeXXX = sub { }; warn which( $codeXXX );
便利!
Kyoto.pm Tech Talks 02 で WebSocket のことを話しました
2012 年 8 月 18 日に開催された Kyoto.pm Tech Talks 02 で WebSocket のことを LT してきました。
発表資料
参考
- WebSocket プロトコルの詳細 : RFC 6455 - The WebSocket Protocol
- WebSocket API : 10.3 Web sockets — HTML Standard
- Takeshi Yoshino - Google+ - The WebSocket Protocol (RFC 6455) の歴史 WebSocket…
Plack::Middleware::WebSocket
Plack で WebSocket プロトコルを扱うための Middleware を motemen さんが 2 年ほど前に書かれていた のですが、それから WebSocket プロトコルの仕様も色々変わっていてそのままだと使えなかったので、4 月ごろに RFC 6455 に適合するように書き換えました。
今回の発表では、これを使ったデモも行いました。 急いで作ったのであまり綺麗なコードじゃないですが、下記リポジトリ (20120818-Kyoto.pm-2/master ブランチ) に置いてありますので、興味があれば実行してみてください。
下記コマンドで clone できます。
$ git clone -b 20120818-Kyoto.pm-2/master git://github.com/nobuoka/presentation.git
今は Plack::Middleware::WebSocket の中に、WebSocket プロトコルのパース処理なども書いているのですが、発表後に 「Protocol::WebSocket って CPAN モジュールがあるよ」 って motemen さんに教えてもらって、「確かに Plack::Middleware::WebSocket にパースとかの細かい処理を書くのは微妙だしそれを使って書き直した方が良いかなー」 と思ったりしました。
evernote-sdk-perl で Thrift::TException が発生する原因
Evernote Cloud API を使用するためには Evernote が提供するライブラリを使用する必要があります。 (Evernote Cloud API の詳細については 公式ドキュメント をご覧ください。) Perl 用のライブラリは evernote-sdk-perl です。 内部的には Thrift が使われているものの、それなりにラッピングされているので、Thrift であることをほとんど意識せずに使うことができます。
それはいいのですが、HTTP 通信周りでエラーが発生した場合には原因がなんであれ Thrift::TException が送出されてしまうため原因の特定が困難である、という問題があります。 今日もそれではまってしまったので、Thrift::TException が発生する原因としてよく遭遇しそうなものを 2 つあげておきます。
その 1 : LWP::Protocol::https モジュールがインストールされていない
Thrift モジュールの内部では LWP::UserAgent モジュールが使われています。 もし、LWP::UserAgent モジュールがインストールされていない状態で evernote-sdk-perl ライブラリを使用すると、「LWP::UserAgent がインストールされていない」 というようなエラーが出るので、LWP::UserAgetnt をインストールすればよいということがわかります。
で、cpanm などで LWP::UserAgent モジュールをインストールすると思うのですが、そのとき普通は LWP::Protocol::https モジュールはインストールされません。 しかし、Evernote との通信には HTTPS が使われるので、LWP::Protocol::https モジュールも必要となります。
LWP::Protocol::https モジュールがインストールされていないと、以下のようなオブジェクトが例外として送出されます。 わかりにくいですね。
bless( { 'code' => 0, 'message' => 'Missing version identifier' }, 'Thrift::TException' )
その 2 : タイムアウトの発生
EDAMUserStore::UserStore オブジェクトを得るためには以下のようなコードを書くと思います。
my $evernote_host = 'sandbox.evernote.com'; my $user_store_url = 'https://' . $evernote_host . '/edam/user'; my $user_store_client = Thrift::HttpClient->new( $user_store_url ); my $user_store_prot = Thrift::BinaryProtocol->new( $user_store_client ); my $user_store = EDAMUserStore::UserStoreClient->new( $user_store_prot, $user_store_prot );
このとき、Thrift 内部で行われる HTTP 通信のタイムアウト時間は、デフォルトで 100 ms となっています。 (Thrift::HttpClient の $self->{sendTimeout} の値。 Thrift::HttpClient#flush メソッド内で LWP::UserAgent->new に渡される。) 100 ms というタイムアウト時間だとかなり短いですので、環境によってはタイムアウトばかりしてしまいます。 また、タイムアウトするときもあればタイムアウトしないときもある、というような現象も起こりえます。
タイムアウト時にも、上で書いたのと同じ Thrift::TException 例外が送出されます。 これも原因を見つけるのが困難なエラーのひとつだと思います。
このエラーを避けるためには、以下のようにそれなりに長いタイムアウト時間を設定すれば良いでしょう。 setSendTimeout で設定されたタイムアウト時間は、上で書いたように LWP::UserAgent->new に渡されて使用されます。 setRecvTimeout で設定されたタイムアウト時間は、現在のところ使用されている様子はありませんが、念のため設定しておくと良いかと思います。
my $evernote_host = 'sandbox.evernote.com'; my $user_store_url = 'https://' . $evernote_host . '/edam/user'; my $user_store_client = Thrift::HttpClient->new( $user_store_url ); # default timeout value may be too short $user_store_client->setSendTimeout( 10000 ); $user_store_client->setRecvTimeout( 10000 ); my $user_store_prot = Thrift::BinaryProtocol->new( $user_store_client ); my $user_store = EDAMUserStore::UserStoreClient->new( $user_store_prot, $user_store_prot );
その他の原因
基本的にはネットワーク周りに問題がある場合に、Thrift::TException が発生するのかなーと思います。 もうちょっとわかりやすい例外が送出されればうれしいのですけどねぇ。
perlbrew を使って Ubuntu 12.04 に perl 環境を構築する
Ubuntu 12.04 に perl 環境を構築しようと思って作業していたのですが、perlbrew を使って perl のインストールをしようとしたところ以下のようなエラーが発生してビルドに失敗してしまいました。
(略) <math.h> found. Checking to see if your libm supports _LIB_VERSION... No, it does not (probably harmless) (略) cc -fstack-protector -L/usr/local/lib -o miniperl \ gv.o toke.o perly.o pad.o regcomp.o dump.o util.o mg.o reentr.o mro.o keywords.o hv.o av.o run.o pp_hot.o sv.o pp.o scope.o pp_ctl.o pp_sys.o doop.o doio.o regexec.o utf8.o taint.o deb.o universal.o globals.o perlio.o perlapi.o numeric.o mathoms.o locale.o pp_pack.o pp_sort.o \ miniperlmain.o opmini.o perlmini.o~ pp.o: In function `Perl_pp_pow': pp.c:(.text+0x364e): undefined reference to `pow' pp.o: In function `Perl_pp_modulo': pp.c:(.text+0x4415): undefined reference to `floor' pp.c:(.text+0x45af): undefined reference to `floor' (略) collect2: ld はステータス 1 で終了しました make: *** [miniperl] エラー 1 cc -fstack-protector -L/usr/local/lib -o miniperl \ gv.o toke.o perly.o pad.o regcomp.o dump.o util.o mg.o reentr.o mro.o keywords.o hv.o av.o run.o pp_hot.o sv.o pp.o scope.o pp_ctl.o pp_sys.o doop.o doio.o regexec.o utf8.o taint.o deb.o universal.o globals.o perlio.o perlapi.o numeric.o mathoms.o locale.o pp_pack.o pp_sort.o \ miniperlmain.o opmini.o perlmini.o~ pp.o: In function `Perl_pp_pow': pp.c:(.text+0x364e): undefined reference to `pow' pp.o: In function `Perl_pp_modulo': pp.c:(.text+0x4415): undefined reference to `floor' (略) collect2: ld はステータス 1 で終了しました make: *** [miniperl] エラー 1
どうも libm のリンクがうまくいってない感じがするなー、ということでそっち方向で検索をかけてみたもののあまりいい情報が得られず途方に暮れていたのが先週の話。 さっきなんとなく 「perlbrew Ubuntu」 で検索してみたら色々情報がありました。
- Ubuntu 11.04 (Natty) で perl がインストール出来ない場合の理由と対策 - punitan (a.k.a. punytan) のメモ
- PerlとRubyの開発環境構築メモ(ubuntu 11.10) - jitsu102の日記
- perlbrew on Ubuntu 11.10 - masa-woの日記
Ubuntu Nasty から libm などの位置が変わったが perlbrew の Configure がデフォルトで見に行くパスにそれが含まれていない、ってことが原因のようです。 なので、perlbrew コマンドのオプションとして、libm が入っているパスを指定すれば良い、と。 うちの環境では /usr/lib/x86_64-linux-gnu に libm が入っているので、以下のようにパスを指定してやることで無事ビルドできました。
$ perlbrew install perl-5.14.2 -Dplibpth=/usr/lib/x86_64-linux-gnu
ライブラリの位置の確認方法など、詳細は上に挙げたページをご覧ください。
perl 環境構築の流れ (メモ)
Ubuntu 12.04 に perl 環境を構築する時の流れをメモしておきます。 まずは perl のビルドに必要なパッケージを apt-get でインストール。
$ sudo apt-get build-dep perl
続いて perlbrew をインストール。 詳細は http://perlbrew.pl/。
$ curl -kL http://install.perlbrew.pl | bash
インストール後 ~/.bashrc に以下の 2 行を追加。 この後で端末を新しく開く (とか source コマンドで読み込みなおすとかする) と perlbrew を使えるようになっているはずです。
PATH=$HOME/perl5/perlbrew/bin:$PATH [[ -s "$HOME/perl5/perlbrew/etc/bashrc" ]] && source "$HOME/perl5/perlbrew/etc/bashrc"
あとは perlbrew を使って cpanm をインストールしたり perl をインストールしたり。
# cpanm のインストール $ perlbrew install-cpanm # インストール可能なバージョン一覧を表示 $ perlbrew available # インストール (上で書いたようにライブラリパスをオプションで指定; 以下は 64-bit の場合) $ perlbrew install perl-5.14.2 -Dplibpth=/usr/lib/x86_64-linux-gnu # 32-bit の場合 /usr/lib/i386-linux-gnu