Concise Magic File Names

I'm glad to see this being clarified and formalized. Overall, I think this is the right direction to go—you rightly point out that we don't need a large number of knobs to fine-tune this feature.

I feel like the lede is buried a bit in the write-up regarding the description of the current (and proposed renamed) behavior; the initial sections of the pitch say:

Where a reader could interpret "full path to the [...] file" as meaning the absolute path, rather than "the path exactly as written in the swiftc invocation", which isn't clarified until much later in "Alternatives Considered".

In practice #file ends up frequently being the absolute path because that's what Xcode passes to the compiler, but Bazel is an example of a build system that passes paths that are relative to the workspace root (which is the CWD of invoked actions) and thus yields #file strings that match. So I think it would be helpful to clarify the "path exactly as written in the swiftc invocation" part up front.

The motivation cited in this section feels a bit inaccurate. #filePath on its own, if implemented as described here (i.e., as currently implemented), isn't necessarily incompatible with distributed build systems, as long as the build system does the right thing. Using Bazel again as an example, a remote execution environment might use different absolute paths to the workspace on each machine (for example, incorporating a hash or unique job ID), so a distributed build of a multi-module Swift project might have absolute paths that look like this:

machine 1: /build/01234567/username/workspaceroot/path/to/module1/SomeClass.swift
machine 2: /build/abcdef01/username/workspaceroot/path/to/module2/SomeStruct.swift
machine 3: /build/0badbeef/username/workspaceroot/path/to/module3/SomeEnum.swift

Since Bazel will use everything up through .../workspaceroot as the CWD for swiftc, the Swift build rules only pass path/to/module1/SomeClass.swift, path/to/module2/SomeStruct.swift, etc. to the compiler (in fact, Bazel doesn't even provide a way to get the full absolute paths when constructing those invocations). Therefore, #filePath strings would still be distributed-build-compatible because they don't encode any information about the world outside of the workspace.

However, purely as a security measure, I think it's reasonable that someone would want to disable #filePath in certain builds to avoid leaking details about their source directory layout in strings that ship with their binary.

This would be harmful for creating hermetic, reproducible builds. Surfacing absolute paths in user-visible ways when they weren't originally absolute breaks those guarantees and has historically required the addition of more flags to "fix" the problem, like -fdebug-prefix-map in Clang and -debug-prefix-map in Swift to strip path prefixes off of paths encoded in debug info.

If the Swift team wanted to always resolve the absolute paths regardless of how they were passed to the compiler, they would need to honor -debug-prefix-map, -working-directory, or some new flag to make those builds produce consistent strings on distributed systems where the workspace may not always be at the same file system location. In this case, it's best to simply avoid the problem by not introducing it in the first place.

5 Likes