Article

Creating a Standalone Swift Package with Xcode

Bundle executable or shareable code into a standalone Swift package.

Overview

Swift packages are reusable components of Swift, Objective-C, Objective-C++, C, or C++ code. Use them to package executable code, for example a script, as an executable product, or create a package that vends shareable code as a library product. You can create Swift packages with Xcode.

Create a Swift Package

To create a new Swift package, open Xcode and select File > New > Swift Package. Choose a name and select a file location. Select “Create Git repository on my Mac” to put your package under version control. On completion, the Swift package opens in Xcode and looks similar to a standard Xcode project. Xcode generates all necessary files and folders as it creates a Swift package:

  • The README.md file resides at the root level of the package. It describes the functionality of your package.

  • The Package.swift file, or package manifest, describes the configuration for the Swift package. You can double-click it in Finder to open the package in Xcode. The manifest file uses Swift and API from the Swift Package Manager’s PackageDescription library. It defines the package’s name, products, targets, and dependencies on other packages.

  • Source files reside in a folder named Sources. A Swift package can contain several targets, and, as a convention, each target’s code resides in its own subfolder.

  • Unit test targets reside in a folder named Tests, and, following the same convention as standard targets, each test target’s code resides in its own subfolder.

Screenshot showing a newly created standalone Swift package named ExamplePackage. The Editor area shows the package's manifest file while the Navigator area shows the package's contents and the Utilities area displays the information about the package manifest.

Configure Your Swift Package

Swift packages don’t use .xcproject or .xcworkspace but rely on their folder structure and use the Package.swift file for additional configuration. The following code listing shows a simple package manifest:

// swift-tools-version:5.1
import PackageDescription

let package = Package(
    name: "MyLibrary",
    platforms: [
        .macOS(.v10_13),
    ],
    products: [
        .library(name: "MyLibrary", targets: ["MyLibrary"]),
    ],
    dependencies: [
        .package(url: "https://url/of/another/package/named/Utility", from: "1.0.0"),
    ],
    targets: [
        .target(name: "MyLibrary", dependencies: ["Utility"]),
        .testTarget(name: "MyLibraryTests", dependencies: ["MyLibrary"]),
    ]
)

A Package.swift file needs to begin with the string // swift-tools-version:, followed by a version number such as // swift-tools-version:5.1.

The Swift tools version declares:

  • The version of the PackageDescription library

  • The Swift language compatibility version to process the manifest

  • The required minimum version of the Swift tools to use the package

Each version of Swift can introduce updates to the PackageDescription library, but the previous API version is available to packages that declare a prior tools version. This behavior allows you take advantage of new releases of Swift, the Swift tools, and the PackageDescription library, without having to update your package manifest and without losing access to existing packages.

To learn more about the PackageDescription API, see Package.

Add Your Code

To add source files to a Swift package, you can use workflows that you already know. For example, you can add a source file to a package by dragging it into the Project navigator, or by using the File > Add Files to [packageName] menu. A Swift package’s targets can contain Swift, Objective-C/C++, or C/C++ code, but an individual target can’t mix Swift with C-family languages. For example, a Swift package can have two targets, one that contains Objective-C, Objective-C++, and C code, and a second one that contains Swift code.

Screenshot showing a standalone Swift package with two added source files and two unit test files.

Make Your Swift Package Cross-Platform Compatible

While Swift packages are platform-independent by nature and include Linux as a target platform, your Swift packages can be platform-specific. Use conditional compilation blocks to handle platform-specific code and achieve cross-platform compatibility. The following example shows how to use conditional compilation blocks:

#if os(Linux)

// Code specific to Linux

#elseif os(macOS)

// Code specific to macOS

#endif

#if canImport(UIKit)

// Code specific to platforms where UIKit is available

#endif

In addition, you may need to define a minimum deployment target. Note how the package manifest below declares minimum deployment targets by passing them in as a value to the platforms parameter of the package initializer. However, passing minimum deployment targets to the initializer doesn’t restrict the package to the listed platforms.

// swift-tools-version:5.1
import PackageDescription

let package = Package(
    name: "MyPackage",
    platforms: [
        .macOS(.v10_13), .iOS(.v11), .tvOS(.v11),
    ],
    products: [
        // Products define the executables and libraries produced by a package, and make them visible to other packages.
        .library(
            name: "SharedCode", targets: ["SomeInternalCode", "SharedCode"])
        ],
        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: "SharedCode"),
            .target(
                name: "SomeInternalCode"),
            .testTarget(
                name: "SharedCodeTests",
                dependencies: ["SharedCode"]),
            .testTarget(
                name: "SomeInternalCodeTests",
                dependencies: ["SomeInternalCode"]),
    ]
)

Build Your Targets and Run Unit Tests

Xcode creates a scheme for each product in the Swift package’s manifest file. If your package contains multiple products, Xcode creates an additional scheme with the name [packageName]-Package to build all of them. Use this scheme to build all of the package’s targets and run all unit tests.

Select a scheme for the package’s build-and-run destination, and build it as you’d build an app target. Each source target usually has at least one corresponding test target.

See Also

Local and Standalone Packages

Organizing Your Code with Local Packages

Simplify maintenance, promote modularity, and encourage reuse by organizing your app’s code into local Swift packages.

Editing a Package Dependency as a Local Package

Override a package dependency and edit its content by adding a Swift package as a local package.

Developing a Swift Package in Tandem with an App

Add your published Swift package as a local package to your app’s project and develop the package and the app in tandem.

class Package

The configuration of a Swift package.