Introduction to Open Source Swift on Linux

Learn how to use open source Swift to run a Hello, World app on Linux – and how to use the Swift package manager! By Alexis Gallagher.

Leave a rating/review
Save for later
You are currently viewing page 2 of 3 of this article. Click here to view the first page.

What Apple Has Released

Apple has released five categories of software to date:

1) The Swift compiler (source code and executable binaries), debugger, and interactive prompt (i.e., REPL).

This is the heart of the Swift language itself. Apple has released the source code for the the Swift compiler, the same swiftc program that Xcode uses to compile Swift for iOS and Mac apps.

2) The Swift standard library

This is (almost) exactly the same standard library that’s been used since Swift’s release. It defines strings, collection types, protocols, and other fundamental constructs. Have you been yearning to see how the standard library implements a basic type, like Double or Array? Now you can.

But of course, the Swift standard library alone doesn’t get you very far. How many Swift applications have you written where you don’t import UIKit? Probably not very many. The functionality of Foundation, at a minimum, is indispensable for writing useful software (instead of, you know, “Hello, world”, or the five-millionth example of the factorial function). All of this makes it very promising that Apple has also released …

3) Swift Core Libraries

These are brand new, cross-platform, Objective-C-free re-implementations of existing Apple libraries. They provide higher-level functionality such as networking, file system interaction, date and time calculation. A caveat: they’re not quite finished. But that’s not all. Apple has also released …

4) Swift Package Manager

The Swift package manager is a bit like Carthage; it can download dependencies, compile them, and link them together to create libraries and executables. As of April 2016, it is only distributed with the development builds of Swift rather than the more mature release builds. This is why we have downloaded the development build, which contains Swift 3.

5) Other Components

If you browse Apple’s Github page, you can find other components as well: a Swift wrapper for libdispatch (aka, Grand Central Dispatch), notes on the future plans for Swift 3.0, even a parser/renderer for the Markdown dialect CommonMark.

What Apple Hasn’t Released

That’s quite a pile of functionality — but what hasn’t Apple released?

Well, there’s no Xcode, no AppKit and no UIKit. There’s no Core Graphics, no Core Animation, no AVFoundation, nor many of the other familiar core Objective-C libraries. Basically, most of what you need to create beautiful iOS or Mac apps isn’t here yet.

But what Apple has released is quite significant. Consider the Core Libraries project. Why did Apple take the trouble of re-implementing its own mature, battle-tested Foundation libraries?

The fact that the Core Libraries project doesn’t rely on the Objective-C runtime suggests that Apple is creating the underpinnings for Swift to replace Objective-C completely in the long run. And the fact that it’s cross-platform by design suggests Apple is seriously hoping people will use the language for Linux software development — at least for server software, if not for GUI apps.

But the package manager is most significant of all. Before diving into the reasons why, take a quick kick at the tires and see what it does.

Using the Swift Package Manager

The package manager defines a simple, common-sense directory structure for any Swift code that you would like to build into an executable or library. You’ll look at that format using your VirtualBox install of Ubuntu and Vagrant.

First, execute the following command at the shell prompt to create a directory helloworld-project and dive into it:

mkdir helloworld-project && cd helloworld-project

Now execute the following to to create an empty file named Package.swift:

touch Package.swift

The presence of this file indicates that the current directory defines a Swift package.

Now create a directory for source code files with the following command:

mkdir Sources

Next, execute the following to copy your old program, helloworld.swift, into Sources/ with the new name main.swift:

cp ../helloworld.swift Sources/main.swift

The directory structure of helloworld-project now defines the most basic package possible, and should look as follows:

├── Package.swift
└── Sources/
    └── main.swift

Execute the following command to build the package:

swift build

You should see the following:

vagrant@vagrant-ubuntu-trusty-64:~/helloworld-project$ swift build
Compiling Swift Module 'helloworldproject' (1 sources)
Linking .build/debug/helloworld-project

This creates a new, hidden folder for build products — .build. Your directory structure should now look like the following:

├── .build/
│   └── debug/
│       ├── helloworld-project*
│       ├── helloworld-project.o/
│       │   ├── build.db
│       │   ├── helloworld-project/
│       │   │   ├── main.d
│       │   │   ├── main~partial.swiftdoc
│       │   │   ├── main~partial.swiftmodule
│       │   │   ├── main.swiftdeps
│       │   │   ├── master.swiftdeps
│       │   │   └── output-file-map.json
│       │   ├── home/
│       │   │   └── vagrant/
│       │   │       └── helloworld-project/
│       │   │           └── .build/
│       │   │               └── debug/
│       │   ├── llbuild.yaml
│       │   └── Sources/
│       │       └── main.swift.o
│       ├── helloworldproject.swiftdoc
│       └── helloworldproject.swiftmodule
├── Package.swift
└── Sources/
    └── main.swift

You can verify this hidden folder structure by executing ls -aR.

The most important file here is .build/debug/helloworld-project, which is marked with an asterisk above to indicate that it’s executable. This is your executable, which you can run now just by entering it’s name on the command line, like so:

vagrant@vagrant-ubuntu-trusty-64:~/helloworld-project$ .build/debug/helloworld-project
Hello, world

Cool. But what’s all that other gunk in the directories used for?

All of those intermediate build products are indications of the true scope of the package manager’s functionality. Remember — it’s more than just a compiler. In its capacity as a build tool (like make), the package manager is responsible for compiling multiple files required for a single package and linking them together.

In its capacity as a package manager (like Carthage or CocoaPods), it also has the responsibility of linking together multiple packages and fetching dependent packages on the Internet. This implies the package needs some concept of versioning and compatibility (e.g, “Which dependency can meet my needs?”), and of location (e.g., “Where do I get it?”).

For a less-trivial example, take a look at Apple’s own sample project; it’s an app that simulates the dealing of a deck of cards.

Install Git, change to a new directory, and get the top-level package with the following shell commands:

cd ~
sudo apt-get --assume-yes install git
git clone
cd example-package-dealer

Crack open the Apple project and have a look; you’ll see it includes almost nothing:

├── main.swift
├── Package.swift

However, Package.swift is not empty this time; it includes a small snippet of Swift that declares this package depends on version 1 of another package, example-package-deckofplayingcards, which in turn lives at a URL on github, and that package in turn depends on others, and so on.

The net result is that if you call swift build for the example project, you’ll get more than 400 files, as the build tool downloads those other package repositories, compiles them, and links them together.

Apple provides more details on the package manager on the new website. Below is a quick list of notable points about the new package manager:

  • Uses a simple directory structure for package layout and a simple Swift-based manifest file, as opposed to Xcode, which allows any directory structure, but requires a proprietary Xcode project file to track the freeform chaos this implies.
  • Uses semantic versioning, the defacto standard for declaring package versioning and compatibility information
  • Is tightly integrated with Swift’s notion of a module, which Apple uses for Objective-C and has promoted as a standard for C.
  • Overlaps with some of xcodebuild’s functionality.
  • Performs transitive dependency analysis, but doesn’t yet handle dependency conflicts.
  • Builds executable and static libraries, but doesn’t yet handle dynamic libraries.
  • Uses git, but has no support for other version control system yet.
  • Includes a very thoughtful community proposal document, which describing the thinking behind its design.

If you’ve used CocoaPods, Carthage, or other package managers, this will all seem quite familiar. And indeed, technically, it is nothing new. But it is new to Apple, and this is notable. So let us gaze into the mists of time and ask …