Skip to content

Swift Package Manager distribution via prebuilt xcframework (iOS, macOS, Mac Catalyst, visionOS)#1486

Open
bmehta001 wants to merge 27 commits into
microsoft:mainfrom
bmehta001:bhamehta/spm-xcframework-prototype
Open

Swift Package Manager distribution via prebuilt xcframework (iOS, macOS, Mac Catalyst, visionOS)#1486
bmehta001 wants to merge 27 commits into
microsoft:mainfrom
bmehta001:bhamehta/spm-xcframework-prototype

Conversation

@bmehta001

@bmehta001 bmehta001 commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Swift Package Manager distribution via prebuilt xcframework

Adds Swift Package Manager (SPM) support so Apple app developers can consume the 1DS C++ SDK. SPM is the successor to CocoaPods (whose trunk goes read-only on 2 Dec 2026), and the repo has no official in-repo podspec today; the pre-existing wrappers/swift/Package.swift was a local-build skeleton rather than a distributable package.

Approach

SPM cannot practically compile this C++ tree from source (CMake build, Bond codegen, vendored sqlite3/zlib, heavy platform conditionals), so:

  • C++ core + Obj-C wrappers ship as a prebuilt MATTelemetry.xcframework (.binaryTarget). The Obj-C wrappers compile into libmat.a on Apple.
  • The Swift layer (wrappers/swift/Sources/OneDSSwift) is compiled from source on top of the ObjCModule Clang module vended by the xcframework.

Platforms

Package.swift advertises iOS 12, Mac Catalyst 14, macOS 10.15, and visionOS 1. The xcframework bundles six library slices:

Slice Archs
ios-arm64 (device) arm64
ios-simulator arm64 + x86_64
macos-universal arm64 + x86_64
maccatalyst arm64 + x86_64
visionos-arm64 (device) arm64
visionos-simulator arm64

Framework links are gated per platform: IOKit is macOS-only; UIKit is iOS / Mac Catalyst / visionOS; CFNetwork / CoreFoundation / Foundation / Network / SystemConfiguration span all four.

What's here

  • Package.swift — distributable SPM manifest: binaryTarget xcframework + OneDSSwift source target, with per-platform linker settings and source exclusions driven by the availability manifest.
  • tools/apple/build-xcframework.sh — builds static libmat.a slices via build-ios.sh, fattens simulator / Catalyst / macOS archs with lipo, and assembles MATTelemetry.xcframework with xcodebuild -create-xcframework. Forces -DBUILD_SHARED_LIBS=OFF -DBUILD_OBJC_WRAPPER=YES, appended after caller CMAKE_OPTS.
  • build-ios.sh — gained a MATTELEMETRY_SKIP_PACKAGE=1 opt-out so per-slice xcframework builds skip the expensive make package step, plus an explicit error for unsupported Apple platform names.
  • tools/apple/module.modulemap + MATTelemetry-umbrella.h — vend the ObjCModule Clang module; optional-module imports (e.g. ODWPrivacyGuard.h) are appended only when those modules are actually built into the binary.
  • tools/apple/MATTelemetryAvailability.json — generated by the xcframework build from both module-directory presence and the effective -DBUILD_PRIVACYGUARD / -DBUILD_SANITIZER, then read by Package.swift so Swift source exclusions match the binary. Only copied back into the repo under CI or explicit opt-in (MATTELEMETRY_UPDATE_PACKAGE_AVAILABILITY=1), so local builds don't dirty the tree.
  • .github/workflows/spm-release.yml — on a published vX.Y.Z.W release: build the xcframework on a macOS runner, upload it to the Release, pin the binaryTarget url:+checksum:, validate the declared Apple platforms via swift package dump-package, and push a 3-component SemVer tag (X.Y.Z) that SPM can resolve. The tag step is idempotent — it skips if the SemVer tag already exists.
  • tools/apple/README.md — approach, build / consume, release wiring, and remaining TODOs.

Validation performed on macOS

  • tools/apple/build-xcframework.sh release succeeded and produced all six slices (ios-arm64, ios-arm64_x86_64-simulator, macos-arm64_x86_64, Mac Catalyst, visionOS device + simulator).
  • swift build succeeded for macOS host consumption.
  • xcodebuild -scheme OneDSSwift -destination 'generic/platform=iOS Simulator' build succeeded.
  • Obj-C module / static-link smoke tests built and ran on both the iOS Simulator and macOS against the built xcframework.
  • swift package dump-package reports all four platforms (iOS, Mac Catalyst, macOS, visionOS).

Consume after a release

.package(url: "https://github.com/microsoft/cpp_client_telemetry.git", from: "3.10.161")

Remaining TODOs

  • Code-sign the xcframework before distribution.
  • Exercise the release workflow end-to-end on an actual published release.
  • Decide where the root Package.swift lives long-term, since it makes the repository an SPM package.

