How to iterate through set of exact dependency versions for swift package using command line?

Hi! I'm maintaining a macros library with the following dependency on swift-syntax:

let dependencies: [Package.Dependency] = [
  .package(url: "https://github.com/apple/swift-syntax.git", "509.0.0"..<"600.0.0"),
]

My goal is to iterate through those supported versions and run my unit tests against each one. Here is what that ends up looking like when I try validating my package "manually" across versions by-hand:

let dependencies: [Package.Dependency] = [
  //  .package(url: "https://github.com/apple/swift-syntax.git", "509.0.0"..<"600.0.0"),
  //  .package(url: "https://github.com/apple/swift-syntax.git", exact: "510.0.2"),
  //  .package(url: "https://github.com/apple/swift-syntax.git", exact: "510.0.1"),
  //  .package(url: "https://github.com/apple/swift-syntax.git", exact: "510.0.0"),
  //  .package(url: "https://github.com/apple/swift-syntax.git", exact: "509.1.1"),
  //  .package(url: "https://github.com/apple/swift-syntax.git", exact: "509.1.0"),
  //  .package(url: "https://github.com/apple/swift-syntax.git", exact: "509.0.2"),
  //  .package(url: "https://github.com/apple/swift-syntax.git", exact: "509.0.1"),
  .package(url: "https://github.com/apple/swift-syntax.git", exact: "509.0.0"),
]

Ehh… not great. My preference would be to somehow "override" the dependency through the command-line (and then write a script that iterates through those options for me before a clean test build).

I attempted to try and pass a flag through to Xswiftc:

//  swift build -Xswiftc -DSWIFT_SYNTAX_509_0_0

#if SWIFT_SYNTAX_509_0_0

let dependencies: [Package.Dependency] = [
  .package(url: "https://github.com/apple/swift-syntax.git", exact: "509.0.0"),
]

//  swift build -Xswiftc -DSWIFT_SYNTAX_509_0_1

#elseif SWIFT_SYNTAX_509_0_1

let dependencies: [Package.Dependency] = [
  .package(url: "https://github.com/apple/swift-syntax.git", exact: "509.0.1"),
]

#else

...

#endif

But it looks like it is a known issue that these flags are meant for forwarding to targets and are not accessible to SwiftPM while the package itself is constructed.[1][2]

It sounds like using environment variables (which are available to SwiftPM) might be a legit workaround… but I'm also open to any other modern patterns the community might know about. Does anyone have a repo or an example for doing something along these lines? Thanks!


  1. Compiler flags in Package.swift ↩︎

  2. Passing compilation flags to local Swift packages ↩︎

1 Like

You can use my GitHub action Swift Macro Compatibility Check to achieve what you're looking for.

I have implement this action exactly to verify compatibility of Swift packages with macros against multiple versions of swift-syntax.

The action will automatically test your package against various versions of swift-syntax, including:

  • 509.0.0
  • 509.0.1
  • 509.0.2
  • 509.1.0
  • 509.1.1
  • 510.0.0
  • 510.0.1
  • 510.0.2

To use it, you can add a step like this to your GitHub Actions workflow:

- name: Run Swift Macro Compatibility Check
  uses: Matejkob/swift-macro-compatibility-check@v1

Make sure to run this on a macOS runner:

jobs:
  check-macro-compatibility:
    runs-on: macos-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      - name: Run Swift Macro Compatibility Check
        uses: Matejkob/swift-macro-compatibility-check@v1

You can also customize the behavior with options like run-tests, major-versions-only, and verbose.

Alternatively, if you prefer to implement this locally, you could write a script that iterates through the versions and runs swift build and swift test for each on (the a look at the main file in the repo for more details and inspirations).

If you have time and are interested in contributing, you could consider making a PR to the GitHub action to extract the main script that runs swift build and test checks into a separate bash script. This would allow others to either use the GitHub action directly or copy the script for local use.

1 Like

Ahh… interesting! I will take a look. Thanks!

@Matejkob I believe the local script landed for running the test flows?