docs/compilers/Deterministic Inputs.md
The C# and VB compilers are fully deterministic when the /deterministic option is specified (this is the default in the .NET SDK). This means that the "same inputs" will cause the compilers to produce the "same outputs" byte for byte.
The following are considered inputs to the compiler for the purpose of determinism:
@ response files/preferreduilang is not specified (for the language in which diagnostics and exception messages are produced)./codepage is not specified and any of the input source files do not have BOM and are not UTF-8 encoded./lib or /recurse)double arithmetic performed for constant-folding may use excess precision on some platforms./embed or /debug:embedded is used).%LIBPATH%, as it can affect reference discovery if not fully qualified and how the runtime handles analyzer / generator dependency loading./pathmap can be used to normalize this between compiles of the same code in different root directories.At the moment the compiler also depends on the time of day and random numbers for GUIDs, so it is not deterministic unless you specify /deterministic.
When investigating determinism issues where the same code produces different outputs, you can use several techniques to identify the cause:
Build with /p:Features="debug-determinism" to generate a .key file that documents all inputs to the compiler:
dotnet build /p:Features="debug-determinism"
This creates an additional output file (e.g., MyAssembly.dll.key) in the output directory (typically in the obj directory for intermediate builds). The key file is a JSON document containing:
Compare the .key files from two supposedly identical builds to identify which inputs differ:
# Unix/Linux/Mac
diff build1/MyAssembly.dll.key build2/MyAssembly.dll.key
# Windows (using fc)
fc build1\MyAssembly.dll.key build2\MyAssembly.dll.key
Note: If the .key files are identical but the output assemblies differ, this indicates a compiler determinism bug. Please report such cases to the Roslyn team with a reproduction so the issue can be investigated.
Install the mdv (MetaData Viewer) tool from the dotnet/metadata-tools repository:
dotnet tool install mdv -g --prerelease --add-source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json
Generate metadata dumps for your assemblies and compare them:
# Generate metadata output for each DLL
mdv MyAssembly1.dll > assembly1.txt
mdv MyAssembly2.dll > assembly2.txt
# Compare the outputs
diff assembly1.txt assembly2.txt
The metadata dump shows detailed information about types, methods, fields, attributes, and other metadata in the assembly. Differences in the metadata can help identify what changed between builds.
If your assembly contains embedded resources, verify they are identical. The recommended approach is to use ILSpy, which has an easy "Save" button to export resources from the DLL for comparison. Other tools like dnSpy or ildasm can also be used to extract and inspect embedded resources.
Example using ildasm to disassemble and extract embedded .res files:
# Disassemble and generate .res files
ildasm /out=assembly1.il MyAssembly1.dll
ildasm /out=assembly2.il MyAssembly2.dll
# Compare the generated .res files
diff assembly1.res assembly2.res
As a last resort, perform a hex dump comparison of the actual DLL files:
# Unix/Linux/Mac - using xxd or hexdump
xxd MyAssembly1.dll > assembly1.hex
xxd MyAssembly2.dll > assembly2.hex
diff assembly1.hex assembly2.hex
# Windows - using fc with /b flag for binary comparison
fc /b MyAssembly1.dll MyAssembly2.dll
# Or using Format-Hex in PowerShell
Format-Hex MyAssembly1.dll | Out-File assembly1.hex
Format-Hex MyAssembly2.dll | Out-File assembly2.hex
Compare-Object (Get-Content assembly1.hex) (Get-Content assembly2.hex)
A hex diff shows the exact bytes that differ, which can help identify non-deterministic data like timestamps, GUIDs, or other embedded values.
When debugging, look for these common issues:
/deterministic flag: Ensure /deterministic is enabled/pathmap to normalize file paths.key files%LIBPATH% can affect output