Module vs Product vs Target

I remembered that there's a recommendation that the module name should be universally unique (that includes among other packages as well). Especially from Package module name collisions post, and a more recent one; Logging module name clash in Vapor 3.

So I consulted SwiftPM Package Description, but they use the terms Product and Target instead, which leads me to a few questions:

  • What's the difference between Product and Target, and when people say Module, which one do they generally refer to?
  • When you do import Foo, which one is used? And most importantly,
  • Which one should be universally unique, and which one can be disambiguate?
6 Likes

Here is my understanding:

  • module: A group of interrelated sources intended to always be built together. (cf. whole module optimization). This is what is referenced when you import MyModule, and when you use its name for disambiguating a symbol: MyModule.Data vs Foundation.Data.
    • In general English, a module is “one of a set of standardized parts or independent units that can be used to construct a more complex structure”
  • target: A unit of the build result; a particular thing you might aim to build on its own. A Swift target is pretty much equal to a Swift module, so they are often used interchangeably. However module tends to refer more to the grouping whereas target refers more to the result. Another difference is that a target does not necessarily have to contain source; it could be something else such as a resource bundle and such a target is not a module. Targets are referenced by the package manifest’s .target(...) and testTarget(...), and by Xcode under “File → New → Target...” and so on.
    • In general English, a target is “a mark or point at which one fires or aims” or “an objective or result towards which efforts are directed”
  • product: A unit of functionality you want to vend to clients. Often a product is also a single target, but the reverse is not true. Many targets are not intended for others to use (such as test targets), and those are never described as products. Products are defined in the package manifest’s products argument and referenced in client target’s dependency list with .product(...) (unless the reference is reduced to a string literal).
    • In general English, a product is “an article or substance that is manufactured or refined for sale”
13 Likes

Only products have a means of disambiguation:

.target(name: "MyTarget", dependencies: [
    // Ambiguous:
    "Someone’sProduct",
    // Unambiguous:
    .product(name: "Someone’sProduct", package: "Someone’sPackage")
    ])

Targets and modules have no means of disambiguation (yet), so they must be unique:

import Foundation
// Is that the core library, or the Foundation in my own package?
products: [
        // If I have two targets with the same name, this means trouble:
        .library(name: "MyLibary", targets: ["DiplicatedTargetName"]),
]

Technically here Foo is the module name.

But when the module is from a Swift package, then the module inherits its name from the name of the target, so the import happens to also be equal to the target name:

.target(name: "Foo")

I see. Thaks for the detailed explaination :smiley:

1 Like