最近 FAKE でビルドスクリプトを書いています。その際にコンパイラーによってバージョン情報の扱いが違うらしいことに気が付いたので,ここにまとめます。
.NET Framework のアセンブリーには 3 つのバージョン情報があり,属性により指定します。
バージョン | 属性 |
---|---|
アセンブリバージョン | AssemblyVersionAttribute |
Win32 ファイルバージョン | AssemblyFileVersionAttribute |
製品バージョン | AssemblyInformationalVersionAttribute |
ファイルバージョンは FileVersionInfo.ProductVersion で,製品バージョンは FileVersionInfo.ProductVersion でそれぞれ取得できます[A]。
さて, .NET Framework ではバージョン番号の形式は メジャー.マイナー[.ビルド[.リビジョン]] という決められた形式があります。しかしファイルバージョンや製品バージョンは厳密にはアセンブリバージョンでないようなテキストでも良いことになっています。そこで製品バージョン,つまり AssemblyInformationalVersionAttribute にアセンブリバージョン互換でない文字列,例えば "1.0-beta"
を与えたらどうなるでしょうか。
結果から言うと,コンパイラーごとに挙動が異なる模様です。 Windows の C# コンパイラー (csc), F# コンパイラー (fsc), Linux 上での mono[B] の C# コンパイラー (mcs),コミュニティ版 F# コンパイラー (fsharpc)[C] の結果をまとめます。
ケース | バージョン | Windows | Linux | ||
---|---|---|---|---|---|
csc | fsc | mcs | fsharpc | ||
|
|||||
互換値 | ファイル | AFV | AFV | AV | null |
製品 | AIV | AIV | AFV | null | |
非互換値 | ファイル | AFV | AV | AV | null |
製品 | AIV | AV | AFV | null |
csc が常に正しい結果を返し, fsc はアセンブリーバージョン非互換値を指定すると AssemblyFileVersion を製品バージョンとして使用し, mcs はファイルバージョンに AssemblyVersion で製品バージョンに AssemblyFileVersion を使い, fsharpi は常に無視されます。なお,どのコンパイラーでもアセンブリー中の属性は 3 属性とも正常に記録されている模様です[D]。
もともと行っていたのがビルドしたアセンブリーの情報から NuGet パッケージのバージョンを決定するということでした。 NuGet のバージョンは 1.0-beta のようなハイフン区切りのバージョンをプレリリース版としてみなすので, AssemblyVersion だとそのような指定ができないのです。 FAKE スクリプトはバージョンを明示的に指定しないと 0.1 になってしまいます。これを回避するためにアセンブリーからバージョンを取得するということをしようとしていたのですが…。おそらく nuspec に正しいバージョンを書いておいて,それをマニュアルで読み込んで指定するということになりそうです。面倒くさいですね。
[2013-08-10 12:30 追記] よく考えたら,製品バージョンをアセンブリーから取得するのが目的なので,ファイルにバージョンが正常に書き込まれていなくても,アセンブリー自体には属性が含まれているのだから, FileVersionInfo を使わずに Assembly からリフレクションでバージョン情報を取得すれば良いのでした。