SE-0387: Cross-Compilation Destination Bundles

These are not CLI shortcuts, but actual examples of full commands that I run locally to test the prototype implementation.

Love to see how this proposal has evolved since the pitch phase.

I see the point about moving to “build-time triple” and “run-time triple” terminology, but there’s still a lot of places that use “host” and “destination” in this text: is there a way to explain the distinction?

Some nits with respect to the schema:

  • What do you think of headerSearchPaths to parallel librarySearchPaths—the proposed spelling includeSearchPaths can be misread as a imperative ("include these search paths for...anything")
  • In general, when a noun is used to modify another noun in English, one prefers the singular (unless there is some unavoidable ambiguity in meaning). For example, as you do here, "library search paths" not "libraries search paths." For the same reason, in standard English one would prefer "Swift resource path" over "Swift resources path." Is there some ambiguity here that caused you to choose swiftResourcesPath with the plural specifically?
2 Likes

Following up in a subsequent post because the forums software for some reason has disabled my return key, for which reason the rest of this feedback will be in one big paragraph (sorry). I do think @Finagolfin brings up a valid point of concern here that, with better cross-destination compilation support, silently falling back to system tools could lead to difficult-to-diagnose unexpected results. The introduction of a new cross-compilation schema would be an ideal time to explore new restrictions that, if found to be conservative, could always be relaxed later. As a middle way, at least, SPM could warn loudly when it chooses to use a fallback tool when performing cross-compilation, with perhaps an optional toggle in the schema to disallow it altogether.

1 Like

I'm willing to take a bet that in practice 90%+ of destination bundles won't be completely self-contained and will need to fall back on tools from PATH. There's little value in not reusing tools like git, zip etc that are already installed on the user's machine and work perfectly fine. In fact, all of the destinations I've produced while implementing this proposal worked that way.

The main benefit is that destination bundles can be smaller. For example, when cross-compiling from macOS to Linux, that only tool you need that's not included with the Xcode toolchain is a linker that supports ELF object format. Thus the vast majority of bundles for cross-compiling in that direction will need a toolset with a single entry and include a single binary for the Swift toolchain to work as needed.

If tools from the existing environment can't be picked automatically, it will require destination bundles to become much larger by including all of the tools, and that implies hundreds of megabytes of binaries (if not more in a typical scenario) copied around, duplicating those available in PATH. As an alternative, users of destinations will need to maintain their own explicit toolset files that enumerate every single binary that a toolchain might use. And there's no way to enforce that none of the tools would launch something from PATH anyway.

The issue is that we already found it too conservative while trying to implement it. This restriction is not cleanly enforceable, while proving to be burdensome from maintenance and DX perspective.

1 Like

What other system tools does SwiftPM use?

These are not CLI shortcuts, but actual examples of full commands

It is a shortcut because in the most general case of multiple destinations that refer to the same triple, none of the commands you've listed so far will work.

I'm willing to take a bet that in practice 90%+ of destination bundles won't be completely self-contained and will need to fall back on tools from PATH .

If you limit it to tools that generate code, it's more like the opposite.

There's little value in not reusing tools like git , zip etc that are already installed on the user's machine and work perfectly fine.

Since nobody has suggested not using those particular non-code-generating tools, and I specifically said it would be fine to keep using those, it is disingenuous of you to keep mentioning them.

If tools from the existing environment can't be picked automatically, it will require destination bundles to become much larger by including all of the tools, and that implies hundreds of megabytes of binaries (if not more in a typical scenario) copied around, duplicating those available in PATH .

This is a giant exaggeration, it won't be more than tens.

As an alternative, users of destinations will need to maintain their own explicit toolset files that enumerate every single binary that a toolchain might use.

No, most tools are already packaged in the Swift toolchain and so will not need to be enumerated in a toolset.

And there's no way to enforce that none of the tools would launch something from PATH anyway.

Sure, but that's not an excuse for making the problem worse by not cleaning up what we can.

The issue is that we already found it too conservative while trying to implement it.

I find that hard to believe: what tool did you have a problem with?

This restriction is not cleanly enforceable,

I've pointed out exactly where in the SPM source many tools are looked up: it would be trivial to disable those, while I fully grant there are others we don't know about and cannot easily control.

while proving to be burdensome from maintenance and DX perspective.

