dotnet / dotnet/msbuild

MsBuild using last write time of symlinks instead of their targets to determine whether or not to rebuild

Open
#13,465 1 comment 0 reactions 0 assignees View on GitHub
internal-team-onboarding Priority:2 triaged
Dominant language
C#
Stars
5.5k
Forks
1.5k
Avg merge
1d 8h
Merged PRs (30d)
141

Description

### Issue Description

On non-Windows platforms, if one of the source files is a symlink, and the symlink target is modified, MsBuild doesn't recognize the change and doesn't rebuild the target.

### Steps to Reproduce

I reproduced this issue on MacOS, although I suspect that the problem is the same on all non-Windows platforms.

Shell code to reproduce from scratch (run in a new folder):
```sh
#!/bin/sh -e

dotnet new create console -lang:'C#'
mv Program.cs Program.txt
ln -s Program.txt Program.cs
# At this point Program.cs is a symlink to Program.txt, which is not directly part of the build
dotnet build -c:Debug
stat bin/Debug/net*/*.dll # To get the last modification time of the built DLL

sleep 2

touch Program.txt # "Update" the target
dotnet build -c:Debug
stat bin/Debug/net*/*.dll # Same last modification time -> hasn't been rebuilt

sleep 2

rm Program.cs
ln -s Program.txt Program.cs # "Update" the symlink
dotnet build -c:Debug
stat bin/Debug/net*/*.dll # Different last modification time -> has been rebuilt
```

### Expected Behavior

I would expect the assembly to be actually built the 1st and 2nd run.

### Actual Behavior

The actual output is something like this:

```
...

Restore complete (0.2s)
test net10.0 succeeded (3.7s) → bin/Debug/net10.0/test.dll

Build succeeded in 4.1s
16777236 156 ... "Mar 30 22:36:49 2026" 4096 16 0 bin/Debug/net10.0/test.dll
Restore complete (0.2s)
test net10.0 succeeded (0.1s) → bin/Debug/net10.0/test.dll

Build succeeded in 0.4s
16777236 156 ... "Mar 30 22:36:49 2026" 4096 16 0 bin/Debug/net10.0/test.dll
Restore complete (0.2s)
test net10.0 succeeded (0.1s) → bin/Debug/net10.0/test.dll

Build succeeded in 0.5s
16777236 163 ... "Mar 30 22:36:55 2026" 4096 16 0 bin/Debug/net10.0/test.dll
```

so the assembly was built on the 1st and 3rd run.

### Analysis

See also #826 and #322.
I believe the problem is [here](https://github.com/dotnet/msbuild/blob/4fde89a8519bc2ddb04078a82a2082a7071cbfb7/src/Framework/NativeMethods.cs#L1202-L1204), where unlike in the `isWindows` if branch it doesn't check if the path points to a symlink.
It would be nice at least to be able to force link resolution by setting `MSBUILDALWAYSCHECKCONTENTTIMESTAMP` to 1, which sets `EscapeHatches.AlwaysUseContentTimestamp` to true, or even better if it just "did the right thing" like on Windows.

### Versions & Configurations

MacOS Tahoe 26.4
`dotnet --version`: 10.0.102
`dotnet msbuild --version`: 18.0.7.61305

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.