Skip to content

Retain sub-second modification time precision on non-Darwin platforms - #2228

Merged
jakepetroules merged 1 commit into
swiftlang:mainfrom
jakepetroules:fix-nondarwin-mtime-precision
Oct 8, 2026
Merged

jakepetroules merged 1 commit into
swiftlang:mainfrom
jakepetroules:fix-nondarwin-mtime-precision

Conversation

@jakepetroules

Copy link
Copy Markdown
Contributor

On non-Darwin platforms, lastModificationTime(for:) obtained modification times from Foundation and truncated them to whole seconds (nanoseconds: 0). This makes ordering comparisons between files written within the same second ambiguous.

In particular, FirstWaveComputer.computeCanSkipEmitModuleTasks only skips the emit-module job when every source is strictly older than the oldest emit-module output. When a source and the module outputs were written in the same second, both truncate to the same value, < is false, and emit-module is spuriously re-run even though nothing changed. This was the cause of a long-standing nondeterministic failure in swift-build's BuildCommandTests.singleFileCompile on Linux and FreeBSD (most recently seen in CI for swiftlang/swift-build#638); instrumenting the driver confirmed it fails exactly when the source and outputs share a whole-second timestamp.

This change uses stat directly on Glibc, Musl, and Android, as is already done on Darwin, to retain the nanosecond component. stat follows symbolic links, so the modification time of the linked file continues to be returned. Windows is unchanged.

Testing

Added LastModificationTimeTests:

  • retainsSubSecondPrecision: checks the driver's modification time agrees with Foundation's to within 1ms. Fails on Linux without this change (expected 1791395602.9011889, got 1791395602.0), passes with it.
  • followsSymbolicLinks: checks a symlink reports its target's modification time.

Ran the new tests on macOS and Linux (aarch64), and the incremental, module dependency graph, build record, and output job test suites on Linux. With this change, swift-build's singleFileCompile passed 15/15 runs on Linux with its workaround disabled, versus failing roughly two thirds of the time before.

On non-Darwin platforms, lastModificationTime(for:) obtained modification
times from Foundation and truncated them to whole seconds. This makes
ordering comparisons between files written within the same second
ambiguous. In particular, the incremental build only skips an emit-module
job when every source is strictly older than every emit-module output, so
emit-module was spuriously re-run whenever a source and the module outputs
were written in the same second.

Use stat directly on Glibc, Musl, and Android (as on Darwin) to retain the
nanosecond component. stat follows symbolic links, so the modification
time of the linked file continues to be returned.
@jakepetroules

Copy link
Copy Markdown
Contributor Author

@swift-ci test

jakepetroules added a commit to swiftlang/swift-build that referenced this pull request Oct 7, 2026
…hosts

The C file compile depends on the target's Swift generated headers, so the
Swift driver is re-planned and decides whether emit-module is up to date by
checking that every source is strictly older than every emit-module output.
swift-driver truncates modification times to whole seconds on non-Darwin
platforms, so when SwiftFile.swift and the module outputs from the first
build are written within the same second, emit-module is re-run.

The existing workaround only applied to Linux, so the test was still flaky
on FreeBSD. Apply it to every non-macOS host, and document the root cause
in place of the FIXME. The underlying driver fix is
swiftlang/swift-driver#2228.
Teemperor pushed a commit to Teemperor/swift-mono that referenced this pull request Oct 7, 2026
…n all non-Darwin hosts

The C file compile depends on the target's Swift generated headers, so the
Swift driver is re-planned and decides whether emit-module is up to date by
checking that every source is strictly older than every emit-module output.
swift-driver truncates modification times to whole seconds on non-Darwin
platforms, so when SwiftFile.swift and the module outputs from the first
build are written within the same second, emit-module is re-run.

The existing workaround only applied to Linux, so the test was still flaky
on FreeBSD. Apply it to every non-macOS host, and document the root cause
in place of the FIXME. The underlying driver fix is
swiftlang/swift-driver#2228.
@jakepetroules
jakepetroules merged commit babb101 into swiftlang:main Oct 8, 2026
50 of 51 checks passed
@jakepetroules
jakepetroules deleted the fix-nondarwin-mtime-precision branch October 8, 2026 09:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants