Refactor Extract Headers and JNI from AARs to an internal task (#32426)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/32426

This diff refactors the extractHeader and extractJni tasks to a single Gradle task in the `.internal` package.
The reason for this change is that those two tasks were always running, therefore invalidating the
whole native build cache.

Changelog:
[Internal] [Changed] - Refactor Extract Headers and JNI from AARs to an internal task

Reviewed By: mdvacca, ShikaSD

Differential Revision: D31682942

fbshipit-source-id: 191cc77902e82c0425949cee743d240ded790137
This commit is contained in:
Nicola Corti
2021-10-18 04:34:43 -07:00
committed by Facebook GitHub Bot
parent 75b2e5cc97
commit bc93fefe13
3 changed files with 134 additions and 27 deletions
+13 -27
View File
@@ -284,7 +284,7 @@ def getNdkBuildFullPath() {
}
def buildReactNdkLib = tasks.register("buildReactNdkLib", Exec) {
dependsOn(prepareJSC, prepareHermes, prepareBoost, prepareDoubleConversion, prepareFmt, prepareFolly, prepareGlog, prepareLibevent, extractAARHeaders, extractJNIFiles)
dependsOn(prepareJSC, prepareHermes, prepareBoost, prepareDoubleConversion, prepareFmt, prepareFolly, prepareGlog, prepareLibevent, extractNativeDependencies)
dependsOn("generateCodegenArtifactsFromSchema");
inputs.dir("$projectDir/../ReactCommon")
@@ -343,32 +343,18 @@ def packageReactNdkLibsForBuck = tasks.register("packageReactNdkLibsForBuck", Co
into("src/main/jni/prebuilt/lib")
}
task extractAARHeaders {
doLast {
configurations.extractHeaders.files.each {
def file = it.absoluteFile
def packageName = file.name.tokenize('-')[0]
copy {
from zipTree(file)
into "$projectDir/src/main/jni/first-party/$packageName/headers"
include "**/*.h"
}
}
}
}
task extractJNIFiles {
doLast {
configurations.extractJNI.files.each {
def file = it.absoluteFile
def packageName = file.name.tokenize('-')[0]
copy {
from zipTree(file)
into "$projectDir/src/main/jni/first-party/$packageName/"
include "jni/**/*"
}
}
}
final def extractNativeDependencies = tasks.register('extractNativeDependencies', ExtractJniAndHeadersTask) {
it.extractHeadersConfiguration.setFrom(configurations.extractHeaders)
it.extractJniConfiguration.setFrom(configurations.extractJNI)
it.baseOutputDir = project.file("src/main/jni/first-party/")
// Sadly this task as an output folder path that is directly dependent on
// the task input (i.e. src/main/jni/first-party/<package-name>/...
// This means that this task is using the parent folder (first-party/) as
// @OutputFolder. The `prepareHermes` task will also output inside that
// folder and if the two tasks happen to be inside the same run, we want
// `extractNativeDependencies` to run after `prepareHermes` to do not
// invalidate the input/output calculation for this task.
it.mustRunAfter(prepareHermes)
}
task installArchives {
@@ -0,0 +1,49 @@
/*
* Copyright (c) Facebook, Inc. and its 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 org.gradle.api.DefaultTask
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.tasks.*
/**
* A task that takes care of extracting JNIs and Headers from a custom Gradle configuration into an
* output folder. Users are most likely not going to use this task but it will be used when building
* the React Native project.
*/
abstract class ExtractJniAndHeadersTask : DefaultTask() {
@get:InputFiles abstract val extractHeadersConfiguration: ConfigurableFileCollection
@get:InputFiles abstract val extractJniConfiguration: ConfigurableFileCollection
@get:OutputDirectory abstract val baseOutputDir: DirectoryProperty
@TaskAction
fun taskAction() {
extractJniConfiguration.files.forEach {
val file = it.absoluteFile
val packageName = file.name.split("-", ".").first()
project.copy { copySpec ->
copySpec.from(project.zipTree(file))
copySpec.into(baseOutputDir.dir(packageName))
copySpec.include("jni/**/*")
}
}
extractHeadersConfiguration.files.forEach {
val file = it.absoluteFile
val packageName = file.name.split("-", ".").first()
project.copy { copySpec ->
copySpec.from(project.zipTree(file))
copySpec.into(baseOutputDir.get().dir("$packageName/headers"))
copySpec.include("**/*.h")
}
}
}
}
@@ -0,0 +1,72 @@
/*
* Copyright (c) Facebook, Inc. and its 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.createProject
import com.facebook.react.tests.createTestTask
import com.facebook.react.tests.zipFiles
import java.io.*
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
import org.junit.Assert.assertTrue
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
class ExtractJniAndHeadersTaskTest {
@get:Rule val tempFolder = TemporaryFolder()
@Test
fun extractJniAndHeadersTask_extractsHeadersCorrectly() {
val project = createProject()
val aarFile = File(project.projectDir, "libheader.aar")
val headerFile = tempFolder.newFile("justaheader.h")
val output = tempFolder.newFolder("output")
zipFiles(aarFile, listOf(headerFile))
val task =
createTestTask<ExtractJniAndHeadersTask>(project = project) {
it.extractHeadersConfiguration.setFrom(aarFile)
it.baseOutputDir.set(output)
}
task.taskAction()
assertTrue(File(output, "libheader/headers/justaheader.h").exists())
}
@Test
fun extractJniAndHeadersTask_extractsJniCorrectly() {
val project = createProject()
val aarFile = File(project.projectDir, "something.aar")
File(tempFolder.root, "jni/libsomething.so").apply {
parentFile.mkdirs()
createNewFile()
}
val output = tempFolder.newFolder("output")
ZipOutputStream(BufferedOutputStream(FileOutputStream(aarFile.absolutePath))).use { out ->
FileInputStream(aarFile).use { fi ->
BufferedInputStream(fi).use { origin ->
out.putNextEntry(ZipEntry("jni/"))
out.putNextEntry(ZipEntry("jni/libsomething.so"))
origin.copyTo(out, 1024)
}
}
}
val task =
createTestTask<ExtractJniAndHeadersTask>(project = project) {
it.extractJniConfiguration.setFrom(aarFile)
it.baseOutputDir.set(output)
}
task.taskAction()
assertTrue(File(output, "something/jni/libsomething.so").exists())
}
}