SPMResolver 2026.2.20.1
dotnet tool install --global SPMResolver --version 2026.2.20.1
dotnet new tool-manifest
dotnet tool install --local SPMResolver --version 2026.2.20.1
#tool dotnet:?package=SPMResolver&version=2026.2.20.1
nuke :add-package SPMResolver --version 2026.2.20.1
SPMResolver
spm-resolver is a .NET 10 global tool that resolves Swift packages and produces XCFramework outputs suitable for .NET MAUI / macios binding projects.
Prerequisites
- macOS
- .NET SDK 10
- Swift toolchain available on
PATH - Git available on
PATH - Xcode command line tools (
xcodebuild) available onPATH
Install (NuGet)
Package: https://www.nuget.org/packages/SPMResolver/
dotnet tool install --global SPMResolver
dotnet tool update --global SPMResolver
Install from local source (development)
dotnet pack src/SPMResolver/SPMResolver.csproj -c Release -o ./nupkg
dotnet tool install --tool-path ./tools SPMResolver --add-source ./nupkg
When installed with --tool-path, invoke it as ./tools/spm-resolver.
Usage
Resolve from a local package
spm-resolver \
--package-path /path/to/MyPackage \
--output /path/to/exported-xcframeworks
--package-path can also point directly to Package.swift.
Resolve from a remote package URL
spm-resolver \
--package-url https://github.com/example/MyPackage.git \
--tag 1.2.3 \
--output /path/to/exported-xcframeworks
Supported remote ref selectors:
--tag--branch--revision
Only one ref selector can be provided at a time.
All ref selectors are optional. When none is provided, the tool clones the repository's default branch and release lookup (if enabled) checks the latest GitHub release.
Remote ref selectors are valid only when --package-url is used.
Optional flags:
--keep-temporary-workspace: preserves the temporary workspace instead of deleting it at process end (useful for debugging).--disable-release-asset-lookup: skips GitHub Releases artifact lookup and always builds from source. Only valid with--package-url.
Build Behavior
For GitHub-hosted --package-url inputs, the tool first checks GitHub Releases for non-source archive assets (.zip, .tar, .tar.gz, .tgz) and extracts them locally.
GitHub default source assets (Source code (zip) / Source code (tar.gz)) are ignored.
If no XCFrameworks are found in release assets, the tool falls back to the normal source build flow below.
When an extracted release asset contains one or more *.xcframework directories anywhere in its uncompressed contents, that asset's extracted contents are exported to --output as-is (not flattened to only XCFramework directories).
When multiple matching release assets are found, their extracted contents are staged and exported together under asset-named top-level folders to avoid cross-asset overwrites.
This release lookup still runs when --branch or --revision is provided; without --tag, it checks the latest GitHub release, which may not match the requested ref. Use --disable-release-asset-lookup to avoid version mismatch in that scenario.
The lookup logs Checking GitHub Release assets for <owner>/<repo>... at the start, Remote ref selection: ... for selected tag/branch/revision, and Resolved GitHub release page: ... when a release is found.
When no prebuilt artifacts are found, it logs No XCFrameworks found in release assets. Falling back to source build..
Each library product is compiled for up to four platform slices:
| Slice key | Xcode destination |
|---|---|
ios |
generic/platform=iOS |
ios-simulator |
generic/platform=iOS Simulator |
macos |
generic/platform=macOS |
maccatalyst |
generic/platform=macOS,variant=Mac Catalyst |
Slices are skipped when the package's platforms declaration doesn't support them. Products with no platform restrictions are built for all four.
The tool resolves Xcode schemes in this order:
- Exact matches for product/package scheme names (
<Product>-Package,<Product>,<Package>-Package,<Package>). - Related non-test schemes that normalize to the same identity (including common platform-suffixed names like
Foo iOSandFoo-iOS), scored by package platform compatibility.
For dynamic-preferred library products, the per-slice fallback chain is:
- Dynamic linkage +
BUILD_LIBRARY_FOR_DISTRIBUTION=YES - Package-default linkage +
BUILD_LIBRARY_FOR_DISTRIBUTION=YES - Dynamic linkage +
BUILD_LIBRARY_FOR_DISTRIBUTION=NO - Package-default linkage +
BUILD_LIBRARY_FOR_DISTRIBUTION=NO
For static library products, only steps 2 and 4 apply.
The first successful attempt is used.
The build command also passes -skipMacroValidation; if the installed Xcode does not support that flag, the tool automatically retries without it.
Static library .o files are auto-wrapped via libtool.
For large packages, progress is printed per product and per slice so long-running builds remain observable.
The temporary workspace path is printed at startup (Temporary workspace: ...).
Output Behavior
- Destructive Write: If the output directory contains a
manifest.jsonfrom a previous run, the directory is completely deleted and recreated. - Safety Check: If the directory is non-empty but missing
manifest.json, the tool fails to prevent accidental data loss. - Manifest: A
manifest.jsonfile describes all exported artifacts (schema below). - Artifacts:
- Source-based: Buildable library products are compiled in Release mode to
.xcframework. - Binary: Pre-compiled XCFrameworks referenced by the package are copied to the output. For qualifying GitHub release assets, the extracted asset contents are exported as-is.
- Symbols:
.dSYMbundles and*.bcsymbolmapfiles are copied alongside their XCFrameworks.
- Source-based: Buildable library products are compiled in Release mode to
- Failures: If no valid artifacts are produced, the tool exits with an error code. Failed products are still recorded in
manifest.jsonwith"kind": "build-failure"and a non-nullerror.
Manifest Schema (manifest.json)
The manifest is a JSON object with generatedAtUtc (ISO 8601) and a dependencies array. Each entry:
| Field | Description |
|---|---|
name |
The name of the product or artifact. |
identity |
Filesystem-safe identity string. |
sourceUrl |
Source repository URL when available; otherwise null. |
kind |
xcframework, binary-xcframework, or build-failure. |
sourcePath |
Absolute source location used for this entry. |
outputPath |
Absolute path to the exported .xcframework (empty for failures). |
version |
Resolved version when available; otherwise null. |
revision |
Resolved git revision when available; otherwise null. |
branch |
Resolved branch when available; otherwise null. |
builtSlices |
Array of platform slices built (e.g., ["ios", "macos"]). null for binary artifacts. |
symbolPaths |
Array of paths to associated debug symbols. |
error |
Error message for build-failure entries; null on success. |
Timeouts
Individual operations have hard timeouts. If any timeout is hit, the operation fails (non-zero exit):
| Operation | Timeout |
|---|---|
git clone |
30 min |
git checkout |
15 min |
swift package resolve |
15 min |
swift package dump-package |
2 min |
xcodebuild -list (schemes) |
5 min |
Per-slice xcodebuild build |
30 min |
| Artifact discovery | 5 min |
xcodebuild -create-xcframework |
5 min |
Exit Codes
| Code | Meaning |
|---|---|
0 |
Success — at least one XCFramework was exported. |
1 |
Error (missing prereqs, build failure, no outputs). |
130 |
Operation canceled (Ctrl-C). |
Notes
- macOS Only: This tool depends on
xcodebuildand is macOS-only. - Private Repos: Uses system git credentials. Ensure you can
git clonethe package URL before running. - GitHub API auth: Set
GITHUB_TOKENwhen release lookups need higher rate limits or private-release access. - Release lookup troubleshooting: If release lookup reports no release unexpectedly, verify
GITHUB_TOKENis set (especially for private repos) and retry. - Temp workspace: Created under
$TMPDIR/spm-resolver/<guid>/and printed at startup. - Temp cleanup: Default behavior deletes the temp workspace on completion. Use
--keep-temporary-workspaceto retain it. - Swift tools version: A warning is emitted if the installed Swift major version is lower than the package's
swift-tools-version. - Batch reliability baseline: Recent validation runs reached 28/30 successful package exports; remaining outliers were package-specific project/metadata issues.
- Outlier behavior: Some repositories are not framework-friendly in pure SwiftPM/Xcodebuild workflows; these are surfaced as
build-failuremanifest entries and non-zero exit when zero artifacts are produced.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.
| Version | Downloads | Last Updated |
|---|---|---|
| 2026.2.20.1 | 134 | 2/20/2026 |
| 2026.2.18.2 | 103 | 2/18/2026 |