Companion to the official vcpkg port (for C++ consumers): SPM serves Apple app developers, and the two are complementary.

bmehta001 and others added 4 commits June 18, 2026 01:54
First-pass scaffold to support Swift Package Manager on Apple platforms (the
successor to CocoaPods, whose trunk goes read-only Dec 2 2026; there is no
official in-repo podspec today).

SPM cannot practically compile the C++ tree (CMake/Bond/sqlite/zlib/platform
conditionals), so the compiled C++ core + Obj-C wrappers ship as a prebuilt
MATTelemetry.xcframework (.binaryTarget) and the thin Swift layer
(wrappers/swift/Sources/OneDSSwift) is compiled from source on top of the
Obj-C module the xcframework vends.

- Package.swift (root): binaryTarget (xcframework) + OneDSSwift source target;
  documents the path: -> url:+checksum: switch for releases.
- tools/apple/build-xcframework.sh: per-slice static libmat.a via build-ios.sh
  (iOS device + simulator), lipo, then xcodebuild -create-xcframework; emits a
  zip + SPM checksum.
- tools/apple/module.modulemap + MATTelemetry-umbrella.h: vend the `ObjCModule`
  Clang module the existing Swift sources already import.
- tools/apple/README.md: approach, build/consume steps, release wiring, and the
  macOS-validation TODOs (macOS/Catalyst slices, conditional modules, header
  flattening, signing).

NOT yet validated on macOS -- needs a mac with Xcode to run the build and adjust
the static-lib path / header layout.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds .github/workflows/spm-release.yml: on a published 4-component release
(vX.Y.Z.W), a macOS-runner job builds MATTelemetry.xcframework, uploads it to
the Release, computes the SPM checksum, rewrites the Package.swift binaryTarget
from path: to url:+checksum:, and pushes a 3-component SemVer tag (X.Y.Z) that
Swift Package Manager can resolve (the SDK's own 4-component tags are not valid
SemVer, so SPM ignores them).

Also documents the parallel-tag consumption (`from: "3.10.161"`) and the release
flow in tools/apple/README.md. Mirrors the vcpkg-release-bump pattern.

NOT yet validated -- needs the prototype merged (so Package.swift exists at the
release tag) and a macOS runner; the build script itself still needs a first
run on a mac.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy objc_begin/end support headers into the flattened xcframework Headers directory and mirror the existing Swift wrapper optional-module source exclusions in the root package manifest.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Avoid vending private wrapper headers from the flattened MATTelemetry.xcframework Headers directory, which otherwise triggers incomplete umbrella warnings when ObjCModule is imported.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@bmehta001 bmehta001 marked this pull request as ready for review June 18, 2026 22:29
@bmehta001 bmehta001 requested a review from a team as a code owner June 18, 2026 22:29
@bmehta001 bmehta001 requested a review from Copilot June 18, 2026 22:30
@bmehta001 bmehta001 self-assigned this Jun 18, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR prototypes distributing the 1DS C++ SDK to Apple developers via Swift Package Manager by shipping the C++ core + Obj-C wrappers as a prebuilt MATTelemetry.xcframework binary target, with the Swift wrapper layer (OneDSSwift) compiled from source on top.

Changes:

  • Add a distributable root Package.swift using an SPM binaryTarget plus the existing Swift sources.
  • Add Apple tooling to build and package MATTelemetry.xcframework (modulemap + umbrella header + build script).
  • Add a GitHub Actions workflow to build/upload the xcframework on release and publish an SPM-resolvable SemVer tag.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
Package.swift New root SPM manifest for distributing OneDSSwift backed by a binary xcframework.
tools/apple/build-xcframework.sh Script to build per-slice libmat.a, assemble an xcframework, zip it, and compute SPM checksum.
tools/apple/module.modulemap Declares the ObjCModule Clang module for Swift to import from the xcframework.
tools/apple/MATTelemetry-umbrella.h Umbrella header listing Obj-C wrapper headers to export via the modulemap.
tools/apple/README.md Documentation of the approach, local build steps, and release wiring/TODOs.
.github/workflows/spm-release.yml Release automation: build xcframework, upload to Release, rewrite manifest to url+checksum, and tag for SPM.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Package.swift
Comment thread Package.swift Outdated
Comment thread tools/apple/build-xcframework.sh
Comment thread tools/apple/MATTelemetry-umbrella.h Outdated
bmehta001 and others added 2 commits June 18, 2026 17:47
Generate the ObjC umbrella and availability manifest from the modules built into the xcframework, read that manifest from Package.swift, and guard Swift type aliases for optional modules.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Drive Swift source exclusions and ObjC umbrella optional imports from the modules actually built into MATTelemetry.xcframework, remove unsupported macOS package advertising, and add Apple system linker settings for the static binary target.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Comment thread Package.swift Outdated
Comment thread tools/apple/build-xcframework.sh Outdated
Remove macOS package advertising until a macOS slice exists, add iOS linker settings for the static xcframework, and avoid repeating build tool setup for each slice.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Comment thread tools/apple/README.md Outdated
Comment thread tools/apple/build-xcframework.sh Outdated
Comment thread tools/apple/build-xcframework.sh Outdated
Mark the prototype as validated, document remaining gaps, and make optional module availability respect explicit BUILD_PRIVACYGUARD/BUILD_SANITIZER settings passed through CMAKE_OPTS.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@bmehta001 bmehta001 requested a review from Copilot June 19, 2026 00:27
@bmehta001

