Swift Package Manager Logo

Implementing Swift Package Manager –Examples

This entry is part 6 of 14 in the series Swift Package Manager

In the next few entries, I’ll go through some examples of creating and consuming several simple packages.

I’ve taken the liberty of preparing a number of Git Repos, containing some packages, and a simple command-line package consumer:

Here’s how they relate to each other:

Fig. 1: Diagram Of The Package Hierarchy

All of the repos are tagged with semantic versions (as shown in the diagram above). Some of them create dylibs, some create static libraries.

The icons indicate whether or not the package emits a static library (little roman-column building), or a dynamic framework (toolbox and cocoa mug).

The lines and arrows indicate that the package or application embeds the package.

Note the three red lines in the diagram above (with the “no” symbol). These indicate some somewhat strange behavior. I’ll get to that, in a bit.

There are seven different versions of the consumer, which incorporate different packages and package versions.

The packages are insanely simple. They each specify a struct that looks more or less like this:

import Foundation
import Package_A

public struct Package_BPrime: PackageProtocol {
    public let indent: Int
    public let text: String
    public init(indent inIndent: Int = 0) {
        indent = inIndent
        let prefix = String(repeating: "\t", count: inIndent)
        text =  "\(prefix)Package_BPrime, Version: 2.0.0\n" + Package_A(indent: inIndent + 1).text
    }
}

The PackageConsumer simply grabs the text property of the topmost package, and prints it:

import Foundation
import Package_D

struct PackageConsumer {
    let text: String
    init(text intext: String = "PackageConsumer, Version 7.0.0") {
        text = intext + "\n" + Package_D(indent: 1).text
    }
}

let text = PackageConsumer().text
print(text)

For most of them, the only difference is the text they set to their text property, and the packages they include.

So it might print something that looks like this:

PackageConsumer, Version 6.0.0
	Package_D, Version: 2.0.0
		Package_C, Version: 2.0.0
			Package_A, Version: 2.0.0
		Package_A, Version: 2.0.0

The “seminal” package is Package_A. This is always a static library, and establishes a protocol that is used throughout the hierarchy.

In the next seven entries, I will go through each version of the PackageConsumer command-line app, explaining the package hierarchy, and linking to the appropriate tags in the GitHub repos.

An Important Note

I have learned that it’s a good idea to use the default package naming system and project structure. That’s because some parts of the build system require it; even though they shouldn’t. I suspect that will be fixed, sooner or later. Here is a Stack Overflow question about the topic.