よく自分でちょこっと使うツールやライブラリをC#で作ったりしますが、いつもビルドするときにバージョンを編集しないままずっと同じ、ということはよくあります。

まあ、1回作ってしばらく使って廃棄するようなものだったら気にする必要はないんですが、結構長い間使うものだったり、ちょくちょく修正や機能追加をするようなもの、ライブラリ的に使うようなものだと、何らか識別できるようにしておいた方が良いこともあります。また、自分で作っていて育っていく感覚も得られますので、ちゃんとバージョンを編集しておくのは悪いことじゃないと思います。

.net(C#)でのバージョン設定

バージョンは、プロジェクトのプロパティで設定するか、AssemblyInfo.csを直接編集して行います。

// アセンブリのバージョン情報は、以下の 4 つの値で構成されています:
//
//      Major Version
//      Minor Version
//      Build Number
//      Revision
//
// すべての値を指定するか、下のように '*' を使ってビルドおよびリビジョン番号を
// 既定値にすることができます:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

AssemblyInfo.csはこんな感じになっています。

ここに書いてあるとおり、AssemblyVerionについては”1.0.*”とかいう指定をしておけば、”1.0.5345.35759″のような形式でBuildとRevisionが自動で入るようになります。Buildに入っているのは、2000年1月1日からの経過日数、Revisionに入っているのは0時からの経過秒数、ということなので1日何回もビルドすると、BuildはそのままでRevisionが増えていくことになります。

“1.0.0.*”という指定も可能で、この場合は経過秒数だけが変わりますので、Major,Minor,Buildを変更しないまま、別の日の全く同じ時間にビルドすると同じ番号のものができることになります。

まあ、なんにしてもこれでは区別しづらいですよね。
しかも、肝心のMajor,Minorあたりは*が使えないのでどうしようもないです。

バージョンの付け方

この辺のことについてぐぐったりすると、バージョン番号をどうやってつけるかと言うことについて悩んでいる人がいたり、MajorやMinorをカウントアップする時はどうするだとか、色々考え方があります。

こう言うのにこだわり出すと、とりあえずVisualStudioで新規のプロジェクトを開いたのはいいけど、バージョンをどうするかで半日悩む……みたいなこともあったりします。まあ、こう言うのを色々考えるのも楽しいですけどね。

で、最近私が個人的にやってる付け方は、

  • Major……何か新しいコードを増やした時は1増やす。
  • Minor……連番でビルドするたびに+1、開発中のDebugビルドでも増やす。でもMajorを上げたら0にする。
  • Build……つかわない
  • Revision……つかわない

と言う方法です。
ちょっとしたツールでも最初からいきなり「ver 1.254」なんて言うことになります。
また作って使い、拡張して使い……していたら平気で「ver 32.0」みたいなことになります。

Majorについては、そもそも自分で作って使うぐらいのモノなので、世間的に言う「メジャーバージョンアップ」なんてしませんし、0とか1で始めたら変わることなんてないわけで……なので世の中的なMinorの部分をMajorとして使うわけです。
ルールとしては、何か新しいコードを追加したとき……機能とか表示を追加したときに1つ上げます。すでに存在しているコードがちゃんと動かなくて修正する時には上げません。

Minorについては、なにも考えずに+1していき、Majorを増やすタイミングで0にリセットします。作っては使い、変だったら修正して……みたいなことをやっていると、今使ってるやつが直したあとのやつなのかわかりにくいことがあるからです。

最近はこういう割り切ったルールにしているので、残念ですがバージョンについて色々妄想をすることがなくなってしまいました。

バージョンのカウントアップ

さて、バージョンの付け方を割り切ったものにしたのはいいのですが、これをやろうとするとVisualStudioはこんな便利にやってくれないですし、いちいちAssemblyInfo.csを書き換えるなんて言うのは絶対忘れますし、覚えていてもやる気になりませんね。

結局、AssemblyInfo.csに書いてあるバージョンが成果物に書き込まれるわけですから、ビルドされる前に書き換えておけばいいのです。

なんかどこか探せばそんなことをしてくれるツールとかありそうですけど、あえてC#で作ります。
要件は以下の通り。

  • 「ビルド前に実行するコマンドライン」で実行するコンソールアプリケーションを作る
  • 「$(ProjectDir)Properties\AssemblyInfo.cs」を渡せばバージョンのところを書き換えてくれるようにする
  • major,minor,build,revisionをどう書き換えるかを実行時引数で指定する
    • 指定した値にする(major=1とかminor=5とか)
    • 元の数値を指定した数分増やす(minorを+1するとか、buildを+30するとか)
    • 現在日付または時刻を指定したフォーマットで設定する(yyyyMMddとか、hhmmssとか)
      • (訂正)アセンブリのバージョンは、それぞれUInt16だったのでyyyyMMddだとオーバーフローします。
      • System.Versionがintだったので間違えました。
      • 65535を超えない指定が必要です。
  • AssemblyInfo.csを開いて、grepで対象となる部分を抽出。
  • そこからさらにバージョンの数字を取得して、実行時の指定通りに処理。
  • 対象を置換して保存。
  • 正常に処理できたらエラーコード0で終了、例外が出たらエラーコード0以外で終了。
    • 0以外だったら、ビルド前コマンド失敗としてビルドを中止してくれる。

こんな感じです。

AssemblyInfo.csで書き換えるのは下記の部分なのですが、

[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

これ、AssemblyVersionだけ指定してAssemblyFileVersionの行を消しておくと、AssemblyFileVersionは自動的にAssemblyVersionにしてくれますし、その逆もありです。
ちなみに、ファイルのプロパティにあるファイルバージョンや製品バージョンはAssemblyFileVersionの方が出ていますので、AssemblyVersionだけ書き換えてもどこからも見えません。書き換える際はどっちか消しておくか、両方とも書き換えるといいと思います。

あと、実装しておくとさらに便利な機能としては、

  • 変更前のバージョンと、変更後のバージョンをダイアログで確認できる
    • このビルドは今回このバージョンに書き換わりますよ、とか
  • そのダイアログでバージョンを変更できるし、変更しないようにもできる
    • 常にmajorは人手でカウントアップしますよ、とか
    • 今回はminorはインクリメントしませんよ、とか
    • バージョンそのものを変更しませんよ、とか
  • ダイアログでキャンセルしたらビルド前イベントを失敗にしてくれる
    • あ、しまった、修正忘れてるところがあった、とか
  • 実行時引数でこのダイアログを出すか出さないか指定できる
    • 特に気にせず設定のままで書き換わってくれてればいい、とか

とかしておくと融通が利いていいですね。

どんな風に作ったかの要点は次回に。

ビルド時にバージョンを更新する方法(実践編)