Question

I'm using a build script to compile several C# projects. The binary output is copied to a result folder, overwriting the previous version of the files, and then added/committed to subversion.

I noticed that the binary output of the compilation are different even when there was no change to the source or environment at all. How is this possible? Isn't the binary result supposed to be exactly equal for the same input?

I'm not intentionally using any kind of special timestamps anywhere, but does the compiler (Microsoft, the one included in .NET 4.0) possibly add timestamps itself?

The reason I'm asking is I'm committing the output to subversion, and due to the way our build server works the checked in changes trigger a rebuild, causing the once again modified binary files to be checked in in a circle.

Was it helpful?

Solution

ANOTHER UPDATE:

Since 2015 the compiler team has been making an effort to get sources of non-determinism out of the compiler toolchain, so that identical inputs really do produce identical outputs. See the "Concept-determinism" tag on the Roslyn github for more details.


UPDATE: This question was the subject of my blog in May 2012. Thanks for the great question!


How is this possible?

Very easily.

Isn't the binary result supposed to be exactly equal for the same input?

Absolutely not. The opposite is true. Every time you run the compiler you should get a different output. Otherwise how could you know that you'd recompiled?

The C# compiler embeds a freshly generated GUID in an assembly on every compilation, thereby guaranteeing that no two compilations produce exactly the same result.

Moreover -- even without the GUID, the compiler makes no guarantees whatsoever that two "identical" compilations will produce the same results.

In particular, the order in which the metadata tables are populated is highly dependent on details of the file system; the C# compiler starts generating metadata in the order in which the files are given to it, and that can be subtly changed by a variety of factors.

due to the way our build server works the checked in changes trigger a rebuild, causing the once again modified binary files to be checked in in a circle.

I'd fix that if I were you.

OTHER TIPS

Yes, the compiler includes a timestamp. Additionally, in some cases the compiler will auto-increment the assembly version number. I haven't seen any guarantee anywhere that the binary result is meant to be identical.

(Note that if the source is already in Subversion, I'd generally steer clear of also adding the binary files in there. I'd usually only include releases of third-party libraries. It depends on exactly what you're doing though.)

As mentioned by others, the compiler does generate a distinct build hence the different result. What you are looking for is the ability to create deterministic builds and now this is included as part of the roslyn compiler.

Roslyn command line options

/deterministic Produce a deterministic assembly (including module version GUID and timestamp)

Read more about this feature https://github.com/dotnet/roslyn/blob/master/docs/compilers/Deterministic%20Inputs.md

As far as I know, only MS binaries are different on every compile. 20 or so years ago, it wasn't like that. The MS binaries were the same after every compile (assuming the source code was the same).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top