Copy link
Copy Markdown
Contributor Author

Copilot round addressed (head 0edd5f11). The macOS session pushed fixes for all 5 outstanding Copilot threads; I verified each against the source at 0edd5f11 and resolved the threads:

  • README.md / build-xcframework.sh validation status — README now reads "Status: validated prototype"; the script header notes it's validated on macOS for iOS device + simulator slices (macOS/Catalyst/visionOS still TODO). Doc and PR description are aligned.
  • Optional-module availability vs BUILD_*build-xcframework.sh now has a cmake_option_enabled() helper; MATTelemetryAvailability.json reflects both module-directory presence and the effective -DBUILD_PRIVACYGUARD / -DBUILD_SANITIZER from CMAKE_OPTS, and the umbrella #imports honor the same flags.
  • IOKit linked unconditionallyPackage.swift no longer links IOKit; all frameworks (incl. UIKit) are gated .when(platforms: [.iOS]), and the .macOS platform was dropped from this prototype.
  • Availability JSON dirtying the working tree — the copy back into tools/apple/MATTelemetryAvailability.json is now gated to CI (GITHUB_ACTIONS=true) or an explicit MATTELEMETRY_UPDATE_PACKAGE_AVAILABILITY=1 opt-in, so local builds no longer dirty the tree.

Re-requested copilot-pull-request-reviewer for a fresh pass on 0edd5f11.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Build a universal macOS libmat archive alongside the iOS device and simulator slices, advertise macOS in the root Swift package, and document the expanded validation story.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

Comment thread .github/workflows/spm-release.yml
Comment thread tools/apple/build-xcframework.sh Outdated
Comment thread Package.swift
Comment thread Package.swift Outdated
Teach the Apple build path to produce macabi archives, include a fat Catalyst variant in MATTelemetry.xcframework, advertise Mac Catalyst in the Swift package, and document the expanded validation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove a drifting line-number reference and keep section headings sequential.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Comment thread tools/apple/build-xcframework.sh Outdated
Comment thread tools/apple/build-xcframework.sh Outdated
Build each Apple slice from a clean CMake out directory, while preserving the build-tools marker, and restrict xcframework slice builds to the libmat archive target inputs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Comment thread build-ios.sh Outdated
Use POSIX '=' for the MATTELEMETRY_SKIP_PACKAGE check in build-ios.sh.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Comment thread CMakeLists.txt Outdated
Comment thread CMakeLists.txt Outdated
Addresses Copilot review on microsoft#1486 (CMakeLists.txt:70, :108): the new
Apple-slice platform conditionals used unquoted ${IOS_PLAT} (and the
adjacent ${IOS_ARCH}) inside if()/elseif(). If the variable is ever
empty/undefined, `if(${IOS_PLAT} STREQUAL "...")` expands to
`if( STREQUAL "...")`, which is a hard CMake parse error that aborts
configuration. Quoting the expansion ("${IOS_PLAT}") keeps the compare
well-formed (empty -> false) and matches the existing
`if("${MAC_ARCH}" STREQUAL ...)` idiom already used in this file.

Quoted all 7 ${IOS_PLAT} comparisons (lines 57/60/66/70/74/78/104) and
the 3 ${IOS_ARCH} comparisons (84/88/92). ${CMAKE_SYSTEM_NAME} (line
313) is left as-is: it is always defined by CMake, so it cannot trigger
the empty-expansion parse error.

Verified with a minimal CMake repro: the quoted form configures cleanly
with the variable undefined and still matches when set, whereas the old
unquoted form errors out at configure time.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.

The Obj-C wrapper module vended by MATTelemetry.xcframework (and the
local wrappers/swift package) was named `ObjCModule` -- a generic name
that consumers `import`. Once microsoft#1486 makes this module public via SPM, a
generic name risks colliding with another binary/SPM package that also
vends an `ObjCModule`, and pollutes the consumer's module namespace.
Rename it to the namespaced `MATTelemetryObjC` while the name is still
internal (the wrappers/swift package was never distributed), so it is
collision-safe before first release.