I don't think it will be a burden and am prepared to chip in myself on getting SPM working this way.

Let me emphasize that most bundles will mostly use the existing tools from the Swift toolchain or supply their own code-generating tools, ie not git, zip, etc but the assembler or linker. This whole discussion is about what to do about the few exceptions, where for some reason SPM can't find some tool and currently falls back to the system PATH.

I believe it's a good precaution to disable such system lookups that we know about in those few exceptional situations, but maybe you disagree. I fully grant that it would not be a promise of no system lookups, as I originally noted, "It is not clear what all the tools pulled in are: I doubt even the toolchain authors know at this point."

I am excited to see the efforts for making multi-platform development easier. However I have some questions:

  1. Will in the future, the destination bundles be able to provide additional package product definitions, i.e. iOSApplication product for ios destination, and similar for android apps?

    Currently building iOS apps with playground creates a swift package that exposes iOSApplication product defined in AppleProductTypes. Having a destination bundle level implementation might reduce the setup required for cross-platform development.

  2. If compiler directive os() is used in Package.swift, will it check for the destination platform or host platform or solely dependent upon the implementation of destination bundles?

Xcode, Playgrounds, and iOS SDK are out of scope of Swift Evolution. You can file an FB feature request if you think there's something that can be improved on that front.

This behavior is already established and we're not changing it here. Using current proposal's nomenclature, this will check for the build-time OS. If you need run-time platform checks, use conditional target dependencies as described in SE-0273.

+1 in general, but I echo @Finagolfin's concern against silent fallback to system PATH. Also I prefer headerSearchPaths as @xwu suggested.

I don't have much else to add to this review, except for an out-of-scope-ish question, which is somewhat relevant to but different from the "SwiftPM Plugins for Remote Running, Testing, Deployment, and Debugging" future direction: Could this feature serve as a possible/suitable foundation for implementing distributed compilation and/or automatic offloading of Swift programs?

As I mentioned above, this is not a silent fallback. We're following the expected system behavior here. From any perspective it's surprising that PATH would not be doing what it's documented and supposed to do. If someone wants that variable not to have a certain effect, they should reassign it to their desired value. An empty string I guess, with PATH="" if that's needed?

I'm not sure it could, this seems to be orthogonal to cross-compilation. Maybe one could come up with a wrapper similar to sccache and create a toolset that utilizes it?

By my understanding, the concern is that system tools are out of the package author's control, and any difference in behaviour across different systems' tools might break in unexpected and difficult-to-diagnose ways. Also what happens if the system doesn't have tools such as Git installed? It's not very likely, but certainly possible.

I should've clarified that when I said distributed compilation, I was thinking about that across a heterogeneous system, in which each machine cross-compiles parts of the whole thing.

1 Like

Yes, but this was always the case and there's no good way to enforce it in SwiftPM itself right now, and AFAIU in the foreseeable future. Even if hypothetically one prevents SwiftPM from using PATH when using a cross-compilation bundle, we don't have enough control over the rest of the tools, like clang etc, those can look into PATH whenever they want. What's the point in requiring something to be enforced if there are even no mechanisms to enforce it consistently?

Not sure how that's relevant to cross-compilation? Git is an explicit requirement of SwiftPM. A installation of Swift with SwiftPM but without Git should be considered broken, but I don't think this should be a concern on the level cross-compilation tools. It's a responsibility of the user installing the "top-level" toolchain to provide all of the required dependencies.

What's the point in requiring something to be enforced if there are even no mechanisms to enforce it consistently?

We cannot easily "enforce" it for all possible invocations of tools from the system PATH by the toolchain, but we can easily make sure that SPM does not look in the PATH for tools like the linker when cross-compiling, thus lowering but not eliminating the chance of system tool lookups.

It's not all or nothing, I'm simply advocating picking that low-hanging fruit.

I understand that, but my argument is for consistency and predictability that "all or nothing" approach gives us.

PATH has an established behavior that users come to expect. If it isn't applied consistently then we fall into a rabbit hole of keeping track of all the places it's applied or not applied, surfacing these differences in behavior in our documentation, and getting it displayed to users properly in diagnostics if something goes wrong. I don't think this is worth the maintenance burden, especially if users alternatively can set PATH to an empty string on their side and get vastly more predictable behavior when needed.

2 Likes
4 Likes