How to produce multiple libraries from one package?

My goal is to use one Swift package to create multiple libraries.
I would like projects that depend on this package to be able import on the libs they want.

For example my Package would be call Foo, but it exports Bar and Baz.

External code can import the entire lib or pieces of it

import Foo // all the libs in the package Bar and Baz

import Bar // just import Bar from Foo Swift Package

Follow up question, can you specify which source files can be associated with a target? Currently it is all the code in sources are part of the target.

I got this to work with the following setup in the Package.Swift:

let package = Package(
    name: "foo",
    products: [
        // Products define the executables and libraries produced by a package, and make them visible to other packages.
        .library(
            name: "Foo",
            targets: ["Foo"]),
        .library(
            name: "Bar",
            targets: ["Bar"]),
        ],
    dependencies: [
        // Dependencies declare other packages that this package depends on.
        // .package(url: /* package url */, from: "1.0.0"),
    ],
    targets: [
        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
        // Targets can depend on other targets in this package, and on products in packages which this package depends on.
        .target(
            name: "Foo",
            dependencies: ["Bar"],
            path: "Sources/Foo"),
        .target(
            name: "Bar",
            dependencies: [],
            path: "Sources/Bar"),
        .testTarget(
            name: "FooTests",
            dependencies: ["foo"]),
        ]
)
2 Likes

Yes, that is generally correct.


Be careful to watch the casing. This mismatch is asking for trouble:

.target(
    name: "Foo",
// [...]
dependencies: ["foo"]),

If the casing does not match, some path or name related things may work sometimes and not others depending on whether current device’s file‐system is case sensitive or not.


These path arguments are not really necessary. Those paths would be the defaults anyway:

path: "Sources/Foo"),
// [...]
path: "Sources/Bar"),