[Second review] SE-0387: Cross-Compilation Swift SDKs (previously Destination Bundles)

I'd anticipate the need to explicitly specify either of these two outside of a Canadian Cross setup would be small. In simple cross-compilation scenarios one would only refer to the latter two of the three, and compilerRunner is quite unambiguous.

I like how specific these are, but buildProductRunner seems slightly too verbose, maybe productRunner would be ok?

That is, I'm probably ok with these as they gain clarity at a relatively small cost of increased length:

  • compilerBuilder
  • compilerRunner
  • productRunner


  • toolchainBuilder
  • toolchainRunner
  • productRunner

since there are many more tools involved other than just a compiler.

I understand the thought process, but I am a little surprised by this comment.

"Runner" is a pretty common term in the CI/CD space to signify a non-local machine that runs some specific process (often building your application is a main one).

GitLab and Github Actions, for example, both use this term.

That being said, it may also be a reason not to use this shorthand term of "runner", and signify someway that it is the platform of the runner you are describing.

Each phase of cross-compilation runs a compiler that produces an executable that also runs somewhere. “Runner” is too vague of a term.

1 Like

I haven't had time to look at this in detail, but I'd like to ask one thing: if this ends up being named "Swift SDKs" or something like that, could we also update the proposal's filename and title in the repo?

It can be difficult to find things in the evolution repo when the accepted names have diverged greatly from the originally proposed names.


I am strongly opposed to Swift inventing entirely novel terms for this. If we consider this to be an "API" for cross-compilation, then we should embrace the philosophies of the Swift API Design Guidelines:

  • Don’t surprise an expert: anyone already familiar with the term will be surprised and probably angered if we appear to have invented a new meaning for it.
  • Don’t confuse a beginner: anyone trying to learn the term is likely to do a web search and find its traditional meaning.
  • Embrace precedent. Don’t optimize terms for the total beginner at the expense of conformance to existing culture.

Inventing new names fails all three of these checks.

It could be argued that "precedent" here is fuzzy because different build systems have done different things. Even in that case, inventing a whole new standard isn't the right answer. We need to break the tie, and the best way to do that is to acknowledge that Swift is an LLVM- and Clang-based toolchain and that the least confusing option is to adopt the same terminology used by the compiler's underlying technology. That's "host" for the platform where the compiler runs and "target" for the platform where the compiled code will run.

I don't find the argument about target being confusable between a SwiftPM target and a target triple to be compelling for a few reasons:

First, every build system I've interacted with in my career uses "target" to refer to a library or binary that can be built. Almost every build system I've interacted with refers to a "target platform/configuration/environment" as well. These are used in completely different contexts and rarely confused by users.

This is an "expert"-level feature, for some definition of "expert". That is, it is not something your average day-one Swift developer is going to stumble on. I think it's fair that folks doing cross-compilation should be expected to have a deep enough understanding of their environment that they aren't confused by target in the context of a platform and target in the context of a thing being built. If we invent entirely new terms, they will immediately be less discoverable than using existing terms of art, and users of this feature who are used to other tools will be confused about why the terms don't align. This is especially true if they are doing advanced stuff with Clang and have to switch between different terms in the same build.

Lastly, I would expect triple: .target to be the default configuration for a SwiftPM target, and users would only need to specify that argument when they want to reference the host (or some other future alternative platforms).

IMO, the misnamed thing here in SwiftPM's existing target(...), which should be named something like module(...) instead. target in this usage is too vague, given that there are also executableTargets and testTargets—there's nothing that explains to users what a plain old target is. That's out of scope for this proposal, but given that SwiftPM maintainers have expressed a desire to move away from the target suffix, maybe there's a future where target itself is renamed as well, and then we have no need to worry about a conflict with the target triple.


I agree with this and also I don't think that the new terms are reducing confusion even if we consider coming up with new terms a goal.

Agreed, we have previously discussed module or library for this, e.g. this pre-pitch proposed Library. I think it would be fair to mention getting rid of .target() a future direction that could alleviate the concern that lead to inventing new terminology.


I tend agree with the sentiment expressed by @NeoNacho and @allevato, we should try to avoid new terminology where possible

I also agree that the right solution is to change SwiftPM use of the term target for module/library since it is confusing / misleading regardless of the CC proposal


As one of those who do cross-compiling in Swift, I'm happy to see the proposal is very close to being accepted!

