How to Write Command Line Programs Using Multiple Libraries in Swift

Writing a command line program in Swift is not hard. As like any other programs in Swift, you just turn on Xcode, code some, and run it. Then it’s done.

But, if you want to use some libraries in the program, now it becomes a trouble. Because Xcode 7 and 8 does not provide static library target for Swift yet. Which means, your command-line program executable will require separately packaged dynamic library, and that sucks.

Anyway, Swift team is providing another approach to write command-line programs. It’s “Swift Package Manager”. (or SwiftPM in short).

I have never before used a package manager to develop a multi-componented program. Becuse I have been using the IDEs only in my entire programming life. So at this time, I decided to try this package manager based programming.

See this to see how to use SwiftPM for single package (with no library) executable.

To try multicomponent program, I set up some directories.

mkdir app2
mkdir lib3

Now you have these directories.

./
./app2
./lib3

Initialize executable package.

cd app2
swift package init --type executable
cd ..

And library packages.

cd lib3
swift package init --type library
cd ..

Here’s pitfall. A Swift package must be a Git repository. More specifically, it must a tagged-commit. But SwiftPM doesn’t do this automatically, so you need to make it into a Git repo, commit, and tag a version.

git init
git add . -A
git commit -a -m "Ready."
git tag 0.0.0

Configuring Dependencies

Go to application directory and edit `Package.swift`.

cd app2
vi Package.swift

Put this code in the file.

import PackageDescription
let package = Package(
name: "app2",
targets: [],
dependencies: [
.Package(url: "./../lib1", majorVersion: 0),
]
)

Notice that url field must be a URL to a Git repository. It is supposed and should be a URL like “https://github.com/apple/example-package-playingcard”, but for now, I used local file path to simplify trial procedure.

Also let’s edit source code.

vi Sources/main.swift

Put this code in the file.

@testable import lib3
print(lib3())

Generated library project contains lib3 type, but it’s internal access only. So I used @testable keyword to use them for now to get it.

Ok. Now load the dependencies.

swift package update

And build and run.

swift build
.build/debug/app2

You will see something like this.

lib3(text: “Hello, World!”)

Anyway, this code works only in debug build because I used @testable keyword for quick try. If you build this project in release mode, this won’t work. Let’s fix this now.

First, go back to library directory, and update library code.

cd ..
cd lib3
vi Sources/lib3.swift

To expose the lib3 type publicly.

public struct lib3 {
public var text = "Hello, World!"
public init() {}
}

Don’t forget to add a public initializer.

Add, commit and tag the commit.

git add . -A
git commit -a -m "Expose 'lib3' publicly."
git tag 0.0.1

Notice on the new tag name. It’s revision number has been increased. So SwiftPM will pull this version automatically.

Move to app directory, and update code.

cd ..
cd app2
vi Sources/main.swift

It should become like this.

import lib3
print(lib3())

Update dependencies, and build again.

cd ..
cd app2
swift package update
swift build
.build/debug/app2

Of course, now it will work in release build.

swift build --configuration release
.build/release/app2

Done.