Reputation: 37095
I build my project with dotnet build
, targeting netcoreapp3.1
.
The problem is that the assemblies contain the full path to the source-files:
/home/runner/my-app/App.fs
This means that the hash of the assemblies depends on the directory where the code was built. I want it to only depend on the hash of the source-files and the .NET SDK itself.
Is there a way to make dotnet build
use relative paths like this?
./my-app/App.fs
Upvotes: 12
Views: 2644
Reputation: 2180
I can find no reason not to prefer either
<DeterministicSourcePaths>true</DeterministicSourcePaths>
where the SDK supports it, or
<PathMap>$(MSBuildThisFileDirectory)=./</PathMap>
over
<PathMap>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)'))=./</PathMap>
However, there may be reason not to use MSBuildThisFileDirectory
at all and this is not explained or demonstrated in the documentation.
When used in Directory.Build.props
the MSBuildThisFileDirectory
property points to the directory of Directory.Build.props
, not the project it applies to. This makes
<PathMap>$(MSBuildThisFileDirectory)=./</PathMap>
behave semantically the same whether used in Directory.Build.props
in a directory above (below) a .csproj
file but possibly not in the desired way. In comparison the MSBuildProjectDirectory
property always points to the .csproj
directory.
Suppose a tree like
foo/
├── foo.sln
├── Directory.Build.props
├── FooMain/
│ ├── FooMain.csproj
│ └── src/
│ └── Foo.cs
└── FooTest/
├── FooTest.csproj
└── src/
└── Foo.cs
This table shows how different values for PathMap
set in different places affect the outcome of throwing an exception from FooMain/src/Foo.cs
; in particular, it shows that only MSBuildProjectDirectory
is independent of its placement:
PathMap value |
Where | Sample stack trace path |
---|---|---|
$(MSBuildThisFileDirectory)=./ |
Directory.Build.props |
./FooMain/src/Foo.cs:line 42 |
$(MSBuildThisFileDirectory)=./ |
*.csproj |
./src/Foo.cs:line 42 |
$(MSBuildProjectDirectory)=./ |
Directory.Build.props |
./src/Foo.cs:line 42 |
$(MSBuildProjectDirectory)=./ |
*.csproj |
./src/Foo.cs:line 42 |
$(MSBuildProjectDirectory)=./$(MSBuildProjectName)/ |
Directory.Build.props |
./FooMain/src/Foo.cs:line 42 |
$(MSBuildProjectDirectory)=./$(MSBuildProjectName)/ |
*.csproj |
./FooMain/src/Foo.cs:line 42 |
Instead of using PathMap
directly, supported SDKs contemporary with the recently released .NET 7 offer the DeterministicSourcePaths
option. When configured with
<DeterministicSourcePaths>true</DeterministicSourcePaths>
it behaves with the same consistency as
<PathMap>$(MSBuildProjectDirectory)=./$(MSBuildProjectName)/</PathMap>
but the sample stack trace path becomes /_/FooMain/src/Foo.cs:line 42
.
To work reliably, though DeterministicSourcePaths
also requires adding
<ItemGroup>
<SourceRoot Include="$(MSBuildThisFileDirectory)/"/>
</ItemGroup>
to the root Directory.Build.props
.
Whichever option you use, consider that while isolating the stack trace paths is certainly necessary for build reproducibility (despite not being mentioned in the DotNet.ReproducibleBuilds
package as of version 1.1.1) there may be tools that expect to be able to read the absolute path from the stack traces. In particular, it may be practically infeasible to enable deterministic paths for test projects.
Upvotes: 5
Reputation: 5381
You can configure a release build with less information or you can override PathMap value to override it.
<PropertyGroup Label="Override Stack trace file locations">
<PathMap>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)'))=./</PathMap>
</PropertyGroup>
The following Directory.Build.props
in the root of the project should work:
<Project>
<PropertyGroup>
<Deterministic>true</Deterministic>
<DeterministicSourcePaths>true</DeterministicSourcePaths>
<PathMap>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)'))=./</PathMap>
</PropertyGroup>
</Project>
Upvotes: 16
Reputation: 52798
C# compiler (csc) has a compiler switch -deterministic
F# compiler (fsc) appears to have a switch --deterministic+
From looking at the DotNet SDK repo it appears there are 2 properties for project files:
<Deterministic>true</Deterministic>
<DeterministicSourcePaths>true</DeterministicSourcePaths>
You might not need both of these.
Upvotes: 6