diff --git a/.changeset/spotty-readers-go.md b/.changeset/spotty-readers-go.md new file mode 100644 index 00000000..7375bfd4 --- /dev/null +++ b/.changeset/spotty-readers-go.md @@ -0,0 +1,5 @@ +--- +"react-native-node-api": patch +--- + +Print module path on framework slicing failure diff --git a/.changeset/true-ideas-retire.md b/.changeset/true-ideas-retire.md new file mode 100644 index 00000000..eece23ac --- /dev/null +++ b/.changeset/true-ideas-retire.md @@ -0,0 +1,5 @@ +--- +"ferric-cli": patch +--- + +Add x86_64-apple-ios as a default target on an Apple host diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 6032127f..71fcf106 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -117,7 +117,7 @@ jobs: uses: android-actions/setup-android@v4 with: packages: tools platform-tools ndk;${{ env.NDK_VERSION }} - - run: rustup target add x86_64-linux-android aarch64-linux-android armv7-linux-androideabi i686-linux-android aarch64-apple-ios-sim + - run: rustup target add x86_64-linux-android aarch64-linux-android armv7-linux-androideabi i686-linux-android aarch64-apple-ios-sim x86_64-apple-ios - run: pnpm install - run: pnpm run bootstrap - run: pnpm test @@ -170,6 +170,19 @@ jobs: - uses: pnpm/action-setup@v6 with: cache: true + # Device names change with every Xcode release, so pick one dynamically. + - name: Boot the simulator + run: | + SIMULATOR_UDID=$(xcrun simctl list devices available --json | node -e " + const { devices } = JSON.parse(require('node:fs').readFileSync(0, 'utf8')); + const runtimes = Object.keys(devices).filter((r) => r.includes('iOS')).sort(); + const device = runtimes.flatMap((r) => devices[r]).find((d) => d.name.startsWith('iPhone')); + if (!device) throw new Error('Found no available iPhone simulator'); + console.log(device.udid); + ") + echo "Booting $SIMULATOR_UDID" + xcrun simctl bootstatus "$SIMULATOR_UDID" -b + echo "SIMULATOR_UDID=$SIMULATOR_UDID" >> $GITHUB_ENV - name: Setup cpp tools uses: aminya/setup-cpp@v1 with: @@ -178,28 +191,71 @@ jobs: uses: hendrikmuhs/ccache-action@v1.2.23 with: key: ${{ github.job }}-${{ runner.os }} - - name: Set up JDK 17 - uses: actions/setup-java@v5 - with: - java-version: "17" - distribution: "temurin" - - name: Setup Android SDK - uses: android-actions/setup-android@v4 - with: - packages: tools platform-tools ndk;${{ env.NDK_VERSION }} - - run: rustup target add x86_64-linux-android aarch64-linux-android armv7-linux-androideabi i686-linux-android aarch64-apple-ios-sim + # The action defaults to 500M, which a from-source React Native build + # fills mid-build: it evicted 88 times in one run, discarding most of + # what it had just cached. + max-size: 3G + - run: rustup target add aarch64-apple-ios-sim x86_64-apple-ios - run: pnpm install - run: pnpm run bootstrap env: CMAKE_RN_TRIPLETS: arm64;x86_64-apple-ios-sim - FERRIC_TARGETS: aarch64-apple-ios-sim - - run: pnpm run pod-install + FERRIC_TARGETS: aarch64-apple-ios-sim,x86_64-apple-ios + # Mirrors React Native's scripts/xcode/ccache.conf, which only applied + # while ccache ran through their wrapper script (it sets CCACHE_CONFIGPATH + # to it) and so no longer does now that it runs as a compiler launcher. + # Without this sloppiness Xcode's modules, PCH and index-store flags leave + # ccache treating almost every compile as uncacheable. + - name: Tune ccache for Xcode + run: | + ccache --set-config sloppiness=clang_index_store,file_stat_matches,include_file_ctime,include_file_mtime,ivfsoverlay,pch_defines,modules,system_headers,time_macros + ccache --set-config file_clone=true + ccache --set-config depend_mode=true + ccache --set-config inode_cache=true + # Must precede `pod install`: react-native-test-app embeds the resources + # declared in app.json when generating the workspace, skipping missing + # ones, and the app would then expect a Metro dev server at runtime. + # `--assets-dest dist` lands assets in dist/assets, as app.json expects. + - name: Bundle test app + run: pnpm exec react-native bundle --entry-file index.ts --platform ios --dev false --minify false --bundle-output dist/main.ios.jsbundle --assets-dest dist working-directory: apps/test-app - - name: Run tests (iOS) - run: pnpm run test:ios:allTests - # TODO: Enable release mode when it works - # run: pnpm run test:ios:allTests --mode Release + # No USE_CCACHE: it points CC/CXX at React Native's ccache-clang.sh, whose + # bare `clang` resolves to setup-cpp's LLVM instead of Xcode's, breaking + # every system module. Ccache goes on the xcodebuild invocation instead. + # + # Retries the intermittent CocoaPods/CocoaPods#12866 "pathname contains + # null byte" crash, and only that. Drop once CocoaPods > 1.17.0 fixes it. + - name: Install pods + shell: bash working-directory: apps/test-app + run: | + for attempt in 1 2 3; do + if pnpm run pod-install 2>&1 | tee "$RUNNER_TEMP/pod-install.log"; then + exit 0 + fi + if ! grep -q 'pathname contains null byte' "$RUNNER_TEMP/pod-install.log"; then + echo "::error::pod install failed for an unrelated reason" + exit 1 + fi + echo "::warning::pod install hit CocoaPods/CocoaPods#12866 (attempt ${attempt}/3), retrying" + done + echo "::error::pod install kept failing with CocoaPods/CocoaPods#12866" + exit 1 + # Raw xcodebuild output, not piped through xcbeautify — see #391. + # C_COMPILER_LAUNCHER keeps Xcode's own clang and just prefixes it with + # ccache; explicit modules needs opting in when a launcher is used. + - name: Build test app + run: xcodebuild archive -workspace ReactTestApp.xcworkspace -configuration Release -scheme ReactTestApp -destination "generic/platform=iOS Simulator" -archivePath ./build/test-app.xcarchive CODE_SIGN_IDENTITY="-" CODE_SIGNING_ALLOWED=YES C_COMPILER_LAUNCHER=ccache CLANG_ENABLE_EXPLICIT_MODULES_WITH_COMPILER_LAUNCHER=YES + working-directory: apps/test-app/ios + - name: Run test app + run: | + # Install the app + xcrun simctl install "$SIMULATOR_UDID" ./ios/build/test-app.xcarchive/Products/Applications/ReactTestApp.app + # Run Mocha Remote wrapping the launch of the app + pnpm exec mocha-remote --exit-on-error -- xcrun simctl launch --terminate-running-process --console-pty "$SIMULATOR_UDID" com.microsoft.ReactTestApp + working-directory: apps/test-app + env: + MOCHA_REMOTE_CONTEXT: allTests test-macos: # Disabling this on main for now, as initializing the template takes a long time and # we don't have macOS-specific code yet. Currently also blocked on react-native-macos: diff --git a/packages/ferric/src/build.ts b/packages/ferric/src/build.ts index 3e5236ac..6cda0582 100644 --- a/packages/ferric/src/build.ts +++ b/packages/ferric/src/build.ts @@ -207,6 +207,7 @@ export const buildCommand = new Command("build") if (isAppleSupported()) { if (process.arch === "arm64") { targets.add("aarch64-apple-ios-sim"); + targets.add("x86_64-apple-ios"); } } logNotice( diff --git a/packages/host/src/node/cli/apple.ts b/packages/host/src/node/cli/apple.ts index 1defac91..ee2fe3cb 100644 --- a/packages/host/src/node/cli/apple.ts +++ b/packages/host/src/node/cli/apple.ts @@ -508,7 +508,7 @@ export async function linkXcframework({ }); assert( framework, - `Failed to find a framework slice matching: ${JSON.stringify(expectedSlice)}`, + `Failed to find a framework slice of '${modulePath}' matching: ${JSON.stringify(expectedSlice)}`, ); const originalFrameworkPath = path.join(