diff --git a/.circleci/config.yml b/.circleci/config.yml index d184ff02f2899f..520f0da0af1573 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -987,6 +987,7 @@ jobs: environment: - HERMES_WS_DIR: *hermes_workspace_root steps: + - checkout - *attach_hermes_workspace - restore_cache: key: v1-hermes-{{ .Environment.CIRCLE_JOB }}-{{ checksum "/tmp/hermes/hermesversion" }} @@ -994,6 +995,7 @@ jobs: name: Set up workspace command: | mkdir -p /tmp/hermes/osx-bin + cp ~/react-native/sdks/hermes-engine/utils/* "$HERMES_WS_DIR/hermes/utils/." - run: name: Install dependencies command: | diff --git a/package.json b/package.json index 4248508691a2af..5a2f3e0cf6c213 100644 --- a/package.json +++ b/package.json @@ -55,8 +55,8 @@ "scripts/react_native_pods.rb", "scripts/cocoapods/flipper.rb", "scripts/react-native-xcode.sh", + "sdks/hermes-engine", "sdks/hermesc", - "sdks/hermes-engine.podspec", "template.config.js", "template", "!template/node_modules", diff --git a/scripts/react_native_pods.rb b/scripts/react_native_pods.rb index 7fb5cc31de3ba8..ad2210b66cb490 100644 --- a/scripts/react_native_pods.rb +++ b/scripts/react_native_pods.rb @@ -630,8 +630,9 @@ def downloadAndConfigureHermesSource(react_native_path) Pod::UI.puts "[Hermes] Extracting Hermes tarball (#{hermes_tag_sha.slice(0,6)})" system("tar -zxf #{hermes_tarball_path} --strip-components=1 --directory #{hermes_dir}") - # TODO: Integrate this temporary hermes-engine.podspec into the actual one located in facebook/hermes - system("cp #{sdks_dir}/hermes-engine.podspec #{hermes_dir}/hermes-engine.podspec") + # Use React Native's own scripts to build Hermes + system("cp #{sdks_dir}/hermes-engine/hermes-engine.podspec #{hermes_dir}/hermes-engine.podspec") + system("cp #{sdks_dir}/hermes-engine/utils/* #{hermes_dir}/utils/.") hermes_dir end diff --git a/sdks/hermes-engine.podspec b/sdks/hermes-engine/hermes-engine.podspec similarity index 94% rename from sdks/hermes-engine.podspec rename to sdks/hermes-engine/hermes-engine.podspec index c4b28c6071ffe8..3f6594d5a525b8 100644 --- a/sdks/hermes-engine.podspec +++ b/sdks/hermes-engine/hermes-engine.podspec @@ -38,7 +38,6 @@ Pod::Spec.new do |spec| spec.xcconfig = { "CLANG_CXX_LANGUAGE_STANDARD" => "c++17", "CLANG_CXX_LIBRARY" => "compiler-default", "GCC_PREPROCESSOR_DEFINITIONS" => "HERMES_ENABLE_DEBUGGER=1" } - # TODO: Consider moving Hermes build scripts to react_native_pods.rb for greater control over when they're executed spec.prepare_command = <<-EOS # When true, debug build will be used. # See `build-apple-framework.sh` for details diff --git a/sdks/hermes-engine/utils/build-apple-framework.sh b/sdks/hermes-engine/utils/build-apple-framework.sh new file mode 100755 index 00000000000000..26faf2627fa3d6 --- /dev/null +++ b/sdks/hermes-engine/utils/build-apple-framework.sh @@ -0,0 +1,118 @@ +#!/bin/bash +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +if [ "$DEBUG" = true ]; then + BUILD_TYPE="Debug" +else + BUILD_TYPE="Release" +fi + +function command_exists { + command -v "${1}" > /dev/null 2>&1 +} + +if command_exists "cmake"; then + if command_exists "ninja"; then + BUILD_SYSTEM="Ninja" + else + BUILD_SYSTEM="Unix Makefiles" + fi +else + echo >&2 'CMake is required to install Hermes, install it with: brew install cmake' + exit 1 +fi + +function get_release_version { + ruby -rcocoapods-core -rjson -e "puts Pod::Specification.from_file('hermes-engine.podspec').version" +} + +function get_ios_deployment_target { + ruby -rcocoapods-core -rjson -e "puts Pod::Specification.from_file('hermes-engine.podspec').deployment_target('ios')" +} + +function get_mac_deployment_target { + ruby -rcocoapods-core -rjson -e "puts Pod::Specification.from_file('hermes-engine.podspec').deployment_target('osx')" +} + +# Build host hermes compiler for internal bytecode +function build_host_hermesc { + cmake -S . -B build_host_hermesc + cmake --build ./build_host_hermesc --target hermesc +} + +# Utility function to configure an Apple framework +function configure_apple_framework { + local build_cli_tools enable_bitcode + + if [[ $1 == iphoneos || $1 == catalyst ]]; then + enable_bitcode="true" + else + enable_bitcode="false" + fi + if [[ $1 == macosx ]]; then + build_cli_tools="true" + else + build_cli_tools="false" + fi + + cmake -S . -B "build_$1" -G "$BUILD_SYSTEM" \ + -DHERMES_APPLE_TARGET_PLATFORM:STRING="$1" \ + -DCMAKE_OSX_ARCHITECTURES:STRING="$2" \ + -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING="$3" \ + -DHERMES_ENABLE_DEBUGGER:BOOLEAN=true \ + -DHERMES_ENABLE_LIBFUZZER:BOOLEAN=false \ + -DHERMES_ENABLE_FUZZILLI:BOOLEAN=false \ + -DHERMES_ENABLE_TEST_SUITE:BOOLEAN=false \ + -DHERMES_ENABLE_BITCODE:BOOLEAN="$enable_bitcode" \ + -DHERMES_BUILD_APPLE_FRAMEWORK:BOOLEAN=true \ + -DHERMES_BUILD_APPLE_DSYM:BOOLEAN=true \ + -DHERMES_ENABLE_TOOLS:BOOLEAN="$build_cli_tools" \ + -DIMPORT_HERMESC:PATH="$PWD/build_host_hermesc/ImportHermesc.cmake" \ + -DCMAKE_INSTALL_PREFIX:PATH=../destroot \ + -DCMAKE_BUILD_TYPE="$BUILD_TYPE" +} + +# Utility function to build an Apple framework +function build_apple_framework { + echo "Building framework for $1 with architectures: $2" + + build_host_hermesc + [ ! -f "$PWD/build_host_hermesc/ImportHermesc.cmake" ] && + echo "Host hermesc is required to build apple frameworks!" + + configure_apple_framework "$1" "$2" "$3" + + if [[ "$BUILD_SYSTEM" == "Ninja" ]]; then + (cd "./build_$1" && ninja install/strip) + else + (cd "./build_$1" && make install/strip) + fi +} + +# Accepts an array of frameworks and will place all of +# the architectures into an universal folder and then remove +# the merged frameworks from destroot +function create_universal_framework { + cd ./destroot/Library/Frameworks || exit 1 + + local platforms=("$@") + local args="" + + echo "Creating universal framework for platforms: ${platforms[*]}" + + for i in "${!platforms[@]}"; do + args+="-framework ${platforms[$i]}/hermes.framework " + done + + mkdir universal + xcodebuild -create-xcframework $args -output "universal/hermes.xcframework" + + for platform in $@; do + rm -r "$platform" + done + + cd - || exit 1 +} diff --git a/sdks/hermes-engine/utils/build-ios-framework.sh b/sdks/hermes-engine/utils/build-ios-framework.sh new file mode 100755 index 00000000000000..e13598181d829c --- /dev/null +++ b/sdks/hermes-engine/utils/build-ios-framework.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +. ./utils/build-apple-framework.sh + +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" + + create_universal_framework "iphoneos" "iphonesimulator" "catalyst" +else + echo "Skipping; Clean \"destroot\" to rebuild". +fi diff --git a/sdks/hermes-engine/utils/build-mac-framework.sh b/sdks/hermes-engine/utils/build-mac-framework.sh new file mode 100755 index 00000000000000..79040c2d0babdb --- /dev/null +++ b/sdks/hermes-engine/utils/build-mac-framework.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +. ./utils/build-apple-framework.sh +if [ ! -d destroot/Library/Frameworks/macosx/hermes.framework ]; then + mac_deployment_target=$(get_mac_deployment_target) + + build_apple_framework "macosx" "x86_64;arm64" "$mac_deployment_target" +else + echo "Skipping; Clean \"destroot\" to rebuild". +fi