First, let me put some comments on CMake things:

  1. The CMake document "Cross Compiling With CMake" says and consistently uses the following definition:

    The system used to build the software will be called the “build host,” and the system for which the software is built will be called the “target system” or “target platform.”

    Even though the variable describing the build host is somehow CMAKE_HOST_SYSTEM, I think both Autotools and CMake agree that the system used to build the software should be called the “build host,”

    So the CMake column in the table of Basic Cross-Compilation would be:

    GCC/Autotools/Meson LLVM/Clang/CMake Original Proposal Text Alternative
    build build build-time triple builder
    host target run-time triple executor
  2. As far as I understand, CMake doesn't provide Canadian Cross support natively. It's usually done by external tools through two-stage Basic Cross-Compilation. So to be precise, the "host platform" for describing the system running the compiler is not defined in CMake.

    GCC/Autotools/Meson LLVM/Clang CMake Original Proposal Text Alternative
    build build build build-time triple builder
    host host N/A N/A runner
    target target target run-time triple executor
  3. Note that CMake uses "target" as a core concept of build work unit as well as SwiftPM.

Having considered the above discussion, I object to introducing Canadian Cross support and new terminologies for the following reasons:

  1. I think Canadian Cross support in SwiftPM is too specific to the compiler. It will be rarely used except for Swift compiler. Autotools uses build/host/target but target is rarely used according to the document. Also it can be done by two stage basic cross-compilation and it would be much simpler.
  2. If we support only basic cross-compilation (it means we only have "build" / "target"), users don't need to specify the compilation triple in Package.swift at all because SwiftPM can automatically distinguish "build" or "target" just by checking whether it's macro or plugin. So there won't be "target of target" in user facing interface.
    (If we support Canadian Cross, users have to specify which one should be compiled for "host" and "target", so we have to expose such interface in that case.)
  3. The CMake build system already has "ambiguity" in terms of "target", but I guess the two "target"s are well far.

For anyone who wants some background on the “build”, “host”, and “target” terms, the GCC documentation has some history. These terms are several decades old at this point.


An approach to stay true to well-established meanings while resolving SPM ambiguity without introducing a whole new terminology would be to add a System suffix, i.e. use buildSystem and targetSystem (as well as hostSystem if we want Canadian Cross support).

1 Like

Thanks, that's a great point, I've updated the proposal text but kept the name of the file as it was. I don't think we have a nice way to add redirects from the old file name if we rename it and I don't want existing links to break.

1 Like

they aren't quite the same thing though? a target identifier can contain special characters (+, |, etc) but a module identifier must be a c99 identifier.

A .target represents a module in SPM's build model; when you build one, that's the output. The fact that the name might be transformed if it's not a valid module identifier doesn't change that.

when parsing package metadata from SPM, you usually get the target identifier, not the module identifier, and you don't want to accidentally plug a target string into some other tooling API that expects a module identifier string, because 99% of the time they are the same but that 1% of the time is a bug. so i have found it helpful to encode the distinction in the type system.

it's fair to ask if this is something that should be surfaced in the PackageDescription API. but the distinction is not completely useless.

Strong Agree

Canadian Cross should not be supported.
This concept is only necessary for compilers such as GCC, where the target is fixed at the time of its own build.
Such compiler architectures are not adopted today.
For example, swiftc allows a single compiler binary to support multiple targets.
The need for dedicated binaries for WASM and Android support is merely an implementation issue, not an intrinsic design constraint.
Furthermore, for SwiftPM, the task of building a compiler is only a small part of its various uses.
So the Canadian Cross story is doubly rare.
Introducing complex terminology is confusing to users.
This means that the disadvantages are too large and the advantages are too small.

1 Like

Personally, I think it is better to help the untold number of future readers, even if it means breaking some existing links.

For example, if I'm trying to understand some subtle behaviour of the consume operator by reading its SE proposal, I'll go to the repository, look through the list of proposals, and find nothing. The file is actually called 0366-move-function.md. If I'm looking to understand the details of the SDK format, the file name 0387-cross-compilation-destinations.md is not very obvious.

But I do understand your position as well. Perhaps this points to a more general flaw in how we organise proposals.


Even though LLVM supports multiple targets with the same compiler binary, the default target triple is still set at build time. It defaults to the host triple. And the docs intentionally don’t mention the config variable to set the default target triple, preferring to only mention the host triple instead.



i have also been doing github searches, as it never occurred to me that the swift website can also perform proposal searches. this is way better than digging through the swift-evolution repository!

1 Like