diff --git a/.github/workflows/microsoft-pr.yml b/.github/workflows/microsoft-pr.yml index 2c1b4500b3ccf4..ccc79bebd68947 100644 --- a/.github/workflows/microsoft-pr.yml +++ b/.github/workflows/microsoft-pr.yml @@ -132,6 +132,11 @@ jobs: permissions: {} uses: ./.github/workflows/microsoft-build-rntester.yml + build-spm-macos: + name: "Build SPM macOS" + permissions: {} + uses: ./.github/workflows/prebuild-macos-core.yml + # https://github.com/microsoft/react-native-macos/issues/2344 # Disable these tests because verdaccio hangs # test-react-native-macos-init: @@ -158,6 +163,7 @@ jobs: - yarn-constraints - javascript-tests - build-rntester + - build-spm-macos # - test-react-native-macos-init # - react-native-test-app-integration steps: diff --git a/.github/workflows/prebuild-macos-core.yml b/.github/workflows/prebuild-macos-core.yml new file mode 100644 index 00000000000000..774315388d005d --- /dev/null +++ b/.github/workflows/prebuild-macos-core.yml @@ -0,0 +1,196 @@ +name: Prebuild macOS Dependencies + +on: + workflow_call: # this directive allow us to call this workflow from other workflows + + +jobs: + build-rn-slice: + runs-on: macos-14 + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + flavor: ['Debug', 'Release'] + slice: ['macos'] + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Restore cache if present + id: restore-macos-slice + uses: actions/cache/restore@v4 + with: + key: v1-macos-core-${{ matrix.slice }}-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift') }}-${{ hashFiles('packages/react-native/scripts/ios-prebuild/setup.js') }} + path: packages/react-native/ + - name: Setup toolchain + if: steps.restore-macos-slice.outputs.cache-hit != 'true' + uses: ./.github/actions/microsoft-setup-toolchain + with: + platform: macos + node-version: '22' + xcode-developer-dir: '/Applications/Xcode_16.2.0.app' + - name: Yarn Install + if: steps.restore-macos-slice.outputs.cache-hit != 'true' + run: yarn install + shell: bash + - name: Download Hermes + if: steps.restore-macos-slice.outputs.cache-hit != 'true' + uses: actions/download-artifact@v4 + with: + name: hermes-darwin-bin-${{ matrix.flavor }} + path: /tmp/hermes/hermes-runtime-darwin + - name: Extract Hermes + if: steps.restore-macos-slice.outputs.cache-hit != 'true' + shell: bash + run: | + HERMES_TARBALL_ARTIFACTS_DIR=/tmp/hermes/hermes-runtime-darwin + if [ ! -d $HERMES_TARBALL_ARTIFACTS_DIR ]; then + echo "Hermes tarball artifacts dir not present ($HERMES_TARBALL_ARTIFACTS_DIR)." + exit 0 + fi + + TARBALL_FILENAME=$(node ./packages/react-native/scripts/hermes/get-tarball-name.js --buildType "${{ matrix.flavor }}") + TARBALL_PATH=$HERMES_TARBALL_ARTIFACTS_DIR/$TARBALL_FILENAME + + echo "Looking for $TARBALL_FILENAME in $HERMES_TARBALL_ARTIFACTS_DIR" + echo "$TARBALL_PATH" + + if [ ! -f $TARBALL_PATH ]; then + echo "Hermes tarball not present ($TARBALL_PATH). Build Hermes from source." + exit 0 + fi + + echo "Found Hermes tarball at $TARBALL_PATH" + echo "HERMES_ENGINE_TARBALL_PATH=$TARBALL_PATH" >> $GITHUB_ENV + - name: Download ReactNativeDependencies + uses: actions/download-artifact@v4 + with: + name: ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz + path: /tmp/third-party/ + - name: Extract ReactNativeDependencies + if: steps.restore-macos-slice.outputs.cache-hit != 'true' + shell: bash + run: | + # Extract ReactNativeDependencies + tar -xzf /tmp/third-party/ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz -C /tmp/third-party/ + + # Create destination folder + mkdir -p packages/react-native/third-party/ + + # Move the XCFramework in the destination directory + mv /tmp/third-party/packages/react-native/third-party/ReactNativeDependencies.xcframework packages/react-native/third-party/ReactNativeDependencies.xcframework + + VERSION=$(jq -r '.version' package.json) + echo "$VERSION-${{matrix.flavor}}" > "packages/react-native/third-party/version.txt" + cat "packages/react-native/third-party/version.txt" + # Check destination directory + ls -lR packages/react-native/third-party/ + - name: Setup the workspace + if: steps.restore-macos-slice.outputs.cache-hit != 'true' + shell: bash + run: | + cd packages/react-native + node scripts/ios-prebuild.js -s -f "${{ matrix.flavor }}" + - name: Build React Native + if: steps.restore-macos-slice.outputs.cache-hit != 'true' + shell: bash + run: | + # This is going to be replaced by a CLI script + cd packages/react-native + node scripts/ios-prebuild -b -f "${{ matrix.flavor }}" -p "${{ matrix.slice }}" + - name: Upload headers + uses: actions/upload-artifact@v4 + with: + name: prebuild-macos-core-headers-${{ matrix.flavor }}-${{ matrix.slice }} + path: + packages/react-native/.build/headers + - name: Upload artifacts + uses: actions/upload-artifact@v4.3.4 + with: + name: prebuild-macos-core-slice-${{ matrix.flavor }}-${{ matrix.slice }} + path: | + packages/react-native/.build/output/spm/${{ matrix.flavor }}/Build/Products + - name: Save Cache + uses: actions/cache/save@v4 + if: ${{ github.ref == 'refs/heads/main' }} # To avoid that the cache explode + with: + key: v1-macos-core-${{ matrix.slice }}-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift') }}-${{ hashFiles('packages/react-native/scripts/ios-prebuild/setup.js') }} + path: | + packages/react-native/.build/output/spm/${{ matrix.flavor }}/Build/Products + packages/react-native/.build/headers + + compose-xcframework: + runs-on: macos-14 + timeout-minutes: 60 + needs: [build-rn-slice] + strategy: + fail-fast: false + matrix: + flavor: ['Debug', 'Release'] + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Restore cache if present + id: restore-macos-xcframework + uses: actions/cache/restore@v4 + with: + path: packages/react-native/.build/output/xcframeworks + key: v1-macos-core-xcframework-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift') }}-${{ hashFiles('packages/react-native/scripts/ios-prebuild/setup.js') }} + - name: Setup toolchain + if: steps.restore-macos-xcframework.outputs.cache-hit != 'true' + uses: ./.github/actions/microsoft-setup-toolchain + with: + platform: macos + node-version: '22' + xcode-developer-dir: '/Applications/Xcode_16.2.0.app' + - name: Yarn Install + if: steps.restore-macos-xcframework.outputs.cache-hit != 'true' + run: yarn install + shell: bash + - name: Download slice artifacts + if: steps.restore-macos-xcframework.outputs.cache-hit != 'true' + uses: actions/download-artifact@v4 + with: + pattern: prebuild-macos-core-slice-${{ matrix.flavor }}-* + path: packages/react-native/.build/output/spm/${{ matrix.flavor }}/Build/Products + merge-multiple: true + - name: Download headers + if: steps.restore-macos-xcframework.outputs.cache-hit != 'true' + uses: actions/download-artifact@v4 + with: + pattern: prebuild-macos-core-headers-${{ matrix.flavor }}-* + path: packages/react-native/.build/headers + merge-multiple: true + - name: Create XCFramework + if: steps.restore-macos-xcframework.outputs.cache-hit != 'true' + run: | + cd packages/react-native + node scripts/ios-prebuild -c -f "${{ matrix.flavor }}" + - name: Compress and Rename XCFramework + if: steps.restore-macos-xcframework.outputs.cache-hit != 'true' + run: | + cd packages/react-native/.build/output/xcframeworks/${{matrix.flavor}} + tar -cz -f ../ReactCoreMacOS${{matrix.flavor}}.xcframework.tar.gz React.xcframework + - name: Compress and Rename dSYM + if: steps.restore-macos-xcframework.outputs.cache-hit != 'true' + run: | + cd packages/react-native/.build/output/xcframeworks/${{matrix.flavor}}/Symbols + tar -cz -f ../../ReactCoreMacOS${{ matrix.flavor }}.framework.dSYM.tar.gz . + - name: Upload XCFramework Artifact + uses: actions/upload-artifact@v4 + with: + name: ReactCoreMacOS${{ matrix.flavor }}.xcframework.tar.gz + path: packages/react-native/.build/output/xcframeworks/ReactCoreMacOS${{matrix.flavor}}.xcframework.tar.gz + - name: Upload dSYM Artifact + uses: actions/upload-artifact@v4 + with: + name: ReactCoreMacOS${{ matrix.flavor }}.framework.dSYM.tar.gz + path: packages/react-native/.build/output/xcframeworks/ReactCoreMacOS${{matrix.flavor}}.framework.dSYM.tar.gz + - name: Save cache if present + if: ${{ github.ref == 'refs/heads/main' }} # To avoid that the cache explode + uses: actions/cache/save@v4 + with: + path: | + packages/react-native/.build/output/xcframeworks/ReactCoreMacOS${{matrix.flavor}}.xcframework.tar.gz + packages/react-native/.build/output/xcframeworks/ReactCoreMacOS${{matrix.flavor}}.framework.dSYM.tar.gz + key: v1-macos-core-xcframework-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift') }}-${{ hashFiles('packages/react-native/scripts/ios-prebuild/setup.js') }} diff --git a/packages/react-native/Package.swift b/packages/react-native/Package.swift index c387085ea2368f..b814bfc537e9e9 100644 --- a/packages/react-native/Package.swift +++ b/packages/react-native/Package.swift @@ -246,7 +246,7 @@ let reactJsErrorHandler = RNTarget( let reactGraphicsApple = RNTarget( name: .reactGraphicsApple, path: "ReactCommon/react/renderer/graphics/platform/ios", - linkedFrameworks: ["UIKit", "CoreGraphics"], + linkedFrameworks: ["CoreGraphics"], dependencies: [.reactDebug, .jsi, .reactUtils, .reactNativeDependencies] ) @@ -376,7 +376,6 @@ let reactFabric = RNTarget( "components/view/tests", "components/view/platform/android", "components/view/platform/windows", - "components/view/platform/macos", "components/scrollview/tests", "components/scrollview/platform/android", "mounting/tests", @@ -420,16 +419,13 @@ let reactFabricComponents = RNTarget( "components/modal/platform/cxx", "components/view/platform/android", "components/view/platform/windows", - "components/view/platform/macos", "components/textinput/platform/android", "components/text/platform/android", - "components/textinput/platform/macos", "components/text/tests", "textlayoutmanager/tests", "textlayoutmanager/platform/android", "textlayoutmanager/platform/cxx", "textlayoutmanager/platform/windows", - "textlayoutmanager/platform/macos", "conponents/rncore", // this was the old folder where RN Core Components were generated. If you ran codegen in the past, you might have some files in it that might make the build fail. ], dependencies: [.reactNativeDependencies, .reactCore, .reactJsiExecutor, .reactTurboModuleCore, .jsi, .logger, .reactDebug, .reactFeatureFlags, .reactUtils, .reactRuntimeScheduler, .reactCxxReact, .yoga, .reactRendererDebug, .reactGraphics, .reactFabric, .reactTurboModuleBridging], @@ -587,7 +583,7 @@ let targets = [ let package = Package( name: react, - platforms: [.iOS(.v15), .macCatalyst(SupportedPlatform.MacCatalystVersion.v13)], + platforms: [.iOS(.v15), .macOS(.v14), .macCatalyst(SupportedPlatform.MacCatalystVersion.v13)], products: [ .library( name: react, @@ -792,6 +788,13 @@ extension Target { .define("USE_HERMES", to: "1"), ] + defines + cxxCommonHeaderPaths + // Platform-specific framework linking + var conditionalLinkerSettings: [LinkerSetting] = linkerSettings + if name == "React-graphics-Apple" { + conditionalLinkerSettings.append(.linkedFramework("UIKit", .when(platforms: [.iOS, .visionOS]))) + conditionalLinkerSettings.append(.linkedFramework("AppKit", .when(platforms: [.macOS]))) + } + return .target( name: name, dependencies: dependencies, @@ -800,7 +803,7 @@ extension Target { sources: sources, publicHeadersPath: publicHeadersPath, cxxSettings: cxxSettings, - linkerSettings: linkerSettings + linkerSettings: conditionalLinkerSettings ) } } diff --git a/packages/react-native/scripts/ios-prebuild/cli.js b/packages/react-native/scripts/ios-prebuild/cli.js index 01301c800af717..ec3cf8d9f60a35 100644 --- a/packages/react-native/scripts/ios-prebuild/cli.js +++ b/packages/react-native/scripts/ios-prebuild/cli.js @@ -17,6 +17,7 @@ import type {BuildFlavor, Destination, Platform} from './types'; const platforms /*: $ReadOnlyArray */ = [ 'ios', 'ios-simulator', + 'macos', 'mac-catalyst', ]; @@ -25,6 +26,7 @@ const platforms /*: $ReadOnlyArray */ = [ const platformToDestination /*: $ReadOnly<{|[Platform]: Destination|}> */ = { ios: 'iOS', 'ios-simulator': 'iOS Simulator', + 'macos': 'macOS', 'mac-catalyst': 'macOS,variant=Mac Catalyst', };