Giter Club home page Giter Club logo

rules_swift_package_manager's Introduction

Gazelle Plugin for Swift and Swift Package Rules for Bazel

Build

This repository contains a Gazelle plugin and Bazel repository rules that can be used to download, build, and consume Swift packages. The rules in this repository build the external Swift packages using rules_swift 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

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.

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.

cat >>local.bazelrc <<EOF
build --action_env=PATH
EOF

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

Quickstart

The following provides a quick introduction on how to set up and use the features in this repository. These instructions assume that you are using Bazel modules to load your external dependencies. If you are using Bazel's legacy external dependency management, please review the legacy quickstart, instead.

Also, check out the examples for more information.

1. Enable bzlmod

This repository supports bzlmod as well as legacy WORKSPACE dependencies. If you are starting a new project, it is highly recommended to use bzlmod. To enable bzlmod, add the following to your .bazelrc.

common --enable_bzlmod

2. Configure your MODULE.bazel to use rules_swift_package_manager.

Add a dependency on rules_swift_package_manager.

bazel_dep(name = "rules_swift_package_manager", version = "0.30.0")

You will also need to add a dependency on Gazelle, rules_swift, and possibly rules_apple. Follow the links below to get the latest bzlmod snippets to insert into your MODULE.bazel.

NOTE: Only some projects require the inclusion of rules_apple. Some Swift package manager features (e.g., resources) use rules from rules_apple. While your project may not require these rules, one of your Swift package dependencies might require this ruleset. If you just want things to work, add rules_apple as a dependency. Otherwise, try building without rules_apple and be on the lookout for missing depdency errors.

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-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 proejct 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, at this time.

4. Add Gazelle targets to BUILD.bazel at the root of your workspace.

Add the following to the BUILD.bazel file at the root of your workspace.

load("@gazelle//:def.bzl", "gazelle", "gazelle_binary")
load("@rules_swift_package_manager//swiftpkg:defs.bzl", "swift_update_packages")

# Ignore the `.build` folder that is created by running Swift package manager
# commands. The Swift Gazelle plugin executes some Swift package manager
# commands to resolve external dependencies. This results in a `.build` file
# being created.
# NOTE: Swift package manager is not used to build any of the external packages.
# The `.build` directory should be ignored. Be sure to configure your source
# control to ignore it (i.e., add it to your `.gitignore`).
# gazelle:exclude .build

# This declaration builds a Gazelle binary that incorporates all of the Gazelle
# plugins for the languages that you use in your workspace. In this example, we
# are only listing the Gazelle plugin for Swift from rules_swift_package_manager.
gazelle_binary(
    name = "gazelle_bin",
    languages = [
        "@rules_swift_package_manager//gazelle",
    ],
)

# This macro defines two targets: `swift_update_pkgs` and
# `swift_update_pkgs_to_latest`.
#
# The `swift_update_pkgs` target should be run whenever the list of external
# dependencies is updated in the `Package.swift`. Running this target will
# populate the `swift_deps.bzl` with `swift_package` declarations for all of
# the direct and transitive Swift packages that your project uses.
#
# The `swift_update_pkgs_to_latest` target should be run when you want to
# update your Swift dependencies to their latest eligible version.
swift_update_packages(
    name = "swift_update_pkgs",
    gazelle = ":gazelle_bin",
    generate_swift_deps_for_workspace = False,
    update_bzlmod_stanzas = True,
)

# This target updates the Bazel build files for your project. Run this target
# whenever you add or remove source files from your project.
gazelle(
    name = "update_build_files",
    gazelle = ":gazelle_bin",
)

5. Resolve the external dependencies for your project.

Resolve the external dependencies for your project by running the following:

bazel run //:swift_update_pkgs

6. Create or update Bazel build files for your project.

Generate/update the Bazel build files for your project by running the following:

bazel run //:update_build_files

7. Build and test your project.

Build and test your project.

bazel test //...

8. Check-in Package.resolved, swift_deps_index.json, and MODULE.bazel.

  • The Package.resolved file specifies that exact versions of the dependencies that were identified.
  • The swift_deps_index.json file contains information that is used by the Gazelle plugin and the respository rules.
  • In addition to the declarations that you added to the MODULE.bazel file, executing //:swift_update_pkgs adds declarations to the end of the file related to the Swift packages that are used by your workspace.

9. Start coding

You are ready to start coding.

