MsBuild using last write time of symlinks instead of their targets to determine whether or not to rebuild
- 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.