Renamed consistently across both build paths so the same Swift sources
compile against both modulemaps:
- tools/apple/module.modulemap (xcframework) and
  wrappers/swift/Modules/module.modulemap (local): `module MATTelemetryObjC`.
- All 13 `import ObjCModule` -> `import MATTelemetryObjC` in
  wrappers/swift/Sources/OneDSSwift/*.swift.
- Bridging header file renamed
  ObjCModule-Bridging-Header.h -> MATTelemetryObjC-Bridging-Header.h
  and its modulemap reference updated.
- Comments/docs (Package.swift, build-xcframework.sh, tools/apple/README.md,
  examples/swift/README.md) updated.

Pure rename; no behavioral change. Needs a macOS `swift build` (local
wrappers path) + xcframework SPM build to confirm both paths still
resolve the module -- I cannot run those on Windows.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 24 changed files in this pull request and generated 1 comment.

/// Contains alias for the types declared in the ObjC header files to make them available
/// as part of the swift package module.
/// To avoid clients not have to import ObjCModule explicitly.
/// To avoid clients not have to import MATTelemetryObjC explicitly.
The SPM xcframework links the platform's libsqlite3/libz (Package.swift
.linkedLibrary) rather than bundling them. Document why: bundling a
private static sqlite3 would collide with any consumer that also uses
SQLite (Core Data/GRDB/FMDB) -> duplicate symbols / two-instance state;
system linking yields one shared copy. Notes the contrast with vcpkg
(uses vcpkg packages) and Android (bundles, since the NDK has no system
copy).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 24 changed files in this pull request and generated 3 comments.

Comment thread Package.swift
Comment on lines +68 to +72
excludedSources.append(contentsOf: [
"CommonDataContext.swift",
"PrivacyGuard.swift",
"PrivacyGuardInitConfig.swift",
])
/// Contains alias for the types declared in the ObjC header files to make them available
/// as part of the swift package module.
/// To avoid clients not have to import ObjCModule explicitly.
/// To avoid clients not have to import MATTelemetryObjC explicitly.
Comment on lines +136 to +139
cd "$ROOT"
rm -f CMakeCache.txt *.cmake
rm -rf out
MATTELEMETRY_SKIP_PACKAGE=1 ./build-ios.sh "$CONFIG" "$arch" "$plat"
bmehta001 and others added 2 commits June 19, 2026 14:29
Every other PII-tagged public API in OneDSSwift (EventProperties,
Logger, LogManager) already uses the `PIIKind` typealias; only
SemanticContext.setUserID exposed the raw Obj-C `ODWPiiKind` in its
signature/default. Switch it to `PIIKind` (same underlying type via the
ObjCTypes.swift typealias) so consumers of the Swift API never need to
reference the MATTelemetryObjC module name. Pure source-level alias
swap; no behavioral change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
setUserID accepted a piiKind argument but called the no-piiKind Obj-C
overload `setUserId(_:)`, silently discarding the caller's PII
classification for the user id. ODWSemanticContext exposes a
`setUserId:piiKind:` overload (wrappers/obj-c/ODWSemanticContext.h:47-48)
for exactly this. Route the argument through so the requested PII tag is
actually applied.

Privacy-relevant behavioral fix. Needs a macOS `swift build` to confirm
the bridged selector (`setUserId(_:piiKind:)`); cannot run Swift on the
Windows session.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 24 changed files in this pull request and generated 3 comments.

Comment on lines +52 to +55
- withPiiKind: A PIIKind of the userID. Set it to PiiKind_None t odenote it as non-PII.
- Note: Default value is `ODWPiiKind.identity`.
- Note: Default value is `PIIKind.identity`.
*/
public func setUserID(_ userID: String, withPiiKind piiKind: ODWPiiKind = ODWPiiKind.identity) {
odwSemanticContext.setUserId(userID)
public func setUserID(_ userID: String, withPiiKind piiKind: PIIKind = PIIKind.identity) {
Comment on lines 6 to 9
/// Contains alias for the types declared in the ObjC header files to make them available
/// as part of the swift package module.
/// To avoid clients not have to import ObjCModule explicitly.
/// To avoid clients not have to import MATTelemetryObjC explicitly.
/// Important: Due to objc->swift conventions, Type name is removed, so ODWPiiKindGenericData would be accessed as .genericData in swift.
Comment thread tools/apple/README.md Outdated
Comment on lines +3 to +4
This packages the 1DS C++ SDK for Apple developers through Swift Package Manager
(SPM), using a prebuilt xcframework for the C++ core plus Obj-C wrappers and
Keep CommonDataContext available without PrivacyGuard, tighten Swift docs, and scope xcframework slice cleanup to the output directory.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants