diff --git a/.github/actions/build-android/action.yml b/.github/actions/build-android/action.yml index e6a8caebf5f8..0aba8b032dfd 100644 --- a/.github/actions/build-android/action.yml +++ b/.github/actions/build-android/action.yml @@ -45,16 +45,19 @@ runs: if [[ "${{ inputs.release-type }}" == "dry-run" ]]; then # dry-run: we only build ARM64 to save time/resources. For release/nightlies the default is to build all archs. export ORG_GRADLE_PROJECT_reactNativeArchitectures="arm64-v8a,x86" # x86 is required for E2E testing + export HERMES_PREBUILT_FLAG="ORG_GRADLE_PROJECT_react.internal.useHermesNightly=true" TASKS="publishAllToMavenTempLocal build" elif [[ "${{ inputs.release-type }}" == "nightly" ]]; then # nightly: we set isSnapshot to true so artifacts are sent to the right repository on Maven Central. export ORG_GRADLE_PROJECT_isSnapshot="true" + export HERMES_PREBUILT_FLAG="ORG_GRADLE_PROJECT_react.internal.useHermesNightly=true" TASKS="publishAllToMavenTempLocal publishAndroidToSonatype build" else # release: we want to build all archs (default) + export HERMES_PREBUILT_FLAG="ORG_GRADLE_PROJECT_react.internal.useHermesStable=true" TASKS="publishAllToMavenTempLocal publishAndroidToSonatype build" fi - ./gradlew $TASKS -PenableWarningsAsErrors=true + env "$HERMES_PREBUILT_FLAG" ./gradlew $TASKS -PenableWarningsAsErrors=true - name: Save Android ccache if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, '-stable') }} uses: actions/cache/save@v5 diff --git a/build.gradle.kts b/build.gradle.kts index 40846ef4e82d..657f109c454c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -109,16 +109,43 @@ tasks.register("publishAllToMavenTempLocal") { tasks.register("publishAndroidToSonatype") { description = "Publish the Android artifacts to Sonatype (Maven Central or Snapshot repository)" dependsOn(":packages:react-native:ReactAndroid:publishToSonatype") - dependsOn(":packages:react-native:ReactAndroid:hermes-engine:publishToSonatype") } -if (project.findProperty("react.internal.useHermesNightly")?.toString()?.toBoolean() == true) { +var hermesSubstitution: Pair? = null + +if (project.findProperty("react.internal.useHermesStable")?.toString()?.toBoolean() == true) { + val hermesVersions = java.util.Properties() + val hermesVersionPropertiesFile = + File("./packages/react-native/sdks/hermes-engine/version.properties") + hermesVersionPropertiesFile.inputStream().use { hermesVersions.load(it) } + val selectedHermesVersion = hermesVersions["HERMES_VERSION_NAME"] as String + + hermesSubstitution = selectedHermesVersion to "Users opted to use stable hermes release" +} else if ( + project.findProperty("react.internal.useHermesNightly")?.toString()?.toBoolean() == true +) { + val reactNativePackageJson = File("./packages/react-native/package.json") + val reactNativePackageJsonContent = reactNativePackageJson.readText() + val packageJson = groovy.json.JsonSlurper().parseText(reactNativePackageJsonContent) as Map<*, *> + + val hermesCompilerVersion = + (packageJson["dependencies"] as Map<*, *>)["hermes-compiler"] as String + + if (hermesCompilerVersion == "0.0.0") { + throw RuntimeException( + "Trying to use Hermes Nightly but hermes-compiler version is not specified" + ) + } + + hermesSubstitution = "$hermesCompilerVersion-SNAPSHOT" to "Users opted to use hermes nightly" +} else { logger.warn( """ ******************************************************************************** - INFO: You're using Hermes from nightly as you set + INFO: You're building Hermes from source as you set - react.internal.useHermesNightly=true + react.internal.useHermesStable=false + react.internal.useHermesNightly=false in the ./gradle.properties file. @@ -127,12 +154,20 @@ if (project.findProperty("react.internal.useHermesNightly")?.toString()?.toBoole """ .trimIndent() ) +} + +if (hermesSubstitution != null) { + val (hermesVersion, reason) = hermesSubstitution!! + project(":packages:react-native:ReactAndroid:hermes-engine") { + tasks.configureEach { enabled = false } + } + allprojects { configurations.all { resolutionStrategy.dependencySubstitution { substitute(project(":packages:react-native:ReactAndroid:hermes-engine")) - .using(module("com.facebook.hermes:hermes-android:0.+")) - .because("Users opted to use hermes from nightly") + .using(module("com.facebook.hermes:hermes-android:$hermesVersion")) + .because(reason) } } } diff --git a/gradle.properties b/gradle.properties index 0a91ef0f755c..f494dd4fe8c1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,9 +16,14 @@ android.newDsl=false # ./gradlew -PreactNativeArchitectures=x86_64 reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 +# Controls whether to use Hermes from stable builds. This will force hermes version +# set in the sdks/hermes-engine/version.properties file to be used. This has a higher +# priority than react.internal.useHermesNightly. +react.internal.useHermesStable=false + # Controls whether to use Hermes from nightly builds. This will speed up builds # but should NOT be turned on for CI or release builds. -react.internal.useHermesNightly=false +react.internal.useHermesNightly=true # Controls whether to use Hermes 1.0. Clean and rebuild when changing. hermesV1Enabled=false diff --git a/package.json b/package.json index 0c9b48cb4e70..9bb24acddeca 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "lint-kotlin": "./gradlew ktfmtFormat", "lint-markdown": "markdownlint-cli2 2>&1", "lint": "eslint --max-warnings 0 .", + "preinstall": "node ./scripts/try-set-nightly-hermes-compiler.js", "prettier": "prettier --write \"./**/*.{js,md,yml,ts,tsx}\"", "print-packages": "node ./scripts/monorepo/print", "shellcheck": "./.github/workflow-scripts/analyze_scripts.sh", diff --git a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/PropertyUtils.kt b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/PropertyUtils.kt index fa75308e3616..a52e4177fd0c 100644 --- a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/PropertyUtils.kt +++ b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/PropertyUtils.kt @@ -65,6 +65,13 @@ object PropertyUtils { */ const val INTERNAL_REACT_WINDOWS_BASH = "react.internal.windowsBashPath" + /** + * Controls whether to use Hermes from stable builds. This will force hermes version set in the + * sdks/hermes-engine/version.properties file to be used. This has a higher priority than + * react.internal.useHermesNightly. + */ + const val INTERNAL_USE_HERMES_STABLE = "react.internal.useHermesStable" + /** * Internal property to force the build to use Hermes from the latest nightly. This speeds up the * build at the cost of not testing the latest integration against Hermes. diff --git a/packages/react-native/ReactAndroid/hermes-engine/build.gradle.kts b/packages/react-native/ReactAndroid/hermes-engine/build.gradle.kts index 5a5e1385c9ef..f33331ddaa5d 100644 --- a/packages/react-native/ReactAndroid/hermes-engine/build.gradle.kts +++ b/packages/react-native/ReactAndroid/hermes-engine/build.gradle.kts @@ -11,7 +11,6 @@ import de.undercouch.gradle.tasks.download.Download import org.apache.tools.ant.taskdefs.condition.Os plugins { - id("maven-publish") id("signing") alias(libs.plugins.android.library) alias(libs.plugins.download) @@ -348,10 +347,7 @@ android { java.srcDirs("$hermesDir/lib/Platform/Intl/java", "$hermesDir/lib/Platform/Unicode/java") } - buildFeatures { - prefab = true - prefabPublishing = true - } + buildFeatures { prefab = true } dependencies { implementation(libs.fbjni) @@ -365,13 +361,6 @@ android { jniLibs.excludes.add("**/libfbjni.so") } - publishing { - multipleVariants { - withSourcesJar() - allVariants() - } - } - prefab { create("hermesvm") { headers = prefabHeadersDir.absolutePath } } } diff --git a/packages/react-native/sdks/hermes-engine/hermes-engine.podspec b/packages/react-native/sdks/hermes-engine/hermes-engine.podspec index fb9914285080..05ea840726fb 100644 --- a/packages/react-native/sdks/hermes-engine/hermes-engine.podspec +++ b/packages/react-native/sdks/hermes-engine/hermes-engine.podspec @@ -28,6 +28,14 @@ else version = versionProperties['HERMES_VERSION_NAME'] end +# Local monorepo build +if package['version'] == "1000.0.0" then + hermesCompilerVersion = package['dependencies']['hermes-compiler'] + if hermesCompilerVersion != "0.0.0" then + version = hermesCompilerVersion + end +end + source_type = hermes_source_type(version, react_native_path) source = podspec_source(source_type, version, react_native_path) diff --git a/packages/rn-tester/android/app/build.gradle.kts b/packages/rn-tester/android/app/build.gradle.kts index 8f412a5c0dfb..fc1770cbd068 100644 --- a/packages/rn-tester/android/app/build.gradle.kts +++ b/packages/rn-tester/android/app/build.gradle.kts @@ -61,7 +61,14 @@ react { /* Hermes Commands */ // The hermes compiler command to run. By default it is 'hermesc' - hermesCommand = "$reactNativeDirPath/ReactAndroid/hermes-engine/build/hermes/bin/hermesc" + hermesCommand = + if ( + project.findProperty("react.internal.useHermesStable")?.toString()?.toBoolean() == true || + project.findProperty("react.internal.useHermesNightly")?.toString()?.toBoolean() == + true + ) + "$rootDir/node_modules/hermes-compiler/hermesc/%OS-BIN%/hermesc" + else "$reactNativeDirPath/ReactAndroid/hermes-engine/build/hermes/bin/hermesc" autolinkLibrariesWithApp() } @@ -179,8 +186,10 @@ tasks.withType().configureEach { afterEvaluate { if ( - project.findProperty("react.internal.useHermesNightly") == null || - project.findProperty("react.internal.useHermesNightly").toString() == "false" + (project.findProperty("react.internal.useHermesNightly") == null || + project.findProperty("react.internal.useHermesNightly").toString() == "false") && + (project.findProperty("react.internal.useHermesStable") == null || + project.findProperty("react.internal.useHermesStable").toString() == "false") ) { // As we're consuming Hermes from source, we want to make sure // `hermesc` is built before we actually invoke the `emit*HermesResource` task diff --git a/private/react-native-fantom/build.gradle.kts b/private/react-native-fantom/build.gradle.kts index 3bf026783050..7087d8b23182 100644 --- a/private/react-native-fantom/build.gradle.kts +++ b/private/react-native-fantom/build.gradle.kts @@ -139,9 +139,17 @@ val prepareRNCodegen by into(codegenOutDir) } +val enableHermesBuild by + tasks.registering { + project(":packages:react-native:ReactAndroid:hermes-engine") { + tasks.configureEach { enabled = true } + } + } + val prepareHermesDependencies by tasks.registering { dependsOn( + enableHermesBuild, ":packages:react-native:ReactAndroid:hermes-engine:buildHermesLib", ":packages:react-native:ReactAndroid:hermes-engine:prepareHeadersForPrefab", ) diff --git a/scripts/try-set-nightly-hermes-compiler.js b/scripts/try-set-nightly-hermes-compiler.js new file mode 100644 index 000000000000..ef931e4a6b9b --- /dev/null +++ b/scripts/try-set-nightly-hermes-compiler.js @@ -0,0 +1,26 @@ +/** + * 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. + */ + +// @flow +const { execSync } = require('child_process'); +const fs = require('fs'); +const path = require('path'); + +function main() { + const packageJsonPath = path.join(__dirname, '../packages/react-native/package.json'); + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); + const hermesCompilerVersion = packageJson.dependencies['hermes-compiler']; + + if (hermesCompilerVersion === '0.0.0') { + console.log(`Hermes compiler version not set. Updating to the latest nightly release.`); + execSync('yarn workspace react-native add hermes-compiler@nightly --exact', { stdio: 'inherit' }); + } else { + console.log(`Hermes compiler version set to ${hermesCompilerVersion}. Not setting nightly hermes.`); + } +} + +main();