Tips and Tricks

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

  • When you add or remove source files, run bazel run //:update_build_files. This will create/update the Bazel build files in your project. It is designed to be fast and unobtrusive.
  • When you add or remove an external dependency, run bazel run //:swift_update_pkgs. This will resolve the changes to your transitive dependencies and regenerate your Package.resolved, swift_deps_index.json, and swift_deps.bzl (only if you are using legacy WORKSPACE mode).
  • If things do not appear to be working properly, run the following in this order:
    • bazel run //:swift_update_pkgs
    • bazel run //:update_build_files
  • Do yourself a favor and create a Bazel target (e.g., //:tidy) that runs your repository maintenance targets (e.g., //:swift_update_pkgs, //:update_build_files, formatting utilities) in the proper order. If you are looking for an easy way to set this up, check out the //:tidy declaration in this repository and the documentation for the tidy macro.
  • 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.

rules_swift_package_manager's People

Contributors

cgrindel-self-hosted-renovate[bot] avatar cgrindel avatar renovate[bot] avatar cgrindel-app-token-generator[bot] avatar luispadron avatar jpsim avatar attilathefun avatar jflan-dd avatar brentleyjones avatar demonionff avatar eliperkins avatar tingyao-ui avatar adzenith avatar thooms avatar yume190 avatar krypt-lx avatar

Stargazers

Alexandru Pop avatar Sihao Lu avatar Gonzalo avatar Jacob Martin avatar Cody Vandermyn avatar 110416 avatar Jeff Hodsdon avatar Karim Alweheshy avatar Marco Pagliari avatar Ivo Majic avatar Vladislav Prusakov avatar JonyFang avatar Lucas Romano avatar 晴风 avatar Yusuke Ohashi avatar  avatar Joseph Price avatar Hiep Thai avatar George Kontridze avatar Logan Howell avatar  avatar Patrick Lafleur avatar Bupterambition avatar Chris Longe avatar Vladyslav Ilyenko  avatar Xerol Wong avatar Bart Louwers avatar Snorlax avatar IKEDA Sho avatar Junsang Ryu avatar Margulan Daribayev avatar beforeold avatar Ryo Aoyama avatar  avatar Kevin Herro avatar  avatar Hank avatar André avatar eric.hsu avatar Ethan Huang avatar  avatar Timothy avatar Jack Pooley avatar Alex avatar  avatar Nikita avatar Tim Kersey avatar Jaden Geller avatar Kaan Biryol avatar Franz Busch avatar Khanh avatar Gabriel Féron avatar Chris Ballinger avatar PhilCai avatar Mike Chong avatar Thi Doan avatar  avatar Maxwell Elliott avatar Andrei Ogrenich avatar Daniel Aditya Istyana avatar John Firebaugh avatar Keith Smiley avatar  avatar  avatar Phanerozoic avatar

Watchers

 avatar  avatar  avatar

rules_swift_package_manager's Issues

Update the examples to test from no BUILD files.

Remove the existing BUILD files and replace the root BUILD file with just enough to run Gazelle.

Local test

clear ; find Sources -name "BUILD.bazel" -exec rm {} \; ; find Sources -name "BUILD.bazel" -exec rm {} \; ; br //:tidy && bazel test //...

Ensure target names do not contain spaces.

Example: @apple_swift_argument_parser//Plugins/GenerateManualPlugin:Generate Manual

The above should be @apple_swift_argument_parser//Plugins/GenerateManualPlugin:Generate_Manual

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Ignored or Blocked

These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.

Detected dependencies

bazel
WORKSPACE
  • bazel_skylib_gazelle_plugin 1.4.2
  • rules_bazel_integration_test v0.14.1
  • build_bazel_rules_swift 1.9.1
deps.bzl
  • bazel_skylib 1.4.2
  • io_bazel_rules_go v0.41.0
  • bazel_gazelle v0.32.0
  • cgrindel_bazel_starlib v0.16.1
examples/http_archive_ext_deps/WORKSPACE
  • bazel_skylib_gazelle_plugin 1.4.0
  • build_bazel_rules_swift 1.9.1
  • com_github_apple_swift_collections 1.0.4
  • com_github_apple_swift_argument_parser 1.2.2
examples/http_archive_ext_deps/extensions.bzl
  • com_github_apple_swift_collections 1.0.4
  • com_github_apple_swift_argument_parser 1.2.2
examples/nimble_example/WORKSPACE
  • bazel_skylib_gazelle_plugin 1.4.0
  • build_bazel_rules_swift 1.9.1
  • build_bazel_rules_apple 2.4.1
examples/vapor_example/WORKSPACE
  • bazel_skylib_gazelle_plugin 1.4.0
  • build_bazel_rules_swift 1.9.1
bazel-module
MODULE.bazel
bzlmod/workspace/MODULE.bazel
  • cgrindel_bazel_starlib 0.16.1
  • bazel_skylib 1.4.2
  • rules_swift 1.9.1
  • bazel_skylib_gazelle_plugin 1.4.1
  • gazelle 0.32.0
examples/firebase_example/MODULE.bazel
  • cgrindel_bazel_starlib 0.16.1
  • bazel_skylib 1.4.2
  • rules_swift 1.9.1
  • rules_apple 2.4.1
  • bazel_skylib_gazelle_plugin 1.4.1
  • gazelle 0.32.0
examples/http_archive_ext_deps/MODULE.bazel
  • cgrindel_bazel_starlib 0.16.1
  • bazel_skylib 1.4.2
  • rules_swift 1.9.1
  • bazel_skylib_gazelle_plugin 1.4.1
  • gazelle 0.32.0
examples/interesting_deps/MODULE.bazel
  • cgrindel_bazel_starlib 0.16.1
  • bazel_skylib 1.4.2
  • rules_swift 1.9.1
  • bazel_skylib_gazelle_plugin 1.4.1
  • gazelle 0.32.0
examples/ios_sim/MODULE.bazel
  • cgrindel_bazel_starlib 0.16.1
  • bazel_skylib 1.4.2
  • rules_swift 1.9.1
  • rules_apple 2.4.1
  • bazel_skylib_gazelle_plugin 1.4.1
  • gazelle 0.32.0
  • rules_xcodeproj 1.8.1
examples/objc_code/MODULE.bazel
  • cgrindel_bazel_starlib 0.16.1
  • bazel_skylib 1.4.2
  • rules_swift 1.9.1
  • bazel_skylib_gazelle_plugin 1.4.1
  • gazelle 0.32.0
examples/phone_number_kit/MODULE.bazel
  • cgrindel_bazel_starlib 0.16.1
  • bazel_skylib 1.4.2
  • rules_swift 1.9.1
  • rules_apple 2.4.1
  • bazel_skylib_gazelle_plugin 1.4.1
  • gazelle 0.32.0
examples/pkg_manifest_minimal/MODULE.bazel
  • cgrindel_bazel_starlib 0.16.1
  • bazel_skylib 1.4.2
  • rules_swift 1.9.1
  • bazel_skylib_gazelle_plugin 1.4.1
  • gazelle 0.32.0
examples/resources_example/MODULE.bazel
  • cgrindel_bazel_starlib 0.16.1
  • bazel_skylib 1.4.2
  • rules_swift 1.9.1
  • rules_apple 2.4.1
  • bazel_skylib_gazelle_plugin 1.4.1
  • gazelle 0.32.0
examples/snapkit_example/MODULE.bazel
  • cgrindel_bazel_starlib 0.16.1
  • bazel_skylib 1.4.2
  • rules_swift 1.9.1
  • rules_apple 2.4.1
  • bazel_skylib_gazelle_plugin 1.4.1
  • gazelle 0.32.0
examples/soto_example/MODULE.bazel
  • cgrindel_bazel_starlib 0.16.1
  • bazel_skylib 1.4.2
  • rules_swift 1.9.1
  • rules_apple 2.4.1
  • bazel_skylib_gazelle_plugin 1.4.1
  • gazelle 0.32.0
examples/tca_example/MODULE.bazel
  • cgrindel_bazel_starlib 0.16.1
  • bazel_skylib 1.4.2
  • rules_swift 1.9.1
  • rules_apple 2.4.1
  • bazel_skylib_gazelle_plugin 1.4.1
  • gazelle 0.32.0
examples/vapor_example/MODULE.bazel
  • cgrindel_bazel_starlib 0.16.1
  • bazel_skylib 1.4.2
  • rules_swift 1.9.1
  • rules_apple 2.4.1
  • bazel_skylib_gazelle_plugin 1.4.1
  • gazelle 0.32.0
examples/xcmetrics_example/MODULE.bazel
  • cgrindel_bazel_starlib 0.16.1
  • bazel_skylib 1.4.2
  • rules_swift 1.9.1
  • bazel_skylib_gazelle_plugin 1.4.1
  • gazelle 0.32.0
bazelisk
.bazelversion
  • bazel 6.2.1
github-actions
.github/actions/set_up_macos/action.yml
  • maxim-lobanov/setup-xcode v1
  • cgrindel/gha_set_up_bazel v1
  • actions/setup-go v4
.github/actions/set_up_ubuntu/action.yml
  • cgrindel/gha_install_swift_on_ubuntu v1
  • cgrindel/gha_set_up_bazel v1
.github/workflows/ci.yml
  • cgrindel/gha_join_jobs v1
  • actions/checkout v3
  • actions/checkout v3
.github/workflows/commit_msg_check.yml
  • agenthunt/conventional-commit-checker-action v2.0.0
.github/workflows/create_release.yml
  • actions/checkout v3
  • tibdex/github-app-token v1
  • cgrindel/gha_configure_git_user v1
  • cgrindel/gha_create_release v2
gomod
go.mod
  • go 1.18
  • github.com/bazelbuild/bazel-gazelle v0.31.1
  • github.com/bazelbuild/buildtools v0.0.0-20230510134650-37bd1811516d@37bd1811516d
  • github.com/creasty/defaults v1.7.0
  • github.com/deckarep/golang-set/v2 v2.3.0
  • github.com/stretchr/testify v1.8.4
  • golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1@2e198f4a06a1
  • gopkg.in/yaml.v3 v3.0.1
swift
bzlmod/workspace/Package.swift
  • apple/swift-argument-parser from: "1.2.2"
  • apple/swift-log from: "1.5.2"
examples/firebase_example/Package.swift
  • firebase/firebase-ios-sdk from: "10.12.0"
  • ashleymills/Reachability.swift from: "5.1.0"
examples/interesting_deps/Package.swift
  • apple/swift-log from: "1.5.2"
  • SDWebImage/libwebp-Xcode from: "1.2.4"
examples/ios_sim/Package.swift
  • apple/swift-nio 2.37.0
  • apple/swift-markdown 0.2.0
examples/nimble_example/Package.swift
  • Quick/Quick from: "v7.1.0"
  • Quick/Nimble from: "v12.0.1"
examples/objc_code/Package.swift
  • datatheorem/TrustKit from: "3.0.2"
examples/phone_number_kit/Package.swift
  • marmelroy/PhoneNumberKit from: "3.6.6"
examples/pkg_manifest_minimal/Package.swift
  • apple/swift-argument-parser from: "1.2.2"
  • apple/swift-log from: "1.5.2"
  • nicklockwood/SwiftFormat from: "0.51.12"
examples/snapkit_example/Package.swift
  • SnapKit/SnapKit from: "5.6.0"
examples/soto_example/Package.swift
  • soto-project/soto from: "6.7.0"
examples/tca_example/Package.swift
  • pointfreeco/swift-composable-architecture from: "0.55.1"
examples/vapor_example/swift/Package.swift
  • vapor/vapor 4.67.5
  • vapor/fluent 4.6.0
  • vapor/fluent-sqlite-driver 4.3.0
examples/xcmetrics_example/Package.swift
  • spotify/XCMetrics from: "0.0.11"

  • Check this box to trigger a request for Renovate to run again on this repository

Generate targets and index products in dependent Swift packages.

Tasks

  • Generate targets for products in external Swift packages. (swift_package) This seems to be mostly in-place from a previous PR. I thought that I had removed it. 🤷‍♂️
  • Support executable product with a regular target. This is an old-style package. The swift_binary should be created by the product. (Example: old [SwiftFormat Package.swift] #86 (https://github.com/nicklockwood/SwiftFormat/blob/master/Package.swift))

Opted not to pursue

  • Update ModuleIndex.IndexPkgInfo() to index products. (Gazelle plugin)
    • 2022-12-20: All targets that provide a module are directly available. There is no benefit to adding products that are aliases to the index.

Some more FAQs possibly

This is sweet! Just tested it out on the CLI tool were building at Cash and was able to successfully use it to replace our dependency on swift-argument-parser (which rules_spm was having version conflict issues with previously).

Couple of immediate Qs:

  • Is it possible to not have the Package.swift and other files in the root of the repo? Possibly in a per-package way?
    • One possible use case is to have a App/Package.swift and Tool/Package.swift for example.
    • I tried to change the path in the gazelle command and it generates the lock and swift_deps.bzl correctly in a different path outside the root but it looks like the swift_deps_index.json file is always output to root directory.
    • Additionally, the labels generated for the WORKSPACE assume the swift_deps.bzl file is at //:
  • Im a bit confused about when update_build_files is needed, I didn't have to use this at all to get building. The README suggests this should be run every time the sources change, is that true?

Support `bzlmod`

Tasks

  • Add bzlmod support to swift_bazel deps:
    • cgrindel/bazel-starlib
    • bazel-contrib/rules_bazel_integration_test
  • Implement bzlmod support for swift_bazel

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.