diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 148e118..7a38b0e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,10 +8,11 @@ # would pressure people into editing code the repo deliberately keeps as # upstream's. # -# Native code is not compiled here: these are watchOS FFI plugins, and every -# test fakes the bindings through a `forTesting` constructor, so nothing needs -# a Mac. Compiling the `.m` sources needs a watchOS SDK and belongs in the -# per-package `example` build, run on a Mac by hand — see AUTHORING.md §3. +# The package tests fake the native bindings through a `forTesting` +# constructor, so they need no Mac. The `native` job compiles the native +# sources on macOS with -fsyntax-only, the way the CLI builds them, on Xcode 26 +# and 27; running the code is still each package's `example` build on a Mac +# (AUTHORING.md §3). name: CI on: @@ -187,3 +188,53 @@ jobs: if: success() || failure() working-directory: tool run: dart run bin/check_test_names.dart + + native: + # Spec 0022 D1 (#17): every plugin's .m, .mm, .c and SwiftUI view source, + # compiled the way the CLI compiles it, with -fsyntax-only, for a watch + # and for the Simulator. macos-26 runs the oldest Xcode 26 the CLI + # supports and its default; xcode-27 runs Xcode 27. A symbol one SDK lacks + # (CLActivityTypeMaritime in #12) fails here, not in an app's build. + name: native sources (${{ matrix.label }}) + runs-on: ${{ matrix.runner }} + timeout-minutes: 20 + strategy: + fail-fast: false + matrix: + include: + - label: Xcode 26 + runner: macos-26 + developer_dirs: >- + /Applications/Xcode_26.0.1.app/Contents/Developer + /Applications/Xcode_26.6.app/Contents/Developer + - label: Xcode 27 + runner: xcode-27 + developer_dirs: /Applications/Xcode_27.app/Contents/Developer + steps: + - uses: actions/checkout@v4 + + - name: Compile with each Xcode + env: + DEVELOPER_DIRS: ${{ matrix.developer_dirs }} + run: | + status=0 + for developer_dir in $DEVELOPER_DIRS; do + if [ ! -d "$developer_dir" ]; then + echo "FAILED no Xcode at $developer_dir" + status=1 + continue + fi + DEVELOPER_DIR="$developer_dir" tool/check_native_sources.sh || status=1 + done + exit "$status" + + # The check must be able to fail. Its fixtures hold an undeclared + # symbol and a warning, which fail, and a clean source with a + # deprecation, which passes. + - uses: dart-lang/setup-dart@v1 + + - name: Test the check + working-directory: tool + run: | + dart pub get + dart test test/check_native_sources_test.dart diff --git a/tool/README.md b/tool/README.md index 39802e7..e9a2c8a 100644 --- a/tool/README.md +++ b/tool/README.md @@ -18,6 +18,13 @@ tool/check_generated_ignored.sh (cd tool && dart run bin/publish_dry_run.dart) ``` +The `native` job of `ci.yml` runs one more on macOS, once per Xcode, as +`DEVELOPER_DIR` picks it. It needs Xcode, so the Ubuntu jobs leave it out: + +```sh +tool/check_native_sources.sh +``` + The weekly workflow `.github/workflows/upstream.yml` runs two more, which read pub.dev and so are not part of the per-change checks: @@ -108,6 +115,22 @@ runs it in the package job, after the tests. Its report goes into a public log, so a line of pub's output that holds a forbidden word is withheld and fails the package. +## Native sources + +`check_native_sources.sh` compiles every plugin's native watchOS sources the way +the CLI does, with `-fsyntax-only`, for `arm64-apple-watchos26.0` and its +Simulator triple: +- `.m`, `.mm` and `.c` files go through clang, with the CLI's flags; +- SwiftUI view sources go through `swiftc -typecheck`, with a copy of the + CLI's registration shim (`native/plugin_views_shim.swift`). + +An error or a warning fails, except a deprecation, which is counted. +in_app_purchase_watchos uses StoreKit 1 on purpose. A package whose +`watchos/Package.swift` names a SwiftPM package is listed and skipped, as only +a SwiftPM build provides its modules. `--list` prints the plan without +compiling, and the Ubuntu tool tests run it on fixtures. The compile fixtures +run on macOS, in the `native` job. + ## Weekly upstream compatibility `.github/workflows/upstream.yml` runs every Monday and by hand, and never diff --git a/tool/check_native_sources.sh b/tool/check_native_sources.sh new file mode 100755 index 0000000..88995ab --- /dev/null +++ b/tool/check_native_sources.sh @@ -0,0 +1,159 @@ +#!/usr/bin/env bash +# Copyright 2026 The FlutterWatch Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +# +# Compiles every plugin's native watchOS sources the way flutter-watchos does, +# with -fsyntax-only, for a watch and for the Simulator, with the Xcode that +# DEVELOPER_DIR (or xcode-select) picks. CI runs it with the oldest Xcode 26 +# the CLI supports, the newest Xcode 26 and Xcode 27, so a symbol that one +# SDK lacks fails here and not in an app's build (spec 0022 D1, #17). +# +# - Objective-C and C sources (.m, .mm, .c) go through clang with the CLI's +# flags (lib/build_targets/application.dart in flutter-watchos 0.1.1). +# - SwiftUI view sources (.swift under watchos/, except Package.swift and +# anything under Flutter/ or a dot-directory) go through swiftc -typecheck, +# one module per plugin, with the CLI's registration shim +# (tool/native/plugin_views_shim.swift). +# - A plugin whose watchos/Package.swift names a SwiftPM package is skipped +# and listed: its sources import that package's modules, which only a +# SwiftPM build provides, and the CLI builds such a plugin with xcodebuild. +# +# Only git-tracked files are read. A warning fails like an error, as in the +# CLI's own host typecheck, except a deprecation: those are counted and left +# to the package (in_app_purchase_watchos uses StoreKit 1 on purpose). +# +# Usage: tool/check_native_sources.sh [--root ] [--list] +# --list prints what would be compiled and runs nothing; no Xcode needed. +set -euo pipefail + +# The deployment target `flutter-watchos create` writes. +readonly deployment_target="26.0" +readonly targets="watchos:arm64-apple-watchos${deployment_target} watchsimulator:arm64-apple-watchos${deployment_target}-simulator" + +root="" +list=0 +while [ $# -gt 0 ]; do + case "$1" in + --root) [ $# -ge 2 ] || { echo "--root needs a value" >&2; exit 2; }; root="$2"; shift 2 ;; + --list) list=1; shift ;; + *) echo "usage: $0 [--root ] [--list]" >&2; exit 2 ;; + esac +done +if [ -z "$root" ]; then + root="$(git rev-parse --show-toplevel)" +fi +shim="$(cd "$(dirname "$0")" && pwd)/native/plugin_views_shim.swift" +cd "$root" + +# The tracked files under each package's own watchos/ directory. In a +# pathspec `*` also crosses `/`, so the pattern alone would take in each +# example's watchos/ app too; the grep keeps the package's. +tracked="$(git ls-files -- 'packages/*/watchos/*' | grep -E '^packages/[^/]+/watchos/' || true)" + +# Every directory that holds a tracked header: the CLI passes each one to +# every plugin's compile. +includes=() +for dir in $(printf '%s\n' "$tracked" | grep '\.h$' | xargs -n1 dirname | sort -u); do + includes+=("-I$dir") +done + +# True for a view source: not the manifest, and nothing under Flutter/ or a +# dot-directory (CLI build output and SwiftPM state). +is_view_source() { + local relative="${1#*/watchos/}" + case "$relative" in + Package.swift | Flutter/* | */Flutter/* | .* | */.*) return 1 ;; + *.swift) return 0 ;; + *) return 1 ;; + esac +} + +# Prints the warnings in [1] that are not deprecations. +other_warnings() { + grep 'warning:' <<< "$1" | grep -v -e 'is deprecated' -e 'was deprecated' || true +} + +# Reports one compile: [1] its name, [2] its exit code, [3] its output. +report() { + local deprecations + deprecations="$(grep -c 'warning:.*deprecated' <<< "$3" || true)" + if [ "$2" -eq 0 ] && [ -z "$(other_warnings "$3")" ]; then + if [ "$deprecations" -gt 0 ]; then + echo "ok $xcode $triple $1 ($deprecations deprecation warning$([ "$deprecations" -eq 1 ] || echo s))" + else + echo "ok $xcode $triple $1" + fi + else + echo "FAILED $xcode $triple $1" + echo "$3" + status=1 + fi +} + +xcode="" +if [ "$list" -eq 0 ]; then + # sed, not head: head would close the pipe early, and pipefail would end + # the script on xcodebuild's SIGPIPE. + xcode="$(xcodebuild -version | sed -n 1p)" +fi + +status=0 +checked=0 +for package_dir in $(printf '%s\n' "$tracked" | cut -d/ -f1-2 | sort -u); do + package="${package_dir#packages/}" + manifest="$package_dir/watchos/Package.swift" + if [ -f "$manifest" ] && grep -q '\.package(' "$manifest"; then + echo "skip $package: its watchos/Package.swift names a SwiftPM package, which only a SwiftPM build provides" + continue + fi + c_sources=() + view_sources=() + for file in $(printf '%s\n' "$tracked" | grep "^$package_dir/"); do + case "$file" in + *.m | *.mm | *.c) c_sources+=("$file") ;; + *) if is_view_source "$file"; then view_sources+=("$file"); fi ;; + esac + done + for target in $targets; do + sdk="${target%%:*}" + triple="${target#*:}" + for source in ${c_sources[@]+"${c_sources[@]}"}; do + checked=$((checked + 1)) + if [ "$list" -eq 1 ]; then + echo "plan clang $sdk $triple $source" + continue + fi + code=0 + output="$(xcrun -sdk "$sdk" clang -fsyntax-only -target "$triple" \ + -fobjc-arc -fmodules ${includes[@]+"${includes[@]}"} "$source" 2>&1)" || code=$? + report "$source" "$code" "$output" + done + if [ ${#view_sources[@]} -gt 0 ]; then + checked=$((checked + 1)) + if [ "$list" -eq 1 ]; then + echo "plan swiftc $sdk $triple ${package}_views: ${view_sources[*]}" + continue + fi + code=0 + output="$(xcrun -sdk "$sdk" swiftc -typecheck -target "$triple" \ + -parse-as-library -module-name "${package}_views" \ + "$shim" "${view_sources[@]}" 2>&1)" || code=$? + report "${package}_views" "$code" "$output" + fi + done +done + +if [ "$checked" -eq 0 ]; then + echo "No native source found under packages/*/watchos/." + exit 1 +fi +if [ "$list" -eq 1 ]; then + echo "include ${includes[*]+"${includes[*]}"}" + exit 0 +fi +if [ "$status" -ne 0 ]; then + echo "Native sources: some do not compile cleanly with $xcode." + exit 1 +fi +echo "Native sources: all compile cleanly with $xcode." diff --git a/tool/native/plugin_views_shim.swift b/tool/native/plugin_views_shim.swift new file mode 100644 index 0000000..14df696 --- /dev/null +++ b/tool/native/plugin_views_shim.swift @@ -0,0 +1,79 @@ +// A copy of the registration shim flutter-watchos compiles into every plugin +// module with SwiftUI view sources (kPluginViewSupportSwift in the CLI's +// lib/build_targets/watchos_plugin_views.dart, CLI 0.1.1). It is here only so +// tool/check_native_sources.sh can type-check plugin view sources the way the +// CLI compiles them. Update it with the CLI. Not part of any plugin. +// +// Compiled by flutter-watchos into every plugin module that ships SwiftUI +// view sources. Not part of the plugin — do not copy it into one. +// +// Gives plugin code `FlutterWatchOSPluginViews.register(_:factory:)`, the +// Swift face of the app runner's C registration entry point. + +import Darwin +import Foundation +import SwiftUI + +private let _factoriesLock = NSLock() +private var _factories: [String: (String) -> AnyView] = [:] + +/// The @convention(c) trampoline handed to the runner, once per registered +/// type. Receives (viewType, creationParams); returns the built AnyView +/// RETAINED, boxed by the Swift runtime (`as AnyObject` — SwiftUI hard-rejects +/// class-conforming Views, so the view itself must stay a struct and the +/// runtime box is the only class in the crossing). The runner unwraps it with +/// a plain dynamic cast, since AnyView is SwiftUI's own type on both sides. +/// nil means no factory — render nothing. +private let _factoryTrampoline: @convention(c) ( + UnsafePointer?, UnsafePointer? +) -> UnsafeMutableRawPointer? = { type, params in + guard let type else { return nil } + let viewType = String(cString: type) + let creationParams = params.map { String(cString: $0) } ?? "" + _factoriesLock.lock() + let factory = _factories[viewType] + _factoriesLock.unlock() + guard let factory else { return nil } + return Unmanaged.passRetained(factory(creationParams) as AnyObject).toOpaque() +} + +/// Registration surface for a plugin's native SwiftUI views. +public enum FlutterWatchOSPluginViews { + private typealias _Register = @convention(c) ( + UnsafePointer?, + (@convention(c) ( + UnsafePointer?, UnsafePointer? + ) -> UnsafeMutableRawPointer?)? + ) -> Void + + /// The runner's registration entry point, resolved via dlsym + /// (RTLD_DEFAULT is the special -2 handle) so nothing links against the + /// app at compile time. nil when the app was created by a CLI that + /// predates plugin platform views. + private static let _register: _Register? = { + guard let sym = dlsym( + UnsafeMutableRawPointer(bitPattern: -2), + "FlutterWatchOSPlatformViewRegisterNativeFactory") + else { return nil } + return unsafeBitCast(sym, to: _Register.self) + }() + + /// Registers (or replaces) the native factory for `viewType`. The factory + /// receives the Dart widget's `creationParams` string and always runs on + /// the main thread; `register` itself may be called from any thread + /// (plugin registration typically arrives over FFI from Dart). + public static func register( + _ viewType: String, factory: @escaping (String) -> AnyView + ) { + _factoriesLock.lock() + _factories[viewType] = factory + _factoriesLock.unlock() + guard let register = _register else { + NSLog("FlutterWatchOSPluginViews: this app's runner predates " + + "plugin platform views; '\(viewType)' will not render. " + + "Re-create the app with a current flutter-watchos.") + return + } + viewType.withCString { register($0, _factoryTrampoline) } + } +} diff --git a/tool/test/check_native_sources_test.dart b/tool/test/check_native_sources_test.dart new file mode 100644 index 0000000..36a7f10 --- /dev/null +++ b/tool/test/check_native_sources_test.dart @@ -0,0 +1,94 @@ +// Copyright 2026 The FlutterWatch Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// tool/check_native_sources.sh on its fixtures, in +// tool/test/fixtures/check_native_sources/. `--list` runs anywhere, so the +// plan fixtures run on every machine. The compile fixtures need Xcode, so +// they run on macOS only: the CI job that compiles the native sources runs +// this file there. + +import 'dart:io'; + +import 'package:path/path.dart' as p; +import 'package:test/test.dart'; + +import 'src/fixture_repo.dart'; + +void main() { + final String script = p.absolute('check_native_sources.sh'); + final List fixtures = fixturesIn( + p.join('test', 'fixtures', 'check_native_sources'), + ); + + /// Runs the script on [fixture]'s repository, with [arguments]. + ProcessResult run(Fixture fixture, List arguments) { + final String root = fixture.createRepository(); + addTearDown(() => Directory(root).deleteSync(recursive: true)); + return Process.runSync('bash', [ + script, + '--root', + root, + ...arguments, + ]); + } + + /// Checks [result] against [fixture]'s `expect` file. + void expectFixture(Fixture fixture, ProcessResult result) { + final String output = '${result.stdout}${result.stderr}'; + expect(result.exitCode, fixture.expectedExitCode, reason: output); + for (final String line in fixture.expectedOutput) { + expect(output, contains(line)); + } + } + + Fixture named(String name) => + fixtures.singleWhere((Fixture f) => f.name == name); + + group('--list', () { + test('plans what the CLI compiles, and nothing else', () { + final Fixture fixture = named('plan'); + final ProcessResult result = run(fixture, ['--list']); + expectFixture(fixture, result); + final String output = '${result.stdout}'; + expect(output, isNot(contains('scratch.m')), reason: 'untracked'); + expect( + output, + isNot(contains('Flutter/Generated.swift')), + reason: 'CLI build output', + ); + expect( + output, + isNot(contains('example/watchos')), + reason: "the example's app", + ); + expect( + output, + isNot(contains('b_watchos_ffi.m')), + reason: 'a SwiftPM-dependency package is skipped', + ); + }); + + test('a repository with no native source fails', () { + final Fixture fixture = named('no_sources'); + expectFixture(fixture, run(fixture, ['--list'])); + }); + }); + + group('compiles', () { + test('a clean source passes, and a deprecation is counted', () { + final Fixture fixture = named('compile_clean'); + expectFixture(fixture, run(fixture, [])); + }); + + test('an undeclared symbol fails', () { + final Fixture fixture = named('compile_undeclared'); + expectFixture(fixture, run(fixture, [])); + }); + + test('a warning that is not a deprecation fails', () { + final Fixture fixture = named('compile_warning'); + expectFixture(fixture, run(fixture, [])); + }); + }, skip: Platform.isMacOS ? false : 'needs Xcode'); +} diff --git a/tool/test/fixtures/check_native_sources/compile_clean/expect b/tool/test/fixtures/check_native_sources/compile_clean/expect new file mode 100644 index 0000000..a3648fe --- /dev/null +++ b/tool/test/fixtures/check_native_sources/compile_clean/expect @@ -0,0 +1,4 @@ +0 +packages/ok_watchos/watchos/Classes/ok_watchos_ffi.m (1 deprecation warning) +ok_watchos_views +Native sources: all compile cleanly with diff --git a/tool/test/fixtures/check_native_sources/compile_clean/repo/packages/ok_watchos/watchos/Classes/ok_watchos_ffi.m b/tool/test/fixtures/check_native_sources/compile_clean/repo/packages/ok_watchos/watchos/Classes/ok_watchos_ffi.m new file mode 100644 index 0000000..c9e7139 --- /dev/null +++ b/tool/test/fixtures/check_native_sources/compile_clean/repo/packages/ok_watchos/watchos/Classes/ok_watchos_ffi.m @@ -0,0 +1,7 @@ +#import + +__attribute__((deprecated("a newer call replaces it"))) static int ok_watchos_old_value(void) { + return 1; +} + +int ok_watchos_value(void) { return ok_watchos_old_value(); } diff --git a/tool/test/fixtures/check_native_sources/compile_clean/repo/packages/ok_watchos/watchos/Views/ok_watchos_views.swift b/tool/test/fixtures/check_native_sources/compile_clean/repo/packages/ok_watchos/watchos/Views/ok_watchos_views.swift new file mode 100644 index 0000000..6ce3077 --- /dev/null +++ b/tool/test/fixtures/check_native_sources/compile_clean/repo/packages/ok_watchos/watchos/Views/ok_watchos_views.swift @@ -0,0 +1,8 @@ +import SwiftUI + +@_cdecl("ok_watchos_register_views") +public func okWatchosRegisterViews() { + FlutterWatchOSPluginViews.register("ok_watchos") { params in + AnyView(Text(params)) + } +} diff --git a/tool/test/fixtures/check_native_sources/compile_undeclared/expect b/tool/test/fixtures/check_native_sources/compile_undeclared/expect new file mode 100644 index 0000000..03b7c03 --- /dev/null +++ b/tool/test/fixtures/check_native_sources/compile_undeclared/expect @@ -0,0 +1,4 @@ +1 +FAILED +use of undeclared identifier 'bad_watchos_undeclared' +Native sources: some do not compile cleanly with diff --git a/tool/test/fixtures/check_native_sources/compile_undeclared/repo/packages/bad_watchos/watchos/Classes/bad_watchos_ffi.m b/tool/test/fixtures/check_native_sources/compile_undeclared/repo/packages/bad_watchos/watchos/Classes/bad_watchos_ffi.m new file mode 100644 index 0000000..7910342 --- /dev/null +++ b/tool/test/fixtures/check_native_sources/compile_undeclared/repo/packages/bad_watchos/watchos/Classes/bad_watchos_ffi.m @@ -0,0 +1 @@ +int bad_watchos_value(void) { return bad_watchos_undeclared; } diff --git a/tool/test/fixtures/check_native_sources/compile_warning/expect b/tool/test/fixtures/check_native_sources/compile_warning/expect new file mode 100644 index 0000000..dc802f6 --- /dev/null +++ b/tool/test/fixtures/check_native_sources/compile_warning/expect @@ -0,0 +1,3 @@ +1 +FAILED +implicit conversion from diff --git a/tool/test/fixtures/check_native_sources/compile_warning/repo/packages/warn_watchos/watchos/Classes/warn_watchos_ffi.m b/tool/test/fixtures/check_native_sources/compile_warning/repo/packages/warn_watchos/watchos/Classes/warn_watchos_ffi.m new file mode 100644 index 0000000..30bf883 --- /dev/null +++ b/tool/test/fixtures/check_native_sources/compile_warning/repo/packages/warn_watchos/watchos/Classes/warn_watchos_ffi.m @@ -0,0 +1,4 @@ +int warn_watchos_value(void) { + int truncated = 1.5; + return truncated; +} diff --git a/tool/test/fixtures/check_native_sources/no_sources/expect b/tool/test/fixtures/check_native_sources/no_sources/expect new file mode 100644 index 0000000..7a6ef1d --- /dev/null +++ b/tool/test/fixtures/check_native_sources/no_sources/expect @@ -0,0 +1,2 @@ +1 +No native source found under packages/*/watchos/. diff --git a/tool/test/fixtures/check_native_sources/no_sources/repo/packages/d_watchos/lib/d_watchos.dart b/tool/test/fixtures/check_native_sources/no_sources/repo/packages/d_watchos/lib/d_watchos.dart new file mode 100644 index 0000000..316a905 --- /dev/null +++ b/tool/test/fixtures/check_native_sources/no_sources/repo/packages/d_watchos/lib/d_watchos.dart @@ -0,0 +1 @@ +library; diff --git a/tool/test/fixtures/check_native_sources/plan/expect b/tool/test/fixtures/check_native_sources/plan/expect new file mode 100644 index 0000000..f8ac29c --- /dev/null +++ b/tool/test/fixtures/check_native_sources/plan/expect @@ -0,0 +1,8 @@ +0 +plan clang watchos arm64-apple-watchos26.0 packages/a_watchos/watchos/Classes/a_watchos_ffi.m +plan clang watchsimulator arm64-apple-watchos26.0-simulator packages/a_watchos/watchos/Classes/a_watchos_ffi.m +skip b_watchos: its watchos/Package.swift names a SwiftPM package, which only a SwiftPM build provides +plan clang watchos arm64-apple-watchos26.0 packages/c_watchos/watchos/Classes/c_watchos.c +plan swiftc watchos arm64-apple-watchos26.0 c_watchos_views: packages/c_watchos/watchos/Views/c_watchos_views.swift +plan swiftc watchsimulator arm64-apple-watchos26.0-simulator c_watchos_views: packages/c_watchos/watchos/Views/c_watchos_views.swift +include -Ipackages/a_watchos/watchos/Classes diff --git a/tool/test/fixtures/check_native_sources/plan/repo/packages/a_watchos/watchos/Classes/a_watchos_ffi.h b/tool/test/fixtures/check_native_sources/plan/repo/packages/a_watchos/watchos/Classes/a_watchos_ffi.h new file mode 100644 index 0000000..7a2b192 --- /dev/null +++ b/tool/test/fixtures/check_native_sources/plan/repo/packages/a_watchos/watchos/Classes/a_watchos_ffi.h @@ -0,0 +1 @@ +void a_watchos_value(void); diff --git a/tool/test/fixtures/check_native_sources/plan/repo/packages/a_watchos/watchos/Classes/a_watchos_ffi.m b/tool/test/fixtures/check_native_sources/plan/repo/packages/a_watchos/watchos/Classes/a_watchos_ffi.m new file mode 100644 index 0000000..a944f6b --- /dev/null +++ b/tool/test/fixtures/check_native_sources/plan/repo/packages/a_watchos/watchos/Classes/a_watchos_ffi.m @@ -0,0 +1,3 @@ +#import "a_watchos_ffi.h" + +void a_watchos_value(void) {} diff --git a/tool/test/fixtures/check_native_sources/plan/repo/packages/a_watchos/watchos/Package.swift b/tool/test/fixtures/check_native_sources/plan/repo/packages/a_watchos/watchos/Package.swift new file mode 100644 index 0000000..72a57a0 --- /dev/null +++ b/tool/test/fixtures/check_native_sources/plan/repo/packages/a_watchos/watchos/Package.swift @@ -0,0 +1,7 @@ +// swift-tools-version: 5.9 +import PackageDescription + +let package = Package( + name: "a_watchos", + targets: [.target(name: "a_watchos", path: "Classes")] +) diff --git a/tool/test/fixtures/check_native_sources/plan/repo/packages/b_watchos/watchos/Classes/b_watchos_ffi.m b/tool/test/fixtures/check_native_sources/plan/repo/packages/b_watchos/watchos/Classes/b_watchos_ffi.m new file mode 100644 index 0000000..eeff7e8 --- /dev/null +++ b/tool/test/fixtures/check_native_sources/plan/repo/packages/b_watchos/watchos/Classes/b_watchos_ffi.m @@ -0,0 +1 @@ +void b_watchos_value(void) {} diff --git a/tool/test/fixtures/check_native_sources/plan/repo/packages/b_watchos/watchos/Package.swift b/tool/test/fixtures/check_native_sources/plan/repo/packages/b_watchos/watchos/Package.swift new file mode 100644 index 0000000..3dc4b9d --- /dev/null +++ b/tool/test/fixtures/check_native_sources/plan/repo/packages/b_watchos/watchos/Package.swift @@ -0,0 +1,8 @@ +// swift-tools-version: 5.9 +import PackageDescription + +let package = Package( + name: "b_watchos", + dependencies: [.package(url: "https://example.com/sdk.git", from: "1.0.0")], + targets: [.target(name: "b_watchos", path: "Classes")] +) diff --git a/tool/test/fixtures/check_native_sources/plan/repo/packages/c_watchos/example/watchos/Runner/App.swift b/tool/test/fixtures/check_native_sources/plan/repo/packages/c_watchos/example/watchos/Runner/App.swift new file mode 100644 index 0000000..e6c6d46 --- /dev/null +++ b/tool/test/fixtures/check_native_sources/plan/repo/packages/c_watchos/example/watchos/Runner/App.swift @@ -0,0 +1 @@ +import SwiftUI diff --git a/tool/test/fixtures/check_native_sources/plan/repo/packages/c_watchos/watchos/Classes/c_watchos.c b/tool/test/fixtures/check_native_sources/plan/repo/packages/c_watchos/watchos/Classes/c_watchos.c new file mode 100644 index 0000000..9320441 --- /dev/null +++ b/tool/test/fixtures/check_native_sources/plan/repo/packages/c_watchos/watchos/Classes/c_watchos.c @@ -0,0 +1 @@ +int c_watchos_value(void) { return 1; } diff --git a/tool/test/fixtures/check_native_sources/plan/repo/packages/c_watchos/watchos/Flutter/Generated.swift b/tool/test/fixtures/check_native_sources/plan/repo/packages/c_watchos/watchos/Flutter/Generated.swift new file mode 100644 index 0000000..e6a31cc --- /dev/null +++ b/tool/test/fixtures/check_native_sources/plan/repo/packages/c_watchos/watchos/Flutter/Generated.swift @@ -0,0 +1 @@ +// Build output the CLI writes; not a view source. diff --git a/tool/test/fixtures/check_native_sources/plan/repo/packages/c_watchos/watchos/Views/c_watchos_views.swift b/tool/test/fixtures/check_native_sources/plan/repo/packages/c_watchos/watchos/Views/c_watchos_views.swift new file mode 100644 index 0000000..e6c6d46 --- /dev/null +++ b/tool/test/fixtures/check_native_sources/plan/repo/packages/c_watchos/watchos/Views/c_watchos_views.swift @@ -0,0 +1 @@ +import SwiftUI diff --git a/tool/test/fixtures/check_native_sources/plan/untracked/packages/a_watchos/watchos/Classes/scratch.m b/tool/test/fixtures/check_native_sources/plan/untracked/packages/a_watchos/watchos/Classes/scratch.m new file mode 100644 index 0000000..3f6bfcc --- /dev/null +++ b/tool/test/fixtures/check_native_sources/plan/untracked/packages/a_watchos/watchos/Classes/scratch.m @@ -0,0 +1 @@ +void scratch(void) {}