Introduction
同一ソースから常に同じバイナリが生成できれば、ある 2 つのリビジョンで生成されたバイナリまたはその集合を比較することで、差分を把握することができる。
これを利用してパッチを作ることができるのではと考えたのだが…
この手の質問は Microsoft の Japan Developer Support Core チームによく問い合わせが来るそうで。
こちらのブログでは C# と MSVC での成果物について記載している。
How to do?
C# の場合
*.csproj
に <Deterministic>false</Deterministic>
を追加することで、生成されるバイナリに埋め込まれるタイムスタンプが変化するようになる。
つまり、C# の場合、デフォルトで生成されるバイナリが同一になっている。
少なくとも、 .NET Framework 4.8 、 .NET 8.0 において、デフォルトで Deterministic
が true
になっているいることを確認した。
1 | <Project Sdk="Microsoft.NET.Sdk"> |
dumpbin
でバイナリのヘッダーを確認出来る。
1 | dotnet build -c Release |
ここで <Deterministic>false</Deterministic>
を追加してみる。
1 | $ "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\dumpbin.exe" /headers net8.0\Test.dll | findstr "time date stamp" |
タイムスタンプが変化した。
注意しなくてはいけないのは、obj
内のオブジェクトファイルにタイムスタンプが埋め込まれるのか、ソースに変更せずにビルドすると、タイムスタンプが変化しない。
バイナリを生成する前は obj
を削除する必要がある。
msbuild.exe
を使えば、引数で制御もできる。
1 | $ "C:\Program Files\Microsoft Visual Studio\2022\Community\Msbuild\Current\Bin\MSBuild.exe" -t:clean,build -p:Configuration=Release -p:deterministic=false |
C++ の場合
上記ブログにもあったように、deterministic
は非対応の模様。
1 | $ "C:\Program Files\Microsoft Visual Studio\2022\Community\Msbuild\Current\Bin\MSBuild.exe" -t:clean,build -p:Configuration=Release -p:deterministic=true |
ただし、正式な文書はないが別のオプションがある。
ビルドオプションではなく、リンカーオプションに /brepro
を付与する。
オプションの前後でヘッダーが変化したことが確認出来る。
1 | $ "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\dumpbin.exe" /headers bin\Win32\Release\Demo.exe | findstr "time date stamp" |
またはコマンドラインを使ってリンカーオプションを書き換えてもいい。
まず、下記のような *.props
ファイルを用意する。
1 |
|
最後に、msbuild.exe
に先のファイルを 絶対パス で指定する。
1 | $ "C:\Program Files\Microsoft Visual Studio\2022\Community\Msbuild\Current\Bin\MSBuild.exe" -t:clean,build -p:Configuration=Release /p:ForceImportBeforeCppTargets="F:\Demo\profile.props" |
上手くいった…が、非公式なオプションであることが気になる。
事実、コミュニティでもこのオプションを文書化する要請が出ているが…芳しくない…
また、副作用としてビルド時間が延びるとある。