モジュールのバージョン番号について考えてみました(1)

前提とするversion.pmのバージョン(とXSか否か)も書いておいてほしい。
とのはてぶコメント、ありがとうございました。 エントリー中のversion.pmは全て version.pm 0.6701 のXS版のことです。


Perlモジュールのバージョン番号をどう付けるかは統一されていないのですが、主に0.01,0.02,...,1.11,1.12などと付けられているものが多いようです。
ところで話は変わって、世の中にはバージョン管理ツールというものがあります。CVSSubversionでは$Revision$というキーワードをファイルに書いておくと、コミットするたびに自動で新しいリビジョン番号で置き換わります。それを利用してモジュールのバージョンを自動的に設定する方法がperlfaq7に載っていました(何故か現在では記述が無くなっています)。

$VERSION = do{my@r=q$Revision: 1.28 $=~/\d+/g;sprintf '%d.'.'%02d'x$#r,@r};

(perlmodには $VERSION = sprintf "%d.%03d", q$Revision: 1.1 $ =~ /(\d+)/g; と書かれています。)
しかしこの方法だと困ったことが起きます。例えば今実際にTemplate::Stashで起きていることなのですが、2.102 より 2.86 の方が新しいと判定されてしまっています。参考:CPANのバージョン番号比較が変 - ヒルズで働く@robarioの技ログ
ここで「%02dだからダメなだけじゃね?%03dにすればいいんじゃね?」という話もあります。確かに%03dにすればこの問題は解消されますが、今度は小数点以下が4桁になったときに同じ問題が発生します。

この比較の問題は、先頭に「v」を付けてv-strings(バージョン文字列)にすることで回避できます。

# $VERSION = do{my@r=q$Revision: 2.102 $=~/\d+/g;sprintf 'v%d.'.'%02d'x$#r,@r}; # $VERSION = v2.102

$ perl -MCPAN::Version -e 'print CPAN::Version->vcmp("2.102", "2.86");'
-1
$ perl -MCPAN::Version -e 'print CPAN::Version->vcmp("v2.102", "v2.86");'
1

vを付けるだけで比較結果が逆転しているのが分かると思います。この辺りはperl v5.9.0からコアモジュールになったversion.pmに関係しており、version.pmでも同じ動きをします。


version.pmにおいて、2.86と2.102はそれぞれ以下のように間違った解釈をされてしまいます。

$ perl -Mversion -e 'print version->new(2.86)->normal'
v2.860.0

$ perl -Mversion -e 'print version->new(2.102)->normal'
v2.102.000

$ perl -Mversion -e 'print version->new(2.102) < version->new(2.86)'
1

これは、小数点以下が2桁である場合に3桁にするために「末尾に」0が付くからです。
これをv-stringsにすると以下のように正しく解釈されるようになります。

$ perl -Mversion -e 'print version->new(v2.86)->normal'
v2.86.0

$ perl -Mversion -e 'print version->new(v2.102)->normal'
v2.102.0

$ perl -Mversion -e 'print version->new(v2.102) < version->new(v2.86)'
$


小数点以下が4桁になった場合は以下のように解釈されます。

$ perl -Mversion -e 'print version->new(2.1024)->normal'
v2.102.400

$ perl -Mversion -e 'print version->new(2.999)->normal'
v2.999.0

$ perl -Mversion -e 'print version->new(2.1024) < version->new(2.999)'
1

これは、小数点以下を3桁毎に区切るため、4桁目がアルファバージョンとして解釈されているからです。
やはりこれもv-stringsにすると正しく解釈されるようになります。

$ perl -Mversion -e 'print version->new(v2.1024)->normal'
v2.1024.0

$ perl -Mversion -e 'print version->new(v2.999)->normal'
v2.999.0

$ perl -Mversion -e 'print version->new(v2.1024) < version->new(v2.999)'
$


まとめますと、

  • Numeric Versions(v-stringsではないバージョン番号 @see perldoc version)を使う場合は、小数点以下が2桁でもダメだし4桁でもダメ
  • v-stringsを使えば気にしなくて良い

ということになります。


まだ他にも気になることがありますが、長くなったのでそれは次のエントリで書こうと思います。さらに、実際にCVSSubversionを使った自動バージョン付けをモジュールに仕込むことに関して、自分なりの答えを書こうと思います。というか自分の中で最善な書き方がまだ決まっているわけではないのですが。。。