cgrindel / rules_spm

Provide a means for integrating external Swift packages built by Swift Package Manager into Bazel build using rules_swift.
Apache License 2.0
58 stars 13 forks source link
bazel bazel-rules swift swift-package-manager

Swift Package Manager Rules for Bazel

swift_bazel is now rules_swift_package_manager

2023-04-03: The swift_bazel repository was renamed to rules_swift_package_manager. The successor to rules_spm now supersedes the functionality in this repository. As a result, this repository is being archived.

swift_bazel is replacing rules_spm

2023-01-10: The swift_bazel project, the successor for rules_spm, is now ready for testing. In addition to managing external Swift package dependencies, it also provides functionality for generating Bazel build files for your Swift project. If you have used rules_spm for your projects or if you are just looking for a way to manage external Swift packages in your Bazel workspace, I encourage you to check out swift_bazel and provide your feedback.

Important Message for iOS Developers

2022-11-28: There are some known issues with building and deplying applications for iOS devices using rules_spm. If you need to deploy to an iOS device, we do not recommend using rules_spm, at this time.

Work is currently underway to implement a Gazelle plugin that will resolve external package dependencies and generate Bazel build files that will build the external packages using rules_swift. This will allow applications to be built and deployed to any platforms/devices supported by rules_swift and rules_apple. Information about the plugin will be posted to here and bazelbuild.slack.com in the coming weeks.

Build

This repository contains rules for Bazel that can be used to download, build and consume Swift packages with rules_swift rules. The rules in this repository build the external Swift packages with Swift Package Manager, then make the outputs available to Bazel rules.

Table of Contents

Reference Documentation

Click here for reference documentation for the rules and other definitions in this repository.

Prerequisites

Mac OS

Be sure to install Xcode.

Linux

You will need to install Swift. Make sure that running swift --version works properly.

Don't forget that rules_swift expects the use of clang. Hence, you will need to specify CC=clang before running Bazel.

In addition, the Bazel toolchains want to use the Gold linker. While it may be installed on the system, it is possible that it will not be findable when using clang as mentioned previously. So, you will want to do one of the following:

Option #1: Create a symlink to the linker in the clang directory.

sudo ln -s $(which ld.gold) $(dirname $(which clang))

This option worked well on a fairly minimal install of Ubuntu 20.04.

Option #2: Specify a custom PATH via --action_env

Specify a custom PATH to Bazel via --action_env. The custom PATH should have the Swift bin directory as the first item.

swift_exec=$(which swift)
real_swift_exec=$(realpath $swift_exec)
real_swift_dir=$(dirname $real_swift_exec)
new_path="${real_swift_dir}:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
cat >>local.bazelrc <<EOF
build --action_env=PATH=${new_path}
EOF

This approach was necessary to successfully execute the examples on an Ubuntu runner using Github actions. See the Github workflow for more details.

Quickstart

The following provides a quick introduction on how to use the rules in this repository. Also, check out the examples directory for more information.

1. Configure your workspace to use rules_spm

Add the following to your WORKSPACE file to add this repository and its dependencies.

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
    name = "cgrindel_rules_spm",
    sha256 = "777e687245faa7340488e61f5abb23b95b4c0e27e05f7cea7318c03e4cc38289",
    strip_prefix = "rules_spm-0.11.2",
    urls = [
        "http://github.com/cgrindel/rules_spm/archive/v0.11.2.tar.gz",
    ],
)

load(
    "@cgrindel_rules_spm//spm:deps.bzl",
    "spm_rules_dependencies",
)

spm_rules_dependencies()

load(
    "@build_bazel_rules_swift//swift:repositories.bzl",
    "swift_rules_dependencies",
)

swift_rules_dependencies()

load(
    "@build_bazel_rules_swift//swift:extras.bzl",
    "swift_rules_extra_dependencies",
)

swift_rules_extra_dependencies()

2. Add external Swift packages as dependencies to your workspace

Add the following to download and build apple/swift-log to your workspace. NOTE: It is imperative that the products that will be used by your project are listed in the products list.

load("@cgrindel_rules_spm//spm:defs.bzl", "spm_pkg", "spm_repositories")

spm_repositories(
    name = "swift_pkgs",
    dependencies = [
        spm_pkg(
            "https://github.com/apple/swift-log.git",
            exact_version = "1.4.2",
            products = ["Logging"],
        ),
    ],
)

3. Use the module(s) defined in the Swift packages

Each Swift package can contain multiple Swift modules. A Bazel target is created for each Swift module which is exported by the products that were listed in the spm_pkg declaration.

The following shows a Bazel BUILD file with a swift_binary that depends upon the Logging module defined in apple/swift-log.

load("@build_bazel_rules_swift//swift:swift.bzl", "swift_binary")

swift_binary(
    name = "simple",
    srcs = ["main.swift"],
    visibility = ["//swift:__subpackages__"],
    deps = [
        "@swift_pkgs//swift-log:Logging",
    ],
)

Lastly, import the Swift module and enjoy!

import Logging

let logger = Logger(label: "com.example.main")
logger.info("Hello World!")