From 79122abe8a24ad085c241f12fffb2e36f1a21812 Mon Sep 17 00:00:00 2001 From: Riccardo Cipolleschi Date: Wed, 2 Aug 2023 09:42:56 -0700 Subject: [PATCH] Split Hermes build for iOS on different executors to speed up CI and Releases (#38619) Summary: This PR splits the build of Hermes for iOS in multiple jobs. Before, we were building all the slices of Hermes serially. So, we were: - building the hermesc - building hermes for iPhone - building hermes for iPhonesimulator - building hermes for Macos - building hermes for Catalyst - packaging the framework This job was taking up to 45-50 minutes. The the four slices (iPhone, iPhonesimulator, Macos, Catalyst) can be parallelized to harvest a speedup in execution. The following tables contains the executions before and after this change. - Full Clean Build -> Before: 51' 35" | After: 17'33" ( 3x improvement) | BEFORE | AFTER | | --- | --- | | Screenshot 2023-07-28 at 11 48 24 | Screenshot 2023-07-28 at 11 16 32 | | Total time (critical path): `build_hermes_macos-Debug` = 51' 35" | Total time (critical path): `build_hermesc_apple` (2' 56") + `build_apple_slices_hermes-Debug-macosx` (9'23") + `build_hermes_macos-Debug` (5'14") = 17'33" | - Fully Cached Build -> Before: 4'35" | After: 32" ( 9x improvement) | BEFORE | AFTER | | --- | --- | | Screenshot 2023-07-28 at 14 38 12 | Screenshot 2023-07-28 at 16 12 17 | | Total Time (critical path): `build_hermes_macos-Debug` (4'35") | Total Time (critical path): `build_hermesc_apple` (7") + `build_apple_slices_hermes-Debug-macosx` (7") + `build_hermes_macos-Debug` (32") = 46" | ## Changelog: [Internal] - Split hermes build to speedup CI and Release Pull Request resolved: https://github.com/facebook/react-native/pull/38619 Test Plan: - CircleCI stays green - Hermes artifact still works for RNTester and app from the template Reviewed By: cortinico, dmytrorykun Differential Revision: D47896833 Pulled By: cipolleschi fbshipit-source-id: 3b9e8d5de9b2a6fb6671444fda09d77b96123ac2 --- .circleci/config.yml | 500 +++++++++++++----- .../sdks/hermes-engine/hermes-engine.podspec | 47 +- .../utils/build-apple-framework.sh | 27 +- .../utils/build-ios-framework.sh | 69 ++- 4 files changed, 486 insertions(+), 157 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4e60e5123b5283..9df0e80932f7f2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -65,8 +65,12 @@ references: hermes_workspace_release_cache_key: &hermes_workspace_release_cache_key v2-hermes-{{ .Environment.CIRCLE_JOB }}-release-{{ checksum "/tmp/hermes/hermesversion" }}-{{ checksum "/tmp/react-native-version" }}-{{ checksum "packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh" }} hermes_linux_cache_key: &hermes_linux_cache_key v1-hermes-{{ .Environment.CIRCLE_JOB }}-linux-{{ checksum "/tmp/hermes/hermesversion" }}-{{ checksum "/tmp/react-native-version" }} hermes_windows_cache_key: &hermes_windows_cache_key v2-hermes-{{ .Environment.CIRCLE_JOB }}-windows-{{ checksum "/Users/circleci/project/tmp/hermes/hermesversion" }}-{{ checksum "/tmp/react-native-version" }} + hermesc_apple_cache_key: &hermesc_apple_cache_key v2-hermesc-apple-{{ checksum "/tmp/hermes/hermesversion" }}-{{ checksum "/tmp/react-native-version" }} + hermes_apple_slices_cache_key: &hermes_apple_slices_cache_key v2-hermes-apple-{{ checksum "/tmp/hermes/hermesversion" }}-{{ checksum "/tmp/react-native-version" }}-{{ checksum "packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh" }} hermes_tarball_debug_cache_key: &hermes_tarball_debug_cache_key v4-hermes-tarball-debug-{{ checksum "/tmp/hermes/hermesversion" }}-{{ checksum "/tmp/react-native-version" }} hermes_tarball_release_cache_key: &hermes_tarball_release_cache_key v3-hermes-tarball-release-{{ checksum "/tmp/hermes/hermesversion" }}-{{ checksum "/tmp/react-native-version" }} + hermes_macosx_bin_release_cache_key: &hermes_macosx_bin_release_cache_key v1-hermes-release-macosx-{{ checksum "/tmp/hermes/hermesversion" }}-{{ checksum "/tmp/react-native-version" }} + hermes_macosx_bin_debug_cache_key: &hermes_macosx_bin_debug_cache_key v1-hermes-debug-macosx-{{ checksum "/tmp/hermes/hermesversion" }}-{{ checksum "/tmp/react-native-version" }} pods_cache_key: &pods_cache_key v10-pods-{{ .Environment.CIRCLE_JOB }}-{{ checksum "packages/rn-tester/Podfile.lock.bak" }}-{{ checksum "packages/rn-tester/Podfile" }} windows_yarn_cache_key: &windows_yarn_cache_key v1-win-yarn-cache-{{ arch }}-{{ checksum "yarn.lock" }} windows_choco_cache_key: &windows_choco_cache_key v1-win-choco-cache-{{ .Environment.CIRCLE_JOB }} @@ -427,68 +431,115 @@ commands: key: *hermes_tarball_release_cache_key paths: *hermes_tarball_cache_paths - with_hermesc_span: - description: "Makes hermesc available to the provided steps, if hermesc is present." + store_hermes_apple_artifacts: + description: Stores the tarball and the osx binaries parameters: flavor: default: "Debug" description: The Hermes build type. Must be one of "Debug", "Release". type: enum enum: ["Debug", "Release"] - steps: - type: steps steps: - - export_hermesc: - flavor: << parameters.flavor >> - - steps: << parameters.steps >> - - export_hermesc: - flavor: << parameters.flavor >> + - when: + condition: + equal: [ << parameters.flavor >>, "Debug"] + steps: + - store_artifacts: + path: /tmp/hermes/hermes-runtime-darwin/hermes-ios-debug.tar.gz + - when: + condition: + equal: [ << parameters.flavor >>, "Release"] + steps: + - store_artifacts: + path: /tmp/hermes/hermes-runtime-darwin/hermes-ios-release.tar.gz + - store_artifacts: + path: /tmp/hermes/osx-bin/<< parameters.flavor >>/hermesc - export_hermesc: - description: "Configures hermesc for use in Hermes builds when possible. The binary is built by either of the macOS or iOS builds, and may be cached by previous builds." + stop_job_if_apple_artifacts_are_there: + description: Stops the current job if there are already the required artifacts + parameters: + flavor: + default: "All" + description: The flavor of artifacts to check. Must be one of "Debug", "Release" or "All" + type: enum + enum: ["Debug", "Release", "All"] + steps: + - when: + condition: + equal: [ << parameters.flavor >>, "All"] + steps: + - run: + name: "Stop if tarballs are present" + command: | + if [[ -f /tmp/hermes/Release_tarball_present && -f /tmp/hermes/Debug_tarball_present && -f /tmp/hermes/Release_osx_bin && -f /tmp/hermes/Debug_osx_bin ]]; then + echo "Tarball and osx-bin present. Halting this job" + circleci-agent step halt + fi + - when: + condition: + not: + equal: [ << parameters.flavor >>, "All"] + steps: + - run: + name: "Stop if tarballs are present" + command: | + TARBALL_PATH=/tmp/hermes/<< parameters.flavor >>_tarball_present + OSX_BIN_PATH=/tmp/hermes/<< parameters.flavor >>_osx_bin + + if [[ -f "$OSX_BIN_PATH" && -f "$TARBALL_PATH" ]]; then + echo "[HERMES] Tarball and hermesc binary present. Halting this job" + circleci-agent step halt + else + echo "[HERMES] Tarball not found. Building." + fi + check_if_tarball_is_present: + description: "Checks if the tarball of a specific Flavor is present and adds a marker file" parameters: flavor: default: "Debug" - description: The Hermes build type. Must be one of "Debug", "Release". + description: The flavor of artifacts to check. Must be one of "Debug" or "Release" type: enum enum: ["Debug", "Release"] - artifacts_dir: - type: string - default: *hermes_osxbin_artifacts_dir steps: - run: - name: "Export path to HermesC if available" + name: Check if << parameters.flavor >> tarball is there command: | - # Although the hermesc binary built by debug and release jobs is - # identical, we need to store it in distinct paths as Circle CI - # cannot have two different jobs write to the same path in - # artifacts. - mkdir -p << parameters.artifacts_dir >>/Debug << parameters.artifacts_dir >>/Release - hermesc_artifacts_path=<< parameters.artifacts_dir >>/<< parameters.flavor >>/hermesc - - hermesc_bin_path=bin/hermesc - hermes_build_dir_macos=$(pwd)/packages/react-native/sdks/hermes/build_macosx - hermes_build_dir_ios=$(pwd)/packages/react-native/sdks/hermes/build_iphoneos - - function export_hermesc_cmake_path { - build_dir=$1 - hermesc_bin=$build_dir/$hermesc_bin_path - cmake_path=$build_dir/ImportHermesc.cmake - - if [[ -f $cmake_path ]]; then - echo "export HERMES_OVERRIDE_HERMESC_PATH=$cmake_path" >> $BASH_ENV - fi - - if [[ ! -f $hermesc_artifacts_path ]]; then - cp $hermesc_bin $hermesc_artifacts_path - fi - } + FLAVOR=debug + if [[ << parameters.flavor >> == "Release" ]]; then + FLAVOR=release + fi - if [[ -f $hermes_build_dir_macos/$hermesc_bin_path ]]; then - export_hermesc_cmake_path $hermes_build_dir_macos - elif [[ -f $hermes_build_dir_ios/$hermesc_bin_path ]]; then - export_hermesc_cmake_path $hermes_build_dir_ios + if [[ -f "/tmp/hermes/hermes-runtime-darwin/hermes-ios-$FLAVOR.tar.gz" ]]; then + echo "[HERMES TARBALL] Found the << parameters.flavor >> tarball" + touch /tmp/hermes/<< parameters.flavor >>_tarball_present + fi + check_if_osx_bin_is_present: + description: "Checks if the osx bin of a specific Flavor is present and adds a marker file" + parameters: + flavor: + default: "Debug" + description: The flavor of artifacts to check. Must be one of "Debug" or "Release" + type: enum + enum: ["Debug", "Release"] + steps: + - run: + name: Check if macosx binary is there + command: | + if [[ -d /tmp/hermes/osx-bin/<< parameters.flavor >> ]]; then + echo "[HERMES MACOSX BIN] Found the osx bin << parameters.flavor >>" + touch /tmp/hermes/<< parameters.flavor >>_osx_bin fi + setup_hermes_workspace: + description: "Setup Hermes Workspace" + steps: + - run: + name: Set up workspace + command: | + mkdir -p $HERMES_OSXBIN_ARTIFACTS_DIR ./packages/react-native/sdks/hermes + cp -r $HERMES_WS_DIR/hermes/* ./packages/react-native/sdks/hermes/. + cp -r ./packages/react-native/sdks/hermes-engine/utils ./packages/react-native/sdks/hermes/. + + # ------------------------- # JOBS @@ -1253,12 +1304,12 @@ jobs: name: Install dependencies command: | apt update - apt install -y wget git curl + + apt install -y wget git curl jq curl -sL https://deb.nodesource.com/setup_18.x | bash - apt install -y nodejs npm install --global yarn - checkout - - run_yarn - run: name: Set up Hermes workspace and caching command: | @@ -1274,8 +1325,10 @@ jobs: echo $HERMES_TAG_SHA > /tmp/hermes/hermesversion fi cat /tmp/hermes/hermesversion + - get_react_native_version - restore_cache: key: *hermes_workspace_cache_key + - run_yarn - run: name: Download Hermes tarball command: | @@ -1289,12 +1342,44 @@ jobs: paths: - /tmp/hermes/download/ - /tmp/hermes/hermes/ + # Check if we already built the tarball + # if yes, we can skip the building and we can skip some jobs building + - restore_cache: + keys: + - *hermes_tarball_release_cache_key + - check_if_tarball_is_present: + flavor: Release + - restore_cache: + keys: + - *hermes_tarball_debug_cache_key + - check_if_tarball_is_present: + flavor: Debug + - restore_cache: + keys: + - *hermes_macosx_bin_release_cache_key + - check_if_osx_bin_is_present: + flavor: Release + - restore_cache: + keys: + - *hermes_macosx_bin_debug_cache_key + - check_if_osx_bin_is_present: + flavor: Debug - persist_to_workspace: root: *hermes_workspace_root paths: - download - hermes + - hermes-runtime-darwin + - osx-bin - hermesversion + - Release_tarball_present + - Debug_tarball_present + - Release_osx_bin + - Debug_osx_bin + - persist_to_workspace: + root: /tmp + paths: + - react-native-version build_hermesc_linux: docker: @@ -1341,105 +1426,205 @@ jobs: paths: - linux64-bin - build_hermes_macos: + build_hermesc_apple: + executor: reactnativeios + environment: + - HERMES_WS_DIR: *hermes_workspace_root + - HERMES_TARBALL_ARTIFACTS_DIR: *hermes_tarball_artifacts_dir + steps: + - *attach_hermes_workspace + - stop_job_if_apple_artifacts_are_there: + flavor: "All" + - checkout_code_with_cache + - get_react_native_version + - setup_hermes_workspace + - restore_cache: + key: *hermesc_apple_cache_key + - brew_install: + package: cmake + - run: + name: "Build HermesC Apple" + command: | + cd ./packages/react-native/sdks/hermes || exit 1 + . ./utils/build-apple-framework.sh + build_host_hermesc_if_needed + - save_cache: + key: *hermesc_apple_cache_key + paths: + - ./packages/react-native/sdks/hermes/build_host_hermesc + - persist_to_workspace: + root: ./packages/react-native/sdks/hermes/ + paths: + - build_host_hermesc + + build_apple_slices_hermes: parameters: + slice_base_cache_key: + default: *hermes_apple_slices_cache_key + type: string flavor: default: "Debug" description: The Hermes build type. Must be one of "Debug", "Release". type: enum enum: ["Debug", "Release"] + slice: + default: "iphoneos" + description: The Hermes Slice that this job has to build + type: enum + enum: ["macosx", "iphoneos", "iphonesimulator", "catalyst"] executor: reactnativeios environment: - HERMES_WS_DIR: *hermes_workspace_root - HERMES_TARBALL_ARTIFACTS_DIR: *hermes_tarball_artifacts_dir - HERMES_OSXBIN_ARTIFACTS_DIR: *hermes_osxbin_artifacts_dir steps: + - *attach_hermes_workspace + - stop_job_if_apple_artifacts_are_there: + flavor: << parameters.flavor >> + - checkout_code_with_cache + - get_react_native_version + - setup_hermes_workspace + - restore_cache: + key: *hermesc_apple_cache_key + - brew_install: + package: cmake + - restore_cache: + key: << parameters.slice_base_cache_key >>-<< parameters.slice >>-<< parameters.flavor >> + - run: + name: Build the Hermes << parameters.slice >> frameworks + command: | + cd ./packages/react-native/sdks/hermes || exit 1 + SLICE=<< parameters.slice >> + FLAVOR=<< parameters.flavor >> + FINAL_PATH=build_"$SLICE"_"$FLAVOR" + echo "Final path for this slice is: $FINAL_PATH" + + if [[ -d "$FINAL_PATH" ]]; then + echo "[HERMES] Skipping! Found the requested slice at $FINAL_PATH". + exit 0 + fi + + if [[ "$SLICE" == "macosx" ]]; then + echo "[HERMES] Building Hermes for MacOS" + BUILD_TYPE="<< parameters.flavor >>" ./utils/build-mac-framework.sh + else + echo "[HERMES] Building Hermes for iOS: $SLICE" + BUILD_TYPE="<< parameters.flavor >>" ./utils/build-ios-framework.sh "$SLICE" + fi + + echo "Moving from build_$SLICE to $FINAL_PATH" + mv build_"$SLICE" "$FINAL_PATH" + - save_cache: + key: << parameters.slice_base_cache_key >>-<< parameters.slice >>-<< parameters.flavor >> + paths: + - ./packages/react-native/sdks/hermes/build_<< parameters.slice >>_<< parameters.flavor >> + + build_hermes_macos: + parameters: + slice_base_cache_key: + default: *hermes_apple_slices_cache_key + type: string + flavor: + default: "Debug" + description: The Hermes build type. Must be one of "Debug", "Release". + type: enum + enum: ["Debug", "Release"] + executor: reactnativeios + environment: + - HERMES_WS_DIR: *hermes_workspace_root + - HERMES_TARBALL_ARTIFACTS_DIR: *hermes_tarball_artifacts_dir + steps: + - *attach_hermes_workspace + # Try to store the artifacts if they are already in the workspace + - store_hermes_apple_artifacts: + flavor: << parameters.flavor >> + - stop_job_if_apple_artifacts_are_there: + flavor: << parameters.flavor >> - checkout_code_with_cache - run_yarn - - *attach_hermes_workspace - get_react_native_version + - brew_install: + package: cmake + - setup_hermes_workspace + - restore_cache: + key: << parameters.slice_base_cache_key >>-macosx-<< parameters.flavor >> + - restore_cache: + key: << parameters.slice_base_cache_key >>-iphoneos-<< parameters.flavor >> + - restore_cache: + key: << parameters.slice_base_cache_key >>-iphonesimulator-<< parameters.flavor >> + - restore_cache: + key: << parameters.slice_base_cache_key >>-catalyst-<< parameters.flavor >> + - run: + name: "Move back build folders" + command: | + cd ./packages/react-native/sdks/hermes || exit 1 + mv build_macosx_<< parameters.flavor >> build_macosx + mv build_iphoneos_<< parameters.flavor >> build_iphoneos + mv build_iphonesimulator_<< parameters.flavor >> build_iphonesimulator + mv build_catalyst_<< parameters.flavor >> build_catalyst + - run: + name: "Prepare destroot folder" + command: | + cd ./packages/react-native/sdks/hermes || exit 1 + . ./utils/build-apple-framework.sh + prepare_dest_root_for_ci + - run: + name: "Create fat framework for iOS" + command: | + cd ./packages/react-native/sdks/hermes || exit 1 + echo "[HERMES] Creating the universal framework" + ./utils/build-ios-framework.sh build_framework + - run: + name: Package the Hermes Apple frameworks + command: | + BUILD_TYPE="<< parameters.flavor >>" + echo "Packaging Hermes Apple frameworks for $BUILD_TYPE build type" + + TARBALL_OUTPUT_DIR=$(mktemp -d /tmp/hermes-tarball-output-XXXXXXXX) + + TARBALL_FILENAME=$(node ./packages/react-native/scripts/hermes/get-tarball-name.js --buildType "$BUILD_TYPE") + + echo "Packaging Hermes Apple frameworks for $BUILD_TYPE build type" + + TARBALL_OUTPUT_PATH=$(node ./packages/react-native/scripts/hermes/create-tarball.js \ + --inputDir ./packages/react-native/sdks/hermes \ + --buildType "$BUILD_TYPE" \ + --outputDir $TARBALL_OUTPUT_DIR) + + echo "Hermes tarball saved to $TARBALL_OUTPUT_PATH" + + mkdir -p $HERMES_TARBALL_ARTIFACTS_DIR + cp $TARBALL_OUTPUT_PATH $HERMES_TARBALL_ARTIFACTS_DIR/. + + mkdir -p /tmp/hermes/osx-bin/<< parameters.flavor >> + cp ./packages/react-native/sdks/hermes/build_macosx/bin/* /tmp/hermes/osx-bin/<< parameters.flavor >> - when: condition: equal: [ << parameters.flavor >>, "Debug"] steps: - - restore_cache: - keys: - - *hermes_workspace_debug_cache_key + - save_cache: + key: *hermes_tarball_debug_cache_key + paths: *hermes_tarball_cache_paths + - save_cache: + key: *hermes_macosx_bin_debug_cache_key + paths: /tmp/hermes/osx-bin/Debug - when: condition: equal: [ << parameters.flavor >>, "Release"] steps: - - restore_cache: - keys: - - *hermes_workspace_release_cache_key - - run: - name: Set up workspace - command: | - mkdir -p $HERMES_OSXBIN_ARTIFACTS_DIR ./packages/react-native/sdks/hermes - cp -r $HERMES_WS_DIR/hermes/* ./packages/react-native/sdks/hermes/. - cp -r ./packages/react-native/sdks/hermes-engine/utils ./packages/react-native/sdks/hermes/. - - brew_install: - package: cmake - - with_hermes_tarball_cache_span: + - save_cache: + key: *hermes_tarball_release_cache_key + paths: *hermes_tarball_cache_paths + - save_cache: + key: *hermes_macosx_bin_release_cache_key + paths: /tmp/hermes/osx-bin/Release + - store_hermes_apple_artifacts: flavor: << parameters.flavor >> - steps: - - with_hermesc_span: - flavor: << parameters.flavor >> - steps: - - run: - name: Build the Hermes Mac frameworks - command: | - cd ./packages/react-native/sdks/hermes || exit 1 - BUILD_TYPE="<< parameters.flavor >>" ./utils/build-mac-framework.sh - - run: - name: Build the Hermes iOS frameworks - command: | - cd ./packages/react-native/sdks/hermes || exit 1 - BUILD_TYPE="<< parameters.flavor >>" ./utils/build-ios-framework.sh - - run: - name: Package the Hermes Apple frameworks - command: | - BUILD_TYPE="<< parameters.flavor >>" - echo "Packaging Hermes Apple frameworks for $BUILD_TYPE build type" - - TARBALL_OUTPUT_DIR=$(mktemp -d /tmp/hermes-tarball-output-XXXXXXXX) - - TARBALL_FILENAME=$(node ./packages/react-native/scripts/hermes/get-tarball-name.js --buildType "$BUILD_TYPE") - - echo "Packaging Hermes Apple frameworks for $BUILD_TYPE build type" - - TARBALL_OUTPUT_PATH=$(node ./packages/react-native/scripts/hermes/create-tarball.js \ - --inputDir ./packages/react-native/sdks/hermes \ - --buildType "$BUILD_TYPE" \ - --outputDir $TARBALL_OUTPUT_DIR) - - echo "Hermes tarball saved to $TARBALL_OUTPUT_PATH" - - mkdir -p $HERMES_TARBALL_ARTIFACTS_DIR - cp $TARBALL_OUTPUT_PATH $HERMES_TARBALL_ARTIFACTS_DIR/. - - when: - condition: - equal: [ << parameters.flavor >>, "Debug"] - steps: - - save_cache: - key: *hermes_workspace_debug_cache_key - paths: *hermes_workspace_macos_cache_paths - - when: - condition: - equal: [ << parameters.flavor >>, "Release"] - steps: - - save_cache: - key: *hermes_workspace_release_cache_key - paths: *hermes_workspace_macos_cache_paths - - store_artifacts: - path: *hermes_tarball_artifacts_dir - - store_artifacts: - path: *hermes_osxbin_artifacts_dir - - persist_to_workspace: - root: /tmp/hermes/ - paths: - - hermes-runtime-darwin - - osx-bin + - persist_to_workspace: + root: /tmp/hermes/ + paths: + - hermes-runtime-darwin + - osx-bin build_hermesc_windows: executor: @@ -1742,13 +1927,23 @@ workflows: latest : false dryrun: true - prepare_hermes_workspace - - test_ios_rntester_hermes_xcode_integration + # - test_ios_rntester_hermes_xcode_integration - build_hermesc_linux: requires: - prepare_hermes_workspace - - build_hermes_macos: + - build_hermesc_apple: requires: - prepare_hermes_workspace + - build_apple_slices_hermes: + requires: + - build_hermesc_apple + matrix: + parameters: + flavor: ["Debug", "Release"] + slice: ["macosx", "iphoneos", "iphonesimulator", "catalyst"] + - build_hermes_macos: + requires: + - build_apple_slices_hermes matrix: parameters: flavor: ["Debug", "Release"] @@ -1906,17 +2101,24 @@ workflows: filters: *only_release_tags requires: - prepare_hermes_workspace - - build_hermes_macos: + - build_apple_slices_hermes: filters: *only_release_tags requires: - prepare_hermes_workspace matrix: parameters: flavor: ["Debug", "Release"] + slice: ["macosx", "iphoneos", "iphonesimulator", "catalyst"] - build_hermesc_windows: filters: *only_release_tags requires: - prepare_hermes_workspace + - build_hermes_macos: + requires: + - build_apple_slices_hermes + matrix: + parameters: + flavor: ["Debug", "Release"] # This job will trigger when a version tag is pushed (by package_release) - build_npm_package: name: build_and_publish_npm_package @@ -1927,6 +2129,47 @@ workflows: - build_hermes_macos - build_hermesc_windows + package_and_publish_release_dryrun: + when: + and: + - equal: [ false, << pipeline.parameters.run_release_workflow >> ] + - equal: [ false, << pipeline.parameters.run_nightly_workflow >> ] + jobs: + - prepare_package_for_release: + name: prepare_package_for_release + version: '' + latest : false + dryrun: true + - prepare_hermes_workspace: + requires: + - prepare_package_for_release + - build_hermesc_linux: + requires: + - prepare_hermes_workspace + - build_apple_slices_hermes: + requires: + - prepare_hermes_workspace + matrix: + parameters: + flavor: ["Debug", "Release"] + slice: ["macosx", "iphoneos", "iphonesimulator", "catalyst"] + - build_hermesc_windows: + requires: + - prepare_hermes_workspace + - build_hermes_macos: + requires: + - build_apple_slices_hermes + matrix: + parameters: + flavor: ["Debug", "Release"] + - build_npm_package: + name: build_and_publish_npm_package + release_type: "dry-run" + requires: + - build_hermesc_linux + - build_hermes_macos + - build_hermesc_windows + analysis: when: and: @@ -1947,15 +2190,22 @@ workflows: - build_hermesc_linux: requires: - prepare_hermes_workspace - - build_hermes_macos: + - build_apple_slices_hermes: requires: - prepare_hermes_workspace matrix: parameters: flavor: ["Debug", "Release"] + slice: ["macosx", "iphoneos", "iphonesimulator", "catalyst"] - build_hermesc_windows: requires: - prepare_hermes_workspace + - build_hermes_macos: + requires: + - build_apple_slices_hermes + matrix: + parameters: + flavor: ["Debug", "Release"] - build_npm_package: release_type: "nightly" requires: diff --git a/packages/react-native/sdks/hermes-engine/hermes-engine.podspec b/packages/react-native/sdks/hermes-engine/hermes-engine.podspec index 681cb2c4d234a6..31e28215cb3f2c 100644 --- a/packages/react-native/sdks/hermes-engine/hermes-engine.podspec +++ b/packages/react-native/sdks/hermes-engine/hermes-engine.podspec @@ -31,7 +31,7 @@ Pod::Spec.new do |spec| spec.license = package['license'] spec.author = "Facebook" spec.source = source - spec.platforms = { :osx => "10.13", :ios => min_ios_version_supported } + spec.platforms = { :osx => "10.13", :ios => "13.4" } spec.preserve_paths = '**/*.*' spec.source_files = '' @@ -105,25 +105,30 @@ Pod::Spec.new do |spec| spec.prepare_command = ". #{react_native_path}/sdks/hermes-engine/utils/create-dummy-hermes-xcframework.sh" - CMAKE_BINARY = Pod::Executable::which!('cmake') - # NOTE: Script phases are sorted alphabetically inside Xcode project - spec.script_phases = [ - { - :name => '[RN] [1] Build Hermesc', - :script => <<-EOS - . "${REACT_NATIVE_PATH}/scripts/xcode/with-environment.sh" - export CMAKE_BINARY=${CMAKE_BINARY:-#{CMAKE_BINARY}} - . ${REACT_NATIVE_PATH}/sdks/hermes-engine/utils/build-hermesc-xcode.sh #{hermesc_path} - EOS - }, - { - :name => '[RN] [2] Build Hermes', - :script => <<-EOS - . "${REACT_NATIVE_PATH}/scripts/xcode/with-environment.sh" - export CMAKE_BINARY=${CMAKE_BINARY:-#{CMAKE_BINARY}} - . ${REACT_NATIVE_PATH}/sdks/hermes-engine/utils/build-hermes-xcode.sh #{version} #{hermesc_path}/ImportHermesc.cmake - EOS - } - ] + # This podspec is also run in CI to build Hermes without using Pod install + # and sometimes CI fails because `Pod::Executable` does not exist if it is not run with Pod Install. + if defined?(Pod::Executable.to_s) + puts "Const Defined!" + CMAKE_BINARY = Pod::Executable::which!('cmake') + # NOTE: Script phases are sorted alphabetically inside Xcode project + spec.script_phases = [ + { + :name => '[RN] [1] Build Hermesc', + :script => <<-EOS + . "${REACT_NATIVE_PATH}/scripts/xcode/with-environment.sh" + export CMAKE_BINARY=${CMAKE_BINARY:-#{CMAKE_BINARY}} + . ${REACT_NATIVE_PATH}/sdks/hermes-engine/utils/build-hermesc-xcode.sh #{hermesc_path} + EOS + }, + { + :name => '[RN] [2] Build Hermes', + :script => <<-EOS + . "${REACT_NATIVE_PATH}/scripts/xcode/with-environment.sh" + export CMAKE_BINARY=${CMAKE_BINARY:-#{CMAKE_BINARY}} + . ${REACT_NATIVE_PATH}/sdks/hermes-engine/utils/build-hermes-xcode.sh #{version} #{hermesc_path}/ImportHermesc.cmake + EOS + } + ] + end end end diff --git a/packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh b/packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh index 429707c356c9f0..ec7bb17abaf179 100755 --- a/packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh +++ b/packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh @@ -87,11 +87,18 @@ function configure_apple_framework { popd > /dev/null || exit 1 } +function build_host_hermesc_if_needed { + if [[ ! -f "$IMPORT_HERMESC_PATH" ]]; then + build_host_hermesc + else + echo "[HermesC] Skipping! Found an existent hermesc already at: $IMPORT_HERMESC_PATH" + fi +} + # Utility function to build an Apple framework function build_apple_framework { # Only build host HermesC if no file found at $IMPORT_HERMESC_PATH - [ ! -f "$IMPORT_HERMESC_PATH" ] && - build_host_hermesc + build_host_hermesc_if_needed # Confirm ImportHermesc.cmake is now available. [ ! -f "$IMPORT_HERMESC_PATH" ] && @@ -121,6 +128,22 @@ function build_apple_framework { popd > /dev/null || exit 1 } +function prepare_dest_root_for_ci { + mkdir -p "destroot/Library/Frameworks/macosx" "destroot/bin" "destroot/Library/Frameworks/iphoneos" "destroot/Library/Frameworks/iphonesimulator" "destroot/Library/Frameworks/catalyst" + + cp -R "./build_macosx/API/hermes/hermes.framework"* "destroot/Library/Frameworks/macosx" + cp -R "./build_iphoneos/API/hermes/hermes.framework"* "destroot/Library/Frameworks/iphoneos" + cp -R "./build_iphonesimulator/API/hermes/hermes.framework"* "destroot/Library/Frameworks/iphonesimulator" + cp -R "./build_catalyst/API/hermes/hermes.framework"* "destroot/Library/Frameworks/catalyst" + cp "./build_macosx/bin/"* "destroot/bin" + + mkdir -p destroot/include/hermes/Public destroot/include/jsi + + cp public/hermes/Public/*.h destroot/include/hermes/Public + cp API/hermes/*.h destroot/include/hermes + cp "$JSI_PATH"/jsi/*.h destroot/include/jsi +} + # Accepts an array of frameworks and will place all of # the architectures into an universal folder and then remove # the merged frameworks from destroot diff --git a/packages/react-native/sdks/hermes-engine/utils/build-ios-framework.sh b/packages/react-native/sdks/hermes-engine/utils/build-ios-framework.sh index 6b3b8fe2f8cd53..009bddbd7328a2 100755 --- a/packages/react-native/sdks/hermes-engine/utils/build-ios-framework.sh +++ b/packages/react-native/sdks/hermes-engine/utils/build-ios-framework.sh @@ -4,18 +4,69 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -# shellcheck source=xplat/js/react-native-github/sdks/hermes-engine/utils/build-apple-framework.sh -CURR_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" -. "${CURR_SCRIPT_DIR}/build-apple-framework.sh" +# Given a specific target, retrieve the right architecture for it +# $1 the target you want to build. Allowed values: iphoneos, iphonesimulator, catalyst +function get_architecture { + if [[ $1 == "iphoneos" ]]; then + echo "arm64" + elif [[ $1 == "iphonesimulator" ]]; then + echo "x86_64;arm64" + elif [[ $1 == "catalyst" ]]; then + echo "x86_64;arm64" + else + echo "Error: unknown arkitecture passed $1" + exit 1 + fi +} -if [ ! -d destroot/Library/Frameworks/universal/hermes.xcframework ]; then +# build a single framework +# $1 is the target to build +function build_framework { + if [ ! -d destroot/Library/Frameworks/universal/hermes.xcframework ]; then ios_deployment_target=$(get_ios_deployment_target) - build_apple_framework "iphoneos" "arm64" "$ios_deployment_target" - build_apple_framework "iphonesimulator" "x86_64;arm64" "$ios_deployment_target" - build_apple_framework "catalyst" "x86_64;arm64" "$ios_deployment_target" + architecture=$(get_architecture "$1") - create_universal_framework "iphoneos" "iphonesimulator" "catalyst" -else + build_apple_framework "$1" "$architecture" "$ios_deployment_target" + else echo "Skipping; Clean \"destroot\" to rebuild". + fi +} + +# group the frameworks together to create a universal framework +function build_universal_framework { + if [ ! -d destroot/Library/Frameworks/universal/hermes.xcframework ]; then + create_universal_framework "iphoneos" "iphonesimulator" "catalyst" + else + echo "Skipping; Clean \"destroot\" to rebuild". + fi +} + +# single function that builds sequentially iphoneos, iphonesimulator and catalyst +# this is used to preserve backward compatibility +function create_framework { + if [ ! -d destroot/Library/Frameworks/universal/hermes.xcframework ]; then + ios_deployment_target=$(get_ios_deployment_target) + + build_framework "iphoneos" + build_framework "iphonesimulator" + build_framework "catalyst" + + build_universal_framework + else + echo "Skipping; Clean \"destroot\" to rebuild". + fi +} + + +CURR_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" +# shellcheck source=xplat/js/react-native-github/sdks/hermes-engine/utils/build-apple-framework.sh +. "${CURR_SCRIPT_DIR}/build-apple-framework.sh" + +if [[ -z $1 ]]; then + create_framework +elif [[ $1 == "build_framework" ]]; then + build_universal_framework +else + build_framework "$1" fi