36

ビルド スクリプトを使用して、いくつかの C# プロジェクトをコンパイルしています。バイナリ出力は結果フォルダーにコピーされ、以前のバージョンのファイルが上書きされてから、subversion に追加/コミットされます。

ソースや環境にまったく変更がない場合でも、コンパイルのバイナリ出力が異なることに気付きました。これはどのように可能ですか?バイナリの結果は、同じ入力に対して正確に等しいはずではありませんか?

どこでも特別なタイムスタンプを意図的に使用しているわけではありませんが、コンパイラ (Microsoft、.NET 4.0 に含まれているもの) がタイムスタンプ自体を追加する可能性はありますか?

私が尋ねている理由は、出力を subversion にコミットしているためです。ビルド サーバーの動作方法により、チェックインされた変更が再構築をトリガーし、再度変更されたバイナリ ファイルがサークル内でチェックインされます。

4

4 に答える 4

33

別の更新:

2015 年以来、コンパイラ チームは、コンパイラ ツールチェーンから非決定論の原因を取り除く努力をしてきました。これにより、同一の入力が実際に同一の出力を生成します。詳細については、Roslyn github の「Concept-determinism」タグを参照してください。


更新:この質問は、2012 年 5 月の私のブログの主題でした。素晴らしい質問をありがとう!


これはどのように可能ですか?

とても簡単に。

バイナリの結果は、同じ入力に対して正確に等しいはずではありませんか?

絶対違う。その逆です。コンパイラを実行するたびに、異なる出力が得られるはずです。そうでなければ、再コンパイルしたことをどのように知ることができますか?

C# コンパイラは、コンパイルのたびに新しく生成された GUID をアセンブリに埋め込みます。これにより、2 つのコンパイルがまったく同じ結果を生成しないことが保証されます。

さらに、GUID がなくても、コンパイラは、2 つの「同一の」コンパイルが同じ結果を生成することを保証しません。

特に、メタデータ テーブルが読み込まれる順序は、ファイル システムの詳細に大きく依存します。C# コンパイラは、ファイルが与えられた順序でメタデータの生成を開始しますが、これはさまざまな要因によって微妙に変更される可能性があります。

ビルド サーバーの動作方法により、チェックインされた変更によってリビルドがトリガーされ、再度変更されたバイナリ ファイルが循環してチェックインされます。

私があなただったら、それを修正します。

于 2012-01-19T14:30:54.760 に答える
13

はい、コンパイラにはタイムスタンプが含まれています。さらに、場合によっては、コンパイラがアセンブリのバージョン番号を自動インクリメントします。バイナリ結果が同一であるという保証はどこにもありません。

(ソースが既に Subversion にある場合は、通常、そこにバイナリ ファイルを追加することは避けます。通常は、サードパーティ ライブラリのリリースのみを含めます。ただし、それはあなたが何をしているかによって異なります。 )

于 2012-01-19T14:16:27.430 に答える
2

私の知る限り、コンパイルごとに異なるのは MS バイナリだけです。20年ほど前は、そうではありませんでした。MS バイナリは、コンパイルのたびに同じでした (ソース コードが同じであると仮定します)。

于 2016-02-17T03:13:32.887 に答える