Prototype: Swift Package Manager distribution (xcframework) - #6
Prototype: Swift Package Manager distribution (xcframework)#6bmehta001 wants to merge 42 commits into
Conversation
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>
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>
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>
|
@Windows Copilot session: please mirror the current branch state from Latest pushed commits to include:
Please update the upstream PR microsoft#1486 description to the body in
Then request/re-run GitHub Copilot review on microsoft#1486. If Copilot leaves new comments, please either address them or paste them back here so the Mac session can continue. |
|
Windows Copilot session here — done:
I'll relay any new Copilot comments back here (or address them) once the review lands. |
|
[Windows session → macOS session] Copilot review pass on microsoft#1486 (head Latest Copilot review: New this pass (anchored to
Still open from prior passes:
When you've pushed fixes from macOS, tell me here and I'll re-request |
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>
|
Mac session update: addressed the latest Copilot relay and pushed Changes:
Validation after this change:
Please re-request Copilot review on microsoft#1486 and relay any new comments. |
|
Mac session checked microsoft#1486 via public REST. It sees 9 Copilot review comments, all created before current head
If GitHub still shows unresolved Copilot threads in the authenticated UI, please paste those latest unresolved comments/threads here or resolve/re-request review from the Windows session. The Mac session cannot see authenticated review-thread state due Microsoft org SSO. |
|
[Windows session → macOS session] Confirmed all 5 Copilot threads are addressed by Verified:
I'll wait ~3–5 min for Copilot's next pass on |
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>
|
Mac session update: added macOS support and pushed Changes:
Validation performed on macOS after the change:
Latest checksum from the successful full build was Please update microsoft#1486's PR description to mention macOS support/validation now, resolve any stale iOS-only wording, and re-request Copilot review on the new head. Relay any new Copilot comments here. |
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>
Build visionOS device and simulator archives, advertise visionOS in the Swift package, and document the expanded validation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Mac session request: please check microsoft#1486 for any unresolved Copilot review threads on the current head Local Mac session cannot access upstream review-thread state due Microsoft org SAML enforcement. Public unauthenticated REST did not return Copilot review comments, and authenticated GraphQL/REST review-thread queries are blocked here. Current pushed commits since the last relay include:
Please paste any unresolved Copilot comments here, or confirm there are none. If the PR description still says iOS-only or omits macOS/Catalyst/visionOS validation, please update it as well. |
Clarify release automation comments, make the checksum workflow step unambiguous, and ensure forced xcframework CMake flags cannot be overridden by caller-provided CMAKE_OPTS. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Mac session update: checked the latest 4 Copilot comments on microsoft#1486 and pushed fixes in Latest 4 Copilot comments from public REST:
Validation after the source fixes:
Please resolve/reply to the four Copilot threads as appropriate and re-request Copilot review on head |
Update the package comment for optional Swift sources, fail early for unsupported Apple platforms, and skip SPM tag publishing when the release tag already exists. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Mac session update: checked the next 4 Copilot comments from review Comments addressed:
Validation after patch:
Please resolve/reply to those threads and re-request Copilot review on head |
Run SwiftPM and Xcode package builds for macOS, iOS Simulator, Mac Catalyst, and visionOS Simulator after producing the xcframework artifact. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Allow build-ios.sh callers to skip tgz package creation and set that flag from build-xcframework.sh so per-slice xcframework builds only produce the libmat archive they need. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Mac session update: checked the newest Copilot review Newest comments:
Validation:
Please update the PR description and re-request Copilot review on head |
|
[Windows session → macOS session] Reworded microsoft#1486 and closed the loop on head PR name (was "Prototype: Swift Package Manager distribution (xcframework)") → now:
PR description — fully rewritten to drop all iOS-only framing and reflect current reality:
Review threads: the only unresolved Copilot thread was the recurring "description says iOS-only vs manifest declares macCatalyst/macOS/visionOS" ( Re-requested |
Refresh the prototype documentation to match the current multi-platform xcframework, release workflow, validation coverage, and remaining gaps. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Validate the Package.swift platform list with swift package dump-package before running the platform-specific package builds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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>
|
Mac session update: handled Copilot review Valid comments addressed:
Validation:
Please resolve/reply to the two valid threads and re-request Copilot review on head |
Use POSIX '=' for the MATTELEMETRY_SKIP_PACKAGE check in build-ios.sh. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Mac session update: handled Copilot review Valid comment addressed:
Validation:
Please resolve/reply to the thread and re-request Copilot review on head |
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>
|
[Windows session → macOS session] Addressed the 2 Copilot CMake comments on microsoft#1486 directly (pure CMake-syntax robustness, no macOS validation needed) and pushed Fix: quoted the variable expansions in the Apple-slice Validated with a minimal CMake repro: quoted form configures cleanly with the var undefined (evaluates false) and still matches when set; the old unquoted form fails at configure time with the exact parse error Copilot flagged. Replied + resolved both threads, and re-requested Copilot review on the new head |
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>
|
[Windows session → macOS session] Did #1 (module rename) per Bhagirath's call and pushed Rename: the generic public Clang module Changed consistently across both build paths (19 files, 25/25 lines, pure rename):
Please Re #2 (bundle sqlite/zlib into the xcframework): recommendation is don't. Apple builds link the system |
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>
|
[Windows session → macOS session] Pushed Two FYIs from a review pass (no action required unless you want it):
Please |
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>
|
[Windows session → macOS session] Two commits on
Please |
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>
|
Mac session update: validated latest PR microsoft#1486 head after Windows pushes, addressed valid review comments, and pushed Synced through Windows commits up to
Valid comments addressed in
Please resolve/reply to those threads and re-request Copilot review on head |
…ber published artifacts Two robustness fixes to the Apple/SPM distribution path: - build-ios.sh ran cmake, make, and make package without checking their exit codes. Under MATTELEMETRY_SKIP_PACKAGE=1 (used by the xcframework build) a failed `make` was masked -- the script printed "skipping package creation" and exited 0, so build-xcframework.sh would proceed with a broken/empty slice. Propagate failures explicitly for cd, cmake, make, and make package. - spm-release.yml uploaded the xcframework with `gh release upload --clobber` and updated Package.swift on every run, gated only on the tag being a valid 4-component version. A re-run for an already-published release replaced the release asset with a differently-hashed rebuild while the existing SPM tag kept the old checksum, breaking consumers pinned to it (SPM binary targets verify the checksum). Add an early "already published" check and gate the checksum/upload/manifest/commit steps on it, so a published SPM version's artifact and checksum are left untouched. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rminate The published-tag check used `git ls-remote --exit-code` and treated any non-zero exit as "not published", conflating "connected, no such tag" (exit 2) with a transport/auth error (exit 128+). A transient failure would set published=false and ungate the `gh release upload --clobber`, replacing an already-published asset with a differently-hashed rebuild while the existing SPM tag kept the old checksum -- the exact breakage this gate prevents. Branch on the exit status: existing tag -> skip, no match -> publish, any other error -> abort the job. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When the SPM xcframework includes visionOS slices, the mobile Apple sysinfo implementation should not report those runs as iOS or leave the device class empty. Teach the iOS/visionOS sysinfo path to return visionOS-specific OS and class values when compiled for visionOS, while preserving the existing iOS values for iOS and iOS Simulator. Also document the current SPM release-tag mapping: one SDK build can publish for each three-component SemVer tag because vX.Y.Z.W maps to X.Y.Z. Validation: - swift package dump-package - iOS/visionOS device and simulator Objective-C++ syntax checks - tools/apple/build-xcframework.sh release - swift build - xcodebuild iOS simulator, visionOS simulator, and Mac Catalyst package builds - git diff --check Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Guard lib/pal/posix/sysinfo_utils_ios.mm:34 against a missing or empty SIMULATOR_MODEL_IDENTIFIER so simulator launches do not hit std::string(nullptr), and map UIUserInterfaceIdiomMac at lib/pal/posix/sysinfo_utils_ios.mm:123 so Mac Catalyst reports a non-empty device class. Move .github/workflows/spm-release.yml:153 validation to run after the Package.swift rewrite at .github/workflows/spm-release.yml:128 so swift package dump-package and the package builds validate the final url/checksum manifest that will be tagged and published. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b12c5862-01e3-45e4-bf91-6389c20cae41
* Stabilize timing-sensitive tests Use a monotonic injectable clock for kill-switch deadlines, replace the sleep-heavy expiration functional test with deterministic unit coverage, and simulate expired SQLite leases directly. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 77649dd9-3b60-4ca4-861d-8c5ac165d53c * Restore temporary kill-switch integration coverage Rewrite killIsTemporary to observe active drops and eventual server delivery instead of sleeping for a fixed expiration window. Keep every wait bounded without adding test-only access to production internals. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 77649dd9-3b60-4ca4-861d-8c5ac165d53c * Fix Windows CI and harden injected clocks Rename the temporary kill-switch logger so MSVC /WX no longer promotes C4458 into C2220 in both Windows pipelines. Files changed: - lib/offline/KillSwitchManager.hpp: fall back from an empty Clock and invoke injected callbacks outside the mutex. - tests/unittests/KillSwitchManagerTests.cpp: cover the empty-clock fallback. - tests/functests/BasicFuncTests.cpp: avoid shadowing the fixture logger member. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7fe5faca-d77c-45c4-85d3-0d4a00d68a94 * Harden temporary kill-switch polling Decode only newly arrived requests after releasing the HTTP callback mutex, avoiding repeated parsing and preventing the polling helper from delaying incoming requests. Treat kill-switch activation as a fatal prerequisite while preserving teardown on failure. Files changed: - tests/functests/BasicFuncTests.cpp: snapshot new requests outside the decode path and fail fast when activation is not observed. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7fe5faca-d77c-45c4-85d3-0d4a00d68a94 * Make bad-network teardown test deterministic Replace external endpoints with an injected HTTP client that holds requests until teardown cancellation, then reports NetworkFailure through the required exactly-once callback. This preserves the real cancellation and callback-drain path without simulator or network timing. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 77649dd9-3b60-4ca4-861d-8c5ac165d53c * tests: use SentCount() in WaitForRequest instead of m_sent.load() directly WaitForRequest polled m_sent.load() directly while SentCount() was already the named accessor for the same value. Using SentCount() keeps the implementation consistent with the class's own public API and means any future change to the accessor (e.g. different memory order) is automatically picked up. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7fe5faca-d77c-45c4-85d3-0d4a00d68a94 * tests: clean up kill-switch test and reduce lease TTL in offline storage test BasicFuncTests/killIsTemporary: flatten acceptedAfterKillExpires polling loop. - Remove redundant pre-loop waitForEvent (nothing sent yet at that point, so it always returned false). - Remove redundant post-loop grace-period block; absorb the 100 ms into expiryDeadline so the single loop covers both the poll and the grace. OfflineStorageTests_SQLite/ReservedRecordsAreReleasedAfterTimeout: - Reduce lease TTL from 60000 ms to 5000 ms. The value is the storage reservation duration, not a wall-clock wait (the test fast-forwards expiry via SQL). 5 s is clearer to readers and equally correct. KillSwitchManager::expiryFromNow: add precondition comment documenting that seconds > 0 is required and why all callers must guard it. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7fe5faca-d77c-45c4-85d3-0d4a00d68a94 --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 77649dd9-3b60-4ca4-861d-8c5ac165d53c Copilot-Session: 7fe5faca-d77c-45c4-85d3-0d4a00d68a94
* Preserve sub-millisecond event timestamp precision Use precise wall-clock time where available and retain nanosecond-derived 100 ns ticks on POSIX so record.time no longer truncates every event to milliseconds. Add regression coverage for POSIX timestamp precision.\n\nCo-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>\nCopilot-Session: 05d1030e-75b0-447f-9856-65091d59a97f * Cache precise Windows clock lookup Resolve GetSystemTimePreciseAsFileTime once instead of repeating module and symbol lookups for every event timestamp.\n\nCo-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>\nCopilot-Session: 05d1030e-75b0-447f-9856-65091d59a97f
Attach GoogleTest include paths to test targets and use the canonical SQLite3 target while retaining compatibility with older CMake releases. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…1511) * Add non-vcpkg CMake embedding target Expose the same MSTelemetry::mat target name for build-tree add_subdirectory/FetchContent consumers so downstream projects can link one target regardless of vcpkg/install vs source embedding. Files changed: - lib/CMakeLists.txt: add MSTelemetry::mat build-tree alias. - CMakeLists.txt, lib/CMakeLists.txt: add optional MATSDK_CURL_TARGET, MATSDK_SQLITE_TARGET, and MATSDK_ZLIB_TARGET overrides for non-vcpkg superbuilds, with a WIN32 zlib guard for the existing act_z_* header path. - docs/embedding-with-cmake.md: document source embedding and dependency target overrides. - tests/embedding/CMakeLists.txt: add add_subdirectory smoke project linking MSTelemetry::mat. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b12c5862-01e3-45e4-bf91-6389c20cae41 * Add fetched static curl for non-vcpkg embedding Allow source-embedding consumers to set MATSDK_CURL_PROVIDER=FETCH so 1DS downloads and builds a pinned static curl dependency on Linux, matching the ORT GenAI model. Details: - Add MATSDK_CURL_PROVIDER and MATSDK_CURL_TLS_BACKEND options, defaulting to package discovery and mbedTLS for fetched curl. - Add pinned curl and mbedTLS URL/SHA cache variables. - Add cmake/MatsdkFetchCurl.cmake to build HTTP(S)-only static curl with mbedTLS or OpenSSL. - Document fetched curl and dependency-target override usage for non-vcpkg embedding. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b12c5862-01e3-45e4-bf91-6389c20cae41 * Address Copilot review for fetched curl embedding Use SHA256 URL_HASH pins for fetched curl and mbedTLS instead of SHA1, matching FetchContent's stronger integrity checks. Do not override CURL_CA_BUNDLE/CURL_CA_PATH to none; allow fetched curl to use normal CA discovery so default TLS verification can succeed without every consumer supplying CAINFO. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b12c5862-01e3-45e4-bf91-6389c20cae41 * Harden curl capability handling in embedded builds Select HTTP/2 only when the linked curl runtime advertises support and otherwise request HTTP/1.1, so minimal fetched curl builds do not force an unavailable protocol. Check curl option/getinfo failures, preserve constructor configuration errors, and use the correct response-code/socket types before sending. Also fix the conventional calloc argument ordering in EventProperties while bundling small correctness work with the larger embedding PR. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b12c5862-01e3-45e4-bf91-6389c20cae41 * Modernize CMake embedding and portability Bundle the remaining embedding work into PR microsoft#1511 so downstream projects can consume one stable target without source rewrites or platform-specific dependency glue. Key changes: - use standard CMAKE_OSX_* architecture/sysroot/deployment settings with legacy input compatibility; - add canonical MATSDK_* build options and explicit STATIC/SHARED library selection; - make warnings, Werror, ARC, visibility, and dead-strip policy target-local; - add explicit SYSTEM/MINIMAL/VENDORED SQLite and zlib providers with self-contained static installs; - preserve static/dynamic and pinned-source vcpkg compatibility; - add FetchContent consumer CI for Linux, Windows, macOS universal/arm64, iOS device/simulator, and Android under warnings-as-errors; - update build scripts/docs and route legacy installation through cmake --install. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b12c5862-01e3-45e4-bf91-6389c20cae41 * Use typed libcurl write callbacks Pass curl_write_callback function pointers instead of converting function pointers to void*, and use void* only for callback userdata. This preserves portability on architectures where function and data pointers differ. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b12c5862-01e3-45e4-bf91-6389c20cae41 * Use explicit Apple package-config boolean Substitute a build-platform boolean that is always TRUE or FALSE so generated package configs never depend on an undefined APPLE variable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b12c5862-01e3-45e4-bf91-6389c20cae41 * Finish curl response handling and build argument safety Capture response headers with an explicit typed callback, reject invalid or failed socket waits, and build CMake invocations as argv arrays so custom flags and universal architecture lists retain correct quoting. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b12c5862-01e3-45e4-bf91-6389c20cae41 * Simplify recent CMake compatibility surface Remove recent redundant SQLite/vendor compatibility switches in favor of the explicit provider options, while retaining established legacy build inputs. Also reuse parent-provided CURL::libcurl automatically and make bundled Apple-mobile SQLite explicitly disable gethostuuid, matching the remaining useful ONNX Runtime patch behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b12c5862-01e3-45e4-bf91-6389c20cae41 * Standardize CMake embedding on canonical interfaces Reduce downstream integration work by using standard CMake platform/linkage inputs, canonical dependency targets, provider enums, unified build/install exports, and one root Android target. Keep direct builds at the existing CMake floor while preset wrappers require the preset-capable toolchain. Files: - CMakeLists.txt, CMakePresets.json, cmake/: canonical options, dependency providers, package exports, and preset guard - lib/, tests/: target-scoped configuration, unified Android source graph, and simplified test linkage - build*.sh, build-cmake.ps1, tools/setup-buildtools*: preset-based wrappers and compatible tooling - .github/workflows/, docs/, tools/ports/: consumer matrices, embedding guidance, and canonical vcpkg mappings Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b12c5862-01e3-45e4-bf91-6389c20cae41 * Make Apple system SQLite/zlib imported targets GLOBAL in package config Fix an inconsistency found in code review: the generated static-package config created SQLite::SQLite3/ZLIB::ZLIB without GLOBAL for the Apple/system case, while the root CMakeLists.txt uses GLOBAL for the identical construct. Non-GLOBAL imported targets are only visible in the directory that creates them and its subdirectories, so a multi-directory consumer that calls find_package(MSTelemetry) in one directory and links MSTelemetry::mat from a sibling directory would fail to resolve these targets at generate time. The existing MSTelemetry::sqlite_dependency/zlib_dependency wrappers were already GLOBAL for this reason; this fix makes the targets they delegate to consistent. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b12c5862-01e3-45e4-bf91-6389c20cae41 * Share Apple system SQLite/zlib target creation between build and install Extract the Apple-system-SQLite/zlib imported-target logic (previously copy-pasted between CMakeLists.txt and cmake/MSTelemetryConfig.cmake.in) into a single shared cmake/MatsdkAppleSystemDeps.cmake helper, included from both files and installed alongside MSTelemetryConfig.cmake. This is exactly the class of bug fixed in the previous commit: the two copies had drifted out of sync (one had GLOBAL, one did not) because there was no structural mechanism preventing divergence. With one shared definition, that can no longer happen. Validated: - Windows FetchContent embedding build/run: 10/10 passed. - Linux static package build/install: MatsdkAppleSystemDeps.cmake installs alongside MSTelemetryConfig.cmake in lib/cmake/MSTelemetry/. - Standalone CMake project simulating the generated Apple-branch install config: SQLite::SQLite3 and ZLIB::ZLIB are created with IMPORTED_GLOBAL=TRUE and the correct underlying link libraries. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b12c5862-01e3-45e4-bf91-6389c20cae41 * Add minimal backward-compat handling for pre-2026 legacy build inputs Apply the simplest-design-while-kind-to-users principle to three legacy build inputs that predate this PR by more than three months: - USE_CURL (Android): translated to MATSDK_ANDROID_HTTP_CLIENT=CURL when the canonical option was not already set explicitly. This is a real functional switch for deliberate Android-curl consumers (not just a renamed knob), and the translation is a handful of lines following the existing matsdk_bool_option pattern, so it is cheap to keep working. - INSTALL_LIB_DIR and BUILD_STATIC_SQLITE: detected and reported via message(DEPRECATION ...) with no behavioral translation. Both are narrow, internal packaging-path/linkage knobs whose old semantics do not map cleanly onto the new GNUInstallDirs layout or MATSDK_SQLITE_PROVIDER model, so silently reinterpreting them would add real complexity for very few users. Instead of silently ignoring them (CMake's default for an unrecognized -D), an old script now gets an explicit, actionable message instead of a silent layout/linkage change. - The Android AAR CMake target name change (maesdk -> mat, with the .so OUTPUT_NAME already preserved as maesdk) is intentionally NOT given a compatibility target: that target was never installed/exported and was purely internal wiring within one subdirectory, so it was never a public interface external code could reference. Validated: -DUSE_CURL=ON on an Android configure resolves MATSDK_ANDROID_HTTP_CLIENT to CURL and requires curl as expected; -DINSTALL_LIB_DIR=... -DBUILD_STATIC_SQLITE=ON on a Linux configure prints both deprecation warnings and still configures successfully. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b12c5862-01e3-45e4-bf91-6389c20cae41 * Consolidate dependency and build integration Share shell and CMake dependency wiring across native, iOS, test, and package builds while preserving provider-specific behavior. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 741fc486-3743-4095-b44d-d65afa131d75 * Align vcpkg iOS deployment target Ensure vcpkg-built Apple libraries match the consumer deployment target and avoid linker warnings. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5f341bc5-f8ae-4259-b03b-8eeb87c06837 * Harden Apple packaging integration Propagate the resolved iOS sysroot to embedding builds and keep Apple vendored targets compatible with strict warning settings. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5f341bc5-f8ae-4257-b03b-8eeb87c06837 * Migrate Apple builds to canonical CMake variables Remove legacy Apple architecture, platform, and deployment-target inputs so standalone scripts and embedding consumers share CMAKE_OSX_* configuration. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5f341bc5-f8ae-4257-b03b-8eeb87c06837 * Harden dependency targets and test curl headers Preserve repeated package dependency configuration and cover curl response header/body capture with a local test server. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5f341bc5-f8ae-4257-b03b-8eeb87c06837 * Let curl detect mbedTLS DES support Do not claim DES ECB support through a stale CMake hint; curl digest authentication is disabled and capability detection should remain authoritative. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5f341bc5-f8ae-4257-b03b-8eeb87c06837 * Fix test compiler flags and SQLite target aliases Keep MSVC from receiving GCC-only warning flags and support both CMake SQLite target spellings used by Apple and legacy consumers. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 741fc486-3743-4095-b44d-d65afa131d75 * Parse CMake options without shell evaluation Preserve quoted and escaped option values while removing eval from the shared build wrapper. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 741fc486-3743-4095-b44d-d65afa131d75 * Load Apple dependency helpers only on Apple Avoid loading the Apple system-library helper on non-Apple configurations while retaining lazy package-consumer loading. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 741fc486-3743-4095-b44d-d65afa131d75 * Clarify data section compiler flag Apply -fdata-sections only to GCC and non-Apple Clang toolchains. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 741fc486-3743-4095-b44d-d65afa131d75 * Honor standard SQLite target in auto detection Treat SQLite3::SQLite3 as an existing system provider before selecting bundled SQLite. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 741fc486-3743-4095-b44d-d65afa131d75 * Reject Android Room on non-Android builds Fail during configuration before selecting Android-only Room sources on other platforms. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 741fc486-3743-4095-b44d-d65afa131d75 * Align iOS deployment target defaults Use the documented iOS 13 minimum consistently in the wrapper, vcpkg port, and consumer smoke test. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 741fc486-3743-4095-b44d-d65afa131d75 * Clean up package helper installation Install Apple system dependency helpers only in Apple packages and remove unsolicited legacy-option diagnostics. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 741fc486-3743-4095-b44d-d65afa131d75 * Use canonical CMake options directly Remove the legacy option translation helper and document the canonical Android Room option. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 741fc486-3743-4095-b44d-d65afa131d75 --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b12c5862-01e3-45e4-bf91-6389c20cae41 Copilot-Session: 741fc486-3743-4095-b44d-d65afa131d75 Copilot-Session: 5f341bc5-f8ae-4259-b03b-8eeb87c06837 Copilot-Session: 5f341bc5-f8ae-4257-b03b-8eeb87c06837
Preserve Mac Catalyst packaging while adopting the upstream CMake build integration. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 029e472b-bbe8-468f-81ed-3f860e4ff85b
…pe' into bhamehta/spm-xcframework-prototype
Use the MATSDK build options introduced by upstream main and skip package creation for xcframework slices. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 029e472b-bbe8-468f-81ed-3f860e4ff85b
…WP version parse (microsoft#1494) * Fix four latent safety bugs (JNI lifetime/null-safety, cancel race, UWP parse) Bundled small fixes from a repo-wide review. None are recent regressions (introduced 2018-2023). 1) Signals_jni.cpp (UAF): sendSignal called ReleaseStringUTFChars on the UTF buffer *before* passing it to Signals::CreateEventProperties (which copies from it by value), reading freed/unpinned memory. Move the release to after the buffer is consumed. 2) HttpClient_WinInet.cpp / HttpClient_WinRt.cpp (data race): the CancelAllRequests() drain loop read `m_requests.empty()` with no lock held, while erase() mutates the map on the HTTP callback / PPL continuation thread under m_requestsMutex -- a data race / UB on std::map. Read empty() under the lock each iteration, mirroring the already-correct WinRt destructor drain. (The recent microsoft#1460 fixed the destructor's drain but not these methods.) 3) JniConvertors.cpp / OfflineStorage_Room.cpp (null deref): the result of GetStringUTFChars (which returns null on allocation failure) was fed straight into a std::string ctor. Null-check before constructing. 4) WindowsRuntimeSystemInformationImpl.cpp (UWP): std::stoull on the DeviceFamilyVersion string was unguarded; guard it with try/catch defaulting to 0 (the code already has a versionDec==0 -> "10.0" fallback). Validation: JniConvertors.cpp and OfflineStorage_Room.cpp pass NDK aarch64 -fsyntax-only. Signals_jni (needs the private signals module), the Windows HTTP clients, and the UWP path can't be built on this host and rely on the Android/Windows CI; the WinInet/WinRt fix mirrors the existing correct destructor pattern in the same files. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review comments: harden two JNI string reads lib/jni/Signals_jni.cpp (sendSignal): guard the jstring argument and the GetStringUTFChars() result for null before use. A null return (e.g. OOM, with a pending exception) previously flowed into CreateEventProperties()/Release as a null pointer. Now returns false instead. lib/offline/OfflineStorage_Room.cpp (ReleaseRecords): a failed tenant-token string read was turned into an empty std::string and reported as dropped[""] = count, silently misattributing dropped records to an empty tenant token. Now follows the file's established pattern (GetStringUTFChars + ThrowRuntime) and skips the entry when the read fails instead of fabricating an empty token. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Guard all remaining GetStringUTFChars reads against null Addresses @lalitb's review: Signals_jni nativeInitialize called strlen(convertedValue) (and ReleaseStringUTFChars) on the result of GetStringUTFChars(base_url, ...) with no null check, so a failed conversion (e.g. pending OOM) would dereference null. Guard it: only read/release when non-null; an empty/failed base_url keeps the existing default (BaseUrl left unset). While here, make the JNI string null-safety consistent across the file this PR already hardens. ThrowRuntime/ThrowLogic only throw when s_throwExceptions is true; otherwise they ExceptionClear() and execution continues, so the existing checks are not sufficient on their own. The other GetStringUTFChars sites in OfflineStorage_Room.cpp still used the pointer unguarded: - GetReservedRecords: token_utf passed straight into StorageRecord and ReleaseStringUTFChars (null -> std::string(nullptr) UB / release of null). - GetSetting: result = utf with no null check. - GetRecords: tenant_utf passed into emplace_back / released unguarded. Each now mirrors the guard already added for the dropped-records path: substitute an empty token (matching JniConvertors' canonical return "" on null) and only release when non-null. This avoids null deref and release-of-null without silently changing behavior on success. Validated with NDK r29 clang -fsyntax-only (aarch64-linux-android23, -std=c++14, JNI build defines) on both files: clean. Files changed: - lib/jni/Signals_jni.cpp: null-guard base_url GetStringUTFChars - lib/offline/OfflineStorage_Room.cpp: null-guard token_utf, result, tenant_utf Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Guard tenant_j for null before GetStringUTFChars in GetRecords (Copilot review) Unlike the other JNI string reads in this file, the GetRecords() path called env->GetStringUTFChars(tenant_j, ...) with neither a pre-call null check on the jstring nor a following ThrowRuntime() exception check. Passing a null jstring to GetStringUTFChars is undefined per the JNI spec (and can leave a pending NullPointerException in flight). Only call GetStringUTFChars when tenant_j is non-null; the downstream already tolerates a null tenant_utf (defaults to "" and skips the guarded ReleaseStringUTFChars). Validated: NDK 27 clang++ --target=aarch64-linux-android24 -fsyntax-only compiles OfflineStorage_Room.cpp (USE_ROOM) cleanly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Guard remaining jstring inputs before GetStringUTFChars (Copilot review) Copilot's re-review flagged two more JNI string reads where the result was null-checked but the jstring input was passed to GetStringUTFChars unguarded, which crashes (or leaves a pending exception) before the result check when the jstring is null: - Signals_jni.cpp nativeInitialize: only read base_url when non-null; if the read itself fails (e.g. OOM) return immediately rather than continuing JNI calls with an exception pending, matching the nativeLog(signal_item_json) site. - OfflineStorage_Room.cpp ByTenant releaseRecords (token) and GetRecords-by-tenant (tenantToken_java): only call GetStringUTFChars when the jstring is non-null; the downstream already tolerates a null result (skips/defaults). The getSetting site is already guarded by an enclosing if (java_value). Validated: NDK 27 clang++ --target=aarch64-linux-android24 -fsyntax-only compiles both files cleanly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * GetRecords: clear pending JNI exception after tenant-token read (Copilot review) If GetStringUTFChars(tenant_j) fails (e.g. OOM) it returns null and leaves a pending JNI exception. GetRecords() previously continued issuing Get*Field calls with that exception in flight, which can make them return defaults. Call ThrowRuntime after the read (as GetAndReserveRecords and the rest of this file already do) to describe+clear the exception, notify the observer, and unwind the batch via the surrounding try/catch. Validated: NDK 27 clang++ -fsyntax-only compiles cleanly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * JStringToStdString: clear pending JNI exception on failed read (Copilot review) When GetStringUTFChars returns null (e.g. OOM) it leaves a pending Java exception. JStringToStdString returned "" without clearing it, so callers kept making JNI calls with an exception in flight. Clear the pending exception before returning, consistent with the ExceptionClear handling elsewhere in the JNI layer. Keeps the existing string-returning contract rather than redesigning the helper's signature, so no call sites change. Validated: NDK 27 clang++ -fsyntax-only compiles cleanly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * UWP: include <exception> directly for std::exception catch (Copilot review) The DeviceFamilyVersion parse added a catch(const std::exception&) but the file only pulled in <exception> transitively. Include it explicitly so the build does not depend on transitive include order. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Bound the HTTP cancel drains so they cannot spin or hang (issue microsoft#1437) Both HttpClientManager::cancelAllRequests() and HttpClient_WinInet::CancelAllRequests() waited for their in-flight request lists to drain with an unbounded poll loop. A previously-merged fix stopped the 100% CPU burn (locked the empty() check + sleep) but left the loop unbounded: if the drainer never runs -- the SDK task dispatcher stalls/stops for the manager, or a WinInet callback stalls -- the loop still blocks forever, and cancelAllRequests holds the LogManager lock the whole time, freezing LogEvent (issue microsoft#1437, a macOS spindump). Replace both poll loops with a condition variable signaled from the drain site (HttpClientManager::onHttpResponse / HttpClient_WinInet::erase), bounded by a timeout. The CV makes the common case drain in microseconds; the timeout is a last-resort safety valve so the drain can never spin or block indefinitely (and so the LogManager lock is held for at most the timeout, not forever). Callbacks/requests are deliberately NOT force-cleared on timeout: the HTTP client still owns them and invokes them later, so deleting them here would use-after-free (the destructor is not a drain barrier). The timeout is therefore a bounded best-effort valve, not the primary drain. Adds HttpClientManagerTests.CancelAllRequests_TimesOutInsteadOfHanging, which holds a request open and asserts cancelAllRequests returns within the (shortened) timeout instead of hanging, then completes the outstanding callback to confirm it is still safe after the drain was abandoned. Verified: full FuncTests suite (39 tests) passes on Linux (CV drain, no regression); the new unit test passes; HttpClient_WinInet.cpp compiles under MSVC. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Distinguish best-effort (pause) from full-drain (teardown) HTTP cancel Address Copilot review on cancelAllRequests. The previous change bounded every cancel drain with a timeout, which -- as Copilot noted -- can return with callbacks still in flight on the shutdown/destructor paths, where the caller then destroys state a late callback references (use-after-free). Split the two intents: - HttpClientManager::cancelAllRequests(bool bestEffort). bestEffort=true (pause, which runs under the LogManager lock) caps the wait so it cannot block indefinitely (issue microsoft#1437); the manager is not destroyed, so outstanding callbacks stay valid and drain later. bestEffort=false (default; shutdown/cleanup) drains fully -- the lifetime barrier before the referenced state is destroyed. TelemetrySystem::onPause now passes bestEffort=true; onStop/onCleanup keep the full drain. - HttpClient_WinInet::CancelAllRequests() now always drains fully. Its destructor calls it, so a bounded return would let a late WinInet callback touch a destroyed client. WinInet delivers cancellations on its own threads, so this does not depend on the SDK task dispatcher. Both paths use a condition variable signaled from the drain site instead of a poll loop, so neither spins at 100% CPU -- the reported microsoft#1437 failure -- whether bounded or full. Verified: FuncTests (39 tests) pass on Linux, including teardown which now takes the full-drain path; HttpClientManagerTests.CancelAllRequests_TimesOutInsteadOfHanging covers the best-effort timeout; HttpClient_WinInet.cpp compiles under MSVC /permissive- /W4. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Clear pending JNI exception before returning false in Signals_jni Addresses two Copilot review comments (Signals_jni.cpp:36 and :71). When GetStringUTFChars returns null it typically leaves a pending Java exception (e.g. OutOfMemoryError). Returning false without clearing it means the JVM throws that exception at the Java call site, so the caller sees the exception rather than the intended graceful alse -- contradicting the comment. Call env->ExceptionClear() before returning false at both sites so the caller observes a clean false (telemetry should degrade gracefully rather than propagate an OOM into the host app). ExceptionClear is one of the few JNI functions safe to call with an exception in flight, and no other JNI calls are made before return. Validated: the exact JNI usage (GetStringUTFChars + ExceptionClear + ReleaseStringUTFChars) compiles clean under the NDK aarch64-linux-android24 clang with -Wall -Werror. (A full Gradle build of this TU isn't possible in this worktree -- the private lib/modules submodule providing Signals.hpp is absent.) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Drop issue-number references from code comments Reword the HTTP cancel-drain comments to describe the behavior without citing tracking numbers; no code changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Drop issue-number reference from JniConvertors comment Reword the event-type comment to describe the behavior without citing a tracking number; no code change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Only add <condition_variable> for the new member in HttpClient_WinInet This change adds a std::condition_variable_any member; <condition_variable> is the only include it needs. Drop the <mutex> include: the pre-existing recursive_mutex member already resolves via the transitively-included pal/PAL.hpp, so adding <mutex> addressed a pre-existing concern outside this change's scope. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Re-add <mutex> to HttpClient_WinInet for a self-contained header The header uses std::recursive_mutex directly, so it should include <mutex> rather than rely on it being pulled in transitively via pal/PAL.hpp. This keeps the header self-contained (include-what-you-use) alongside <condition_variable> for the condition_variable_any member. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Clarify that best-effort pause is only bounded on async-handler platforms The bestEffort drain in cancelAllRequests caps the wait on m_httpCallbacks, but on Windows (USE_SYNC_HTTPRESPONSE_HANDLER) onHttpResponse drains m_httpCallbacks synchronously inside m_httpClient.CancelAllRequests(), so that wait is usually already satisfied and the real blocking is the transport-level wait there (WinInet condition-variable wait, WinRt poll), which is not bounded. Correct the comment so it no longer implies pause is fully bounded on Windows; fully bounding it requires plumbing the deadline into IHttpClient::CancelAllRequests (follow-up). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Bound best-effort pause on Windows by plumbing a deadline into CancelAllRequests PauseTransmission could block indefinitely on Windows even with the manager-level drain cap: with USE_SYNC_HTTPRESPONSE_HANDLER the callbacks drain synchronously inside IHttpClient::CancelAllRequests, so the real blocking region is the transport wait (WinInet condition-variable wait, WinRt poll), which was unbounded. Add a bestEffortTimeout parameter to IHttpClient::CancelAllRequests (default zero = full drain for shutdown/destructor; positive = best-effort cap). WinInet and WinRt now bound their drain wait by it; HttpClientManager passes m_cancelDrainTimeout on pause and zero on teardown. Fire-and-forget impls (Apple, CAPI, Android) accept and ignore the parameter. Files: lib/include/public/IHttpClient.hpp, lib/http/HttpClient_WinInet.{hpp,cpp}, HttpClient_WinRt.{hpp,cpp}, HttpClient_Apple.{hpp,mm}, HttpClient_CAPI.{hpp,cpp}, HttpClient_Android.{hpp,cpp}, HttpClientManager.{hpp,cpp}, tests/unittests/HttpClientCAPITests.cpp Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review: preserve CancelAllRequests() override compat and tighten the pause bound - Keep the legacy no-arg CancelAllRequests() virtual and add the timed overload as a separate method whose default forwards to it, so existing IHttpClient consumers that override CancelAllRequests() keep working (source-compatible) while built-in clients override the timed variant. - Treat m_cancelDrainTimeout as the total pause budget: subtract time already spent in the transport-level cancel before waiting on the manager callback drain, so the pause path holds the LogManager lock for at most ~one timeout, not up to 2x. - WinRt bounded poll now sleeps at most the remaining budget (min(100ms, remaining)) instead of a full 100ms, so it does not overshoot bestEffortTimeout by a poll interval. - Relax the manager timeout test's lower bound (Ge(100) for a 150ms timeout) so it still catches immediate-return regressions without being flaky under CI timer jitter. Files: lib/include/public/IHttpClient.hpp, lib/http/HttpClientManager.cpp, HttpClient_WinRt.cpp, tests/unittests/HttpClientManagerTests.cpp Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Clarify CancelAllRequests compatibility: source-compatible, not ABI-stable The overload preserves source compatibility for existing IHttpClient overrides, but adding a virtual changes the vtable, so binary implementations must be recompiled -- consistent with the SDK's C++ classes not being ABI-stable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Keep the no-arg CancelAllRequests() working on every built-in client With the legacy no-arg virtual restored on IHttpClient, an impl that overrode only the timed overload would let a CancelAllRequests() call through an IHttpClient reference hit the base no-op instead of cancelling. Each built-in client (WinInet, WinRt, Apple, CAPI, Android) now also overrides CancelAllRequests() to forward to the timed overload with a zero (full-drain) timeout, so both signatures cancel. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Avoid public timed HTTP cancel virtual Move bounded cancel support behind an internal optional capability and use per-request cancellation as the manager fallback for old-style IHttpClient implementations. Keep shutdown on the existing full-drain CancelAllRequests path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Guard Signals JNI logger pointer and drop unused cancel return Fail Signals.sendSignal cleanly when Java passes a null native logger pointer, matching the existing JNI hardening in this file and avoiding a null ILogger dereference before LogEvent(). Also make HttpClientManager::cancelAllRequestsAsync() return void since every caller ignored the bool and the helper has no meaningful failure signal. Deliberately defer the WinRt cancel-drain CV conversion: the current best-effort path is already bounded, and changing the UWP/PPL completion-drain coordination without a transport-specific validation loop is riskier than this follow-up warrants. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b12c5862-01e3-45e4-bf91-6389c20cae41 * Align vcpkg iOS deployment target Ensure vcpkg-built Apple libraries match the consumer deployment target and avoid linker warnings. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5f341bc5-f8ae-4259-b03b-8eeb87c06837 * Harden Apple packaging integration Propagate the resolved iOS sysroot to embedding builds and keep Apple vendored targets compatible with strict warning settings. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5f341bc5-f8ae-4257-b03b-8eeb87c06837 * Migrate Apple builds to canonical CMake variables Remove legacy Apple architecture, platform, and deployment-target inputs so standalone scripts and embedding consumers share CMAKE_OSX_* configuration. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5f341bc5-f8ae-4257-b03b-8eeb87c06837 * Harden nullable JNI and WinRT version inputs Prevent null and empty retry status arrays from reaching JNI APIs, and handle WinRT exceptions while reading the device family version. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Simplify cancellation documentation and clock setup Keep the behavior unchanged while reducing repeated rationale and centralizing the default kill-switch clock. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Stop test runner looping after failures Return the failing build or test status instead of jumping to a self-looping end label, so CI reports failures rather than appearing hung. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Avoid RTTI dependency and report test failures Use the tracked-request cancellation fallback for no-RTTI builds, and make the Windows test runner wait for concurrent tests and propagate every nonzero exit code. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Preserve JNI allocation failures Keep pending Java exceptions from GetStringUTFChars failures so OOM and related conversion errors are not silently converted into empty values or false results. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b12c5862-01e3-45e4-bf91-6389c20cae41 Copilot-Session: 5f341bc5-f8ae-4259-b03b-8eeb87c06837 Copilot-Session: 5f341bc5-f8ae-4257-b03b-8eeb87c06837
Prototype: Swift Package Manager distribution (xcframework)
First-pass scaffold to distribute the 1DS C++ SDK to Apple app developers via Swift Package Manager — the successor to CocoaPods (trunk goes read-only 2 Dec 2026). There is no official in-repo podspec today, and the existing
wrappers/swift/Package.swiftis a local-build skeleton rather than a distributable package.Approach
SPM cannot practically compile this C++ tree from source (CMake/Bond/sqlite/zlib/platform conditionals), so:
MATTelemetry.xcframework(.binaryTarget). The Obj-C wrappers compile intolibmat.aon Apple.wrappers/swift/Sources/OneDSSwift) is compiled from source on top of theObjCModulevended by the xcframework.Package.swiftadvertises.iOS(.v12)only until macOS / Catalyst / visionOS slices are added.What's here
Package.swift— distributable SPM manifest:binaryTarget+OneDSSwiftsource target.tools/apple/build-xcframework.sh— builds staticlibmat.aslices viabuild-ios.sh, combines simulator archs withlipo, and assemblesMATTelemetry.xcframeworkwithxcodebuild -create-xcframework.tools/apple/module.modulemap+MATTelemetry-umbrella.h— vend theObjCModuleClang module.tools/apple/MATTelemetryAvailability.json— generated by the xcframework build and read byPackage.swiftso Swift source exclusions match the optional modules actually built into the binary..github/workflows/spm-release.yml— on a publishedvX.Y.Z.Wrelease: build the xcframework on a macOS runner, upload it to the Release, pin thebinaryTargeturl:+checksum:, and push a 3-component SemVer tag (X.Y.Z) that SPM can resolve.tools/apple/README.md— approach, build/consume, release wiring, and remaining TODOs.Validation performed on macOS
Validated locally with Xcode on macOS:
./build-ios.sh clean release arm64 iphonesimulatorproducedout/lib/libmat.aas a static archive and included Obj-C wrapper symbols.tools/apple/build-xcframework.sh releasesucceeded.ios-arm64ios-arm64_x86_64-simulatorxcodebuild -scheme OneDSSwift -destination 'generic/platform=iOS Simulator' buildConsume after a release
Remaining TODOs
Package.swift.Package.swiftlives long-term, since it makes the repository an SPM package.Companion to the official vcpkg port (C++ consumers) — SPM serves Apple app developers; the two are complementary.