From 23d3a969a412eb008e9e84b7d830b583fa4725ff Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Fri, 14 Feb 2025 09:02:03 -0800 Subject: [PATCH 1/3] [skip ci] Gradle Configuration Cache - Round 1 (#49421) Summary: This is a first part of a series of diff needed to enable G. Configuration Cache: https://docs.gradle.org/current/userguide/configuration_cache.html as it will make our CI faster (and will be the default in the future Gradle version). Here I'm making all those tasks `prepare*` CC friendly. Those tasks were not CC friendly as they were referencing an external variable inside their body. We don't need to know the library version, we can just substring after the first folder and the tasks will behave as before. Changelog: [Internal] [Changed] - Differential Revision: D69655168 --- packages/react-native/ReactAndroid/build.gradle.kts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/react-native/ReactAndroid/build.gradle.kts b/packages/react-native/ReactAndroid/build.gradle.kts index 9fa0ea551a45..80c7fede9b56 100644 --- a/packages/react-native/ReactAndroid/build.gradle.kts +++ b/packages/react-native/ReactAndroid/build.gradle.kts @@ -293,7 +293,7 @@ val prepareDoubleConversion by from(dependenciesPath ?: tarTree(downloadDoubleConversionDest)) from("src/main/jni/third-party/double-conversion/") include("double-conversion-${DOUBLE_CONVERSION_VERSION}/src/**/*", "CMakeLists.txt") - filesMatching("*/src/**/*") { this.path = "double-conversion/${this.name}" } + filesMatching("*/src/**/*") { path = "double-conversion/${name}" } includeEmptyDirs = false into("$thirdPartyNdkDir/double-conversion") } @@ -315,7 +315,7 @@ val prepareFolly by from(dependenciesPath ?: tarTree(downloadFollyDest)) from("src/main/jni/third-party/folly/") include("folly-${FOLLY_VERSION}/folly/**/*", "CMakeLists.txt") - eachFile { this.path = this.path.removePrefix("folly-${FOLLY_VERSION}/") } + eachFile { path = path.substringAfter("/") } includeEmptyDirs = false into("$thirdPartyNdkDir/folly") } @@ -338,7 +338,7 @@ val prepareFastFloat by from(dependenciesPath ?: tarTree(downloadFastFloatDest)) from("src/main/jni/third-party/fast_float/") include("fast_float-${FAST_FLOAT_VERSION}/include/**/*", "CMakeLists.txt") - eachFile { this.path = this.path.removePrefix("fast_float-${FAST_FLOAT_VERSION}/") } + eachFile { path = path.substringAfter("/") } includeEmptyDirs = false into("$thirdPartyNdkDir/fast_float") } @@ -361,7 +361,7 @@ val prepareFmt by from(dependenciesPath ?: tarTree(downloadFmtDest)) from("src/main/jni/third-party/fmt/") include("fmt-${FMT_VERSION}/src/**/*", "fmt-${FMT_VERSION}/include/**/*", "CMakeLists.txt") - eachFile { this.path = this.path.removePrefix("fmt-${FMT_VERSION}/") } + eachFile { path = path.substringAfter("/") } includeEmptyDirs = false into("$thirdPartyNdkDir/fmt") } @@ -394,7 +394,7 @@ val prepareGtest by tasks.registering(Copy::class) { dependsOn(if (dependenciesPath != null) emptyList() else listOf(downloadGtest)) from(dependenciesPath ?: tarTree(downloadGtestDest)) - eachFile { this.path = (this.path.removePrefix("googletest-release-${GTEST_VERSION}/")) } + eachFile { path = path.substringAfter("/") } into(File(thirdPartyNdkDir, "googletest")) } From 2a7ce7ba698f26c2a6dafd96802d7f1200df4b31 Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Fri, 14 Feb 2025 09:02:03 -0800 Subject: [PATCH 2/3] [skip ci] Gradle Configuration Cache - Round 2 Summary: This is the second part of a series of diff needed to enable G. Configuration Cache: https://docs.gradle.org/current/userguide/configuration_cache.html as it will make our CI faster (and will be the default in the future Gradle version). Here I'm making the exec tasks CC friendly. The problem is that previously we were using explicit streams which are not CC friendly for stderr/stdout. The solution is to create a custom task and handle files as input properties. Changelog: [Internal] [Changed] - Differential Revision: D69662246 --- .../react/tasks/internal/CustomExecTask.kt | 44 +++++++++++++++++++ .../tasks/internal/CustomExecTaskTest.kt | 33 ++++++++++++++ .../hermes-engine/build.gradle.kts | 12 ++--- 3 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/internal/CustomExecTask.kt create mode 100644 packages/gradle-plugin/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/internal/CustomExecTaskTest.kt diff --git a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/internal/CustomExecTask.kt b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/internal/CustomExecTask.kt new file mode 100644 index 000000000000..ae6d5c108a3a --- /dev/null +++ b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/internal/CustomExecTask.kt @@ -0,0 +1,44 @@ +/* + * 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. + */ + +package com.facebook.react.tasks.internal + +import java.io.File +import java.io.FileOutputStream +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Exec +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Optional +import org.gradle.api.tasks.OutputFile + +/** + * A Task that will just expose an Exec-like task and that offers properties to configure the + * standard output and error. + */ +abstract class CustomExecTask : Exec() { + + @get:OutputFile @get:Optional abstract val standardOutputFile: RegularFileProperty + + @get:OutputFile @get:Optional abstract val errorOutputFile: RegularFileProperty + + @get:Input @get:Optional abstract val onlyIfProvidedPathDoesNotExists: Property + + override fun exec() { + if (onlyIfProvidedPathDoesNotExists.isPresent && + File(onlyIfProvidedPathDoesNotExists.get()).exists()) { + return + } + if (standardOutputFile.isPresent) { + standardOutput = FileOutputStream(standardOutputFile.get().asFile) + } + if (errorOutputFile.isPresent) { + errorOutput = FileOutputStream(errorOutputFile.get().asFile) + } + super.exec() + } +} diff --git a/packages/gradle-plugin/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/internal/CustomExecTaskTest.kt b/packages/gradle-plugin/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/internal/CustomExecTaskTest.kt new file mode 100644 index 000000000000..c61d5b307c42 --- /dev/null +++ b/packages/gradle-plugin/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/internal/CustomExecTaskTest.kt @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package com.facebook.react.tasks.internal + +import com.facebook.react.tests.createTestTask +import org.assertj.core.api.Assertions.assertThat +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TemporaryFolder + +class CustomExecTaskTest { + + @get:Rule val tempFolder = TemporaryFolder() + + @Test + fun customExec_inputProperties_areSetCorrectly() { + val outFile = tempFolder.newFile("stdout") + val errFile = tempFolder.newFile("stderr") + val task = + createTestTask { task -> + task.errorOutputFile.set(errFile) + task.standardOutputFile.set(outFile) + } + + assertThat(task.errorOutputFile.get().asFile).isEqualTo(errFile) + assertThat(task.standardOutputFile.get().asFile).isEqualTo(outFile) + } +} diff --git a/packages/react-native/ReactAndroid/hermes-engine/build.gradle.kts b/packages/react-native/ReactAndroid/hermes-engine/build.gradle.kts index bc5a4bdd22dc..43b4268edc92 100644 --- a/packages/react-native/ReactAndroid/hermes-engine/build.gradle.kts +++ b/packages/react-native/ReactAndroid/hermes-engine/build.gradle.kts @@ -5,8 +5,8 @@ * LICENSE file in the root directory of this source tree. */ +import com.facebook.react.tasks.internal.* import de.undercouch.gradle.tasks.download.Download -import java.io.FileOutputStream import org.apache.tools.ant.taskdefs.condition.Os plugins { @@ -131,7 +131,7 @@ val installCMake by } val configureBuildForHermes by - tasks.registering(Exec::class) { + tasks.registering(CustomExecTask::class) { dependsOn(installCMake) workingDir(hermesDir) inputs.dir(hermesDir) @@ -149,11 +149,11 @@ val configureBuildForHermes by hermesBuildDir.toString(), "-DJSI_DIR=" + jsiDir.absolutePath, )) - standardOutput = FileOutputStream("$buildDir/configure-hermesc.log") + standardOutputFile.set(project.file("$buildDir/configure-hermesc.log")) } val buildHermesC by - tasks.registering(Exec::class) { + tasks.registering(CustomExecTask::class) { dependsOn(configureBuildForHermes) workingDir(hermesDir) inputs.files(hermesBuildOutputFileTree) @@ -167,8 +167,8 @@ val buildHermesC by "-j", ndkBuildJobs, ) - standardOutput = FileOutputStream("$buildDir/build-hermesc.log") - errorOutput = FileOutputStream("$buildDir/build-hermesc.error.log") + standardOutputFile.set(project.file("$buildDir/build-hermesc.log")) + errorOutputFile.set(project.file("$buildDir/build-hermesc.error.log")) } val prepareHeadersForPrefab by From d41f5df826ad8baa7f69c9637e996d0712a63096 Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Fri, 14 Feb 2025 09:02:03 -0800 Subject: [PATCH 3/3] Gradle Configuration Cache - Round 3 Summary: This is the next part of a series of diff needed to enable G. Configuration Cache: https://docs.gradle.org/current/userguide/configuration_cache.html as it will make our CI faster (and will be the default in the future Gradle version). Here I'm removing the `onlyIf` lambdas to make some tasks CC friendly. The problem is that some `onlyIf` lambdas can't easily be serialized. Here I'm cleaning up the problematic one to move the condition checks at execution time Changelog: [Internal] [Changed] - Differential Revision: D69664732 --- .../facebook/react/tasks/internal/BuildCodegenCLITask.kt | 6 ++++++ packages/react-native/ReactAndroid/build.gradle.kts | 5 +---- .../ReactAndroid/hermes-engine/build.gradle.kts | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/internal/BuildCodegenCLITask.kt b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/internal/BuildCodegenCLITask.kt index ad2d51ed03e4..74eba6527070 100644 --- a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/internal/BuildCodegenCLITask.kt +++ b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/internal/BuildCodegenCLITask.kt @@ -28,6 +28,8 @@ abstract class BuildCodegenCLITask : Exec() { @get:Internal abstract val bashWindowsHome: Property + @get:Internal abstract val rootProjectName: Property + @get:InputFiles abstract val inputFiles: Property @get:OutputFiles abstract val outputFiles: Property @@ -35,6 +37,10 @@ abstract class BuildCodegenCLITask : Exec() { @get:OutputFile abstract val logFile: RegularFileProperty override fun exec() { + // For build from source scenario, we don't need to build the codegen at all. + if (rootProjectName.get() == "react-native-build-from-source") { + return + } val logFileConcrete = logFile.get().asFile.apply { parentFile.mkdirs() diff --git a/packages/react-native/ReactAndroid/build.gradle.kts b/packages/react-native/ReactAndroid/build.gradle.kts index 80c7fede9b56..2f212b635800 100644 --- a/packages/react-native/ReactAndroid/build.gradle.kts +++ b/packages/react-native/ReactAndroid/build.gradle.kts @@ -426,10 +426,7 @@ val buildCodegenCLI by include("lib/**/*.js") include("lib/**/*.js.flow") }) - onlyIf { - // For build from source scenario, we don't need to build the codegen at all. - rootProject.name != "react-native-build-from-source" - } + rootProjectName.set(rootProject.name) } /** diff --git a/packages/react-native/ReactAndroid/hermes-engine/build.gradle.kts b/packages/react-native/ReactAndroid/hermes-engine/build.gradle.kts index 43b4268edc92..9fa746dff892 100644 --- a/packages/react-native/ReactAndroid/hermes-engine/build.gradle.kts +++ b/packages/react-native/ReactAndroid/hermes-engine/build.gradle.kts @@ -124,8 +124,8 @@ val unzipHermes by // the two tasks mentioned before, so we install CMake manually to break the circular dependency. val installCMake by - tasks.registering(Exec::class) { - onlyIf { !File(cmakePath).exists() } + tasks.registering(CustomExecTask::class) { + onlyIfProvidedPathDoesNotExists.set(cmakePath) commandLine( windowsAwareCommandLine(getSDKManagerPath(), "--install", "cmake;${cmakeVersion}")) }