An open API service indexing awesome lists of open source software.

https://github.com/cgrindel/rules_swift_package_manager

Collection of utilities and Bazel rules to aid in the development and maintenance of Swift repositories using Bazel.
https://github.com/cgrindel/rules_swift_package_manager

bazel bazel-rules swift swift-package-manager

Last synced: 3 months ago
JSON representation

Collection of utilities and Bazel rules to aid in the development and maintenance of Swift repositories using Bazel.

Awesome Lists containing this project

README

        

# Swift Package Manager Rules for Bazel

[![Build](https://github.com/cgrindel/rules_swift_package_manager/actions/workflows/ci.yml/badge.svg?event=schedule)](https://github.com/cgrindel/rules_swift_package_manager/actions/workflows/ci.yml)

This repository contains a Bazel ruleset that can be used to download, build, and consume Swift
packages. The rules in this repository build the external Swift packages using [rules_swift],
[rules_apple] and native C/C++ rulesets making the Swift package products and targets available as
Bazel targets.

This repository is designed to fully replace [rules_spm] and provide utilities to ease Swift
development inside a Bazel workspace.

## Table of Contents

* [Documentation](#documentation)
* [Prerequisites](#prerequisites)
* [Mac OS](#mac-os)
* [Linux](#linux)
* [Quickstart](#quickstart)
* [1. Enable bzlmod](#1-enable-bzlmod)
* [2. Configure your `MODULE.bazel` to use rules_swift_package_manager.](#2-configure-your-modulebazel-to-use-rules_swift_package_manager)
* [(Optional) Use `swift_package` repository for updating packages](#optional-use-swift_package-repository-for-updating-packages)
* [(Optional) Enable `swift_deps_info` generation for the Gazelle plugin](#optional-enable-swift_deps_info-generation-for-the-gazelle-plugin)
* [3. Create a minimal `Package.swift` file.](#3-create-a-minimal-packageswift-file)
* [4. Run `swift package update`](#4-run-swift-package-update)
* [5. Run `bazel mod tidy`.](#5-run-bazel-mod-tidy)
* [6. Build and test your project.](#6-build-and-test-your-project)
* [7. Check in `Package.swift`, `Package.resolved`, and `MODULE.bazel`.](#7-check-in-packageswift-packageresolved-and-modulebazel)
* [8. Start coding](#8-start-coding)
* [Using a Swift package registry](#using-a-swift-package-registry)
* [Tips and Tricks](#tips-and-tricks)

## Documentation

- [Rules and API documentation](/docs/README.md)
- [High-level design](/docs/design/high-level.md)
- [Frequently Asked Questions](/docs/faq.md)

## Prerequisites

### Mac OS

Be sure to install Xcode.

### Linux

You will need to [install Swift](https://swift.org/getting-started/#installing-swift). Make sure
that running `swift --version` works properly.

Don't forget that `rules_swift` [expects the use of
`clang`](https://github.com/bazelbuild/rules_swift#3-additional-configuration-linux-only). Hence,
you will need to specify `CC=clang` before running Bazel.

Finally, help [rules_swift] and [rules_swift_package_manager] find the Swift toolchain by ensuring
that a `PATH` that includes the Swift binary is available in the Bazel actions.

```sh
cat >>local.bazelrc <
```python
bazel_dep(name = "rules_swift_package_manager", version = "1.0.0-rc1")
```

In addition, add the following to load the external dependencies described in your `Package.swift`
and `Package.resolved` files.

```bazel
swift_deps = use_extension(
"@rules_swift_package_manager//:extensions.bzl",
"swift_deps",
)
swift_deps.from_package(
resolved = "//:Package.resolved",
swift = "//:Package.swift",
)
use_repo(
swift_deps,
"swift_deps_info", # This is generated by the ruleset.
# The name of the Swift package repositories will be added to this declaration in step 4 after
# running `bazel mod tidy`.
# NOTE: The name of the Bazel external repository for a Swift package is `swiftpkg_xxx` where
# `xxx` is the Swift package identity, lowercase, with punctuation replaced by `hyphen`. For
# example, the repository name for apple/swift-nio is `swiftpkg_swift_nio`.
)
```

You will also need to add a dependency on [rules_swift].

NOTE: Some Swift package manager features (e.g., resources) use rules from [rules_apple]. It is a
dependency for `rules_swift_package_manager`. However, you do not need to declare it unless you use
any of the rules in your project.

#### (Optional) Use `swift_package` repository for updating packages

The `swift_deps` module extension will by default generate a `swift_package` repository which can be used to execute `swift package` commands.
This is useful if you'd like to control the flags and behavior of `swift package`, as well as for using the correct `swift` binary according to the Bazel configured toolchain.

For example, to resolve the `Package.swift` file:

```sh
bazel run @swift_package//:resolve
```

To update packages to their latest supported version:

```sh
bazel run @swift_package//:update
```

Both targets support passing arguments as well, so for example, you could update a single package:

```sh
bazel run @swift_package//:update -- MyPackage
```

These targets will update the `Package.resolved` file defined in `swift_deps.from_package`.
The targets come with default flags applied to enable the best Bazel compatibility, if you wish to configure it further, you can do so with `configure_swift_package`:

```starlark
# MODULE.bazel

swift_deps.configure_swift_package(
build_path = "spm-build",
cache_path = "spm-cache",
dependency_caching = "false",
manifest_cache = "none",
manifest_caching = "false",
)
```

If you do not want to use the `swift_package` repository you can disable it in the `swift_deps.from_package` call:

```starlark
swift_deps.from_package(
declare_swift_package = False, # <=== Disable the `swift_package` repository
resolved = "//:Package.resolved",
swift = "//:Package.swift",
)
```

#### (Optional) Enable `swift_deps_info` generation for the Gazelle plugin

If you will be using the [Gazelle plugin for Swift], you will need to enable the generation of
the `swift_deps_info` repository by enabling `declare_swift_deps_info`.

```bazel
swift_deps.from_package(
declare_swift_deps_info = True, # <=== Enable swift_deps_info generation for the Gazelle plugin
resolved = "//:Package.resolved",
swift = "//:Package.swift",
)
```

### 3. Create a minimal `Package.swift` file.

Create a minimal `Package.swift` file that only contains the external dependencies that are directly
used by your Bazel workspace.

```swift
// swift-tools-version: 5.7

import PackageDescription

let package = Package(
name: "my-project",
dependencies: [
// Replace these entries with your dependencies.
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.2.0"),
.package(url: "https://github.com/apple/swift-log", from: "1.4.4"),
]
)
```

The name of the package can be whatever you like. It is required for the manifest, but it is not
used by [rules_swift_package_manager]. If your project is published and consumed as a Swift package,
feel free to populate the rest of the manifest so that your package works properly by Swift package
manager. Just note that the [Swift Gazelle plugin] does not use the manifest to generate Bazel build
files.

### 4. Run `swift package update`

This will invoke Swift Package Manager and resolve all dependencies resulting in creation of
`Package.resolved` file.

### 5. Run `bazel mod tidy`.

This will update your `MODULE.bazel` with the correct `use_repo` declaration.

### 6. Build and test your project.

Build and test your project.

```sh
bazel test //...
```

### 7. Check in `Package.swift`, `Package.resolved`, and `MODULE.bazel`.

- The `Package.swift` file is used by `rules_swift_package_manager` to generate information about
your project's dependencies.
- The `Package.resolved` file specifies that exact versions of the downloaded dependencies that were
identified.
- The `MODULE.bazel` contains the declarations for your external dependencies.

### 8. Start coding

You are ready to start coding.

## Using a Swift package registry

See [our document on using a Swift package registry](/docs/swift_package_registry.md).

## Tips and Tricks

The following are a few tips to consider as you work with your repository:

- Are you trying to use a Swift package and it just won't build under Bazel? If you can figure out
how to fix it, you can patch the Swift package. Check out [our document on patching Swift packages].

[Bazel modules]: https://bazel.build/external/module
[Bazel's hybrid mode]: https://bazel.build/external/migration#hybrid-mode
[bzlmod]: https://bazel.build/external/overview#bzlmod
[our document on patching Swift packages]: docs/patch_swift_package.md
[CI GitHub workflow]: .github/workflows/ci.yml
[Gazelle plugin]: https://github.com/bazelbuild/bazel-gazelle/blob/master/extend.md
[Gazelle]: https://github.com/bazelbuild/bazel-gazelle
[Gazelle plugin for Swift]: https://github.com/cgrindel/swift_gazelle_plugin
[Swift Gazelle plugin]: https://github.com/cgrindel/swift_gazelle_plugin
[examples]: examples/
[rules_apple]: https://github.com/bazelbuild/rules_apple
[rules_spm]: https://github.com/cgrindel/rules_spm
[rules_swift]: https://github.com/bazelbuild/rules_swift
[rules_swift_package_manager]: https://github.com/cgrindel/rules_swift_package_manager
[tidy]: https://github.com/cgrindel/bazel-starlib/blob/main/doc/bzltidy/rules_and_macros_overview.md#tidy