Skip to content

Commit 493306f

Browse files
cortinicofacebook-github-bot
authored andcommitted
RNGP - Move the generateAutolinkingNewArchitectureFiles task to core autolinking
Summary: This diff is part of RFC0759 react-native-community/discussions-and-proposals#759 Here I'm moving the New Architecture C++ Autolinking from the CLI to core. It follows the same logic as this: https://github.com/react-native-community/cli/blob/73f880c3d87cdde81204364289f2f488a473c52b/packages/cli-platform-android/native_modules.gradle#L544-L550 Changelog: [Internal] [Changed] - RNGP - Move the generateAutolinkingNewArchitectureFiles task to core autolinking Reviewed By: cipolleschi, blakef Differential Revision: D55475594
1 parent 42f9129 commit 493306f

File tree

4 files changed

+479
-1
lines changed

4 files changed

+479
-1
lines changed

packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactPlugin.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ package com.facebook.react
1010
import com.android.build.api.variant.AndroidComponentsExtension
1111
import com.android.build.gradle.internal.tasks.factory.dependsOn
1212
import com.facebook.react.internal.PrivateReactExtension
13+
import com.facebook.react.tasks.GenerateAutolinkingNewArchitecturesFileTask
1314
import com.facebook.react.tasks.GenerateCodegenArtifactsTask
1415
import com.facebook.react.tasks.GenerateCodegenSchemaTask
1516
import com.facebook.react.tasks.GeneratePackageListTask
@@ -25,6 +26,7 @@ import com.facebook.react.utils.DependencyUtils.readVersionAndGroupStrings
2526
import com.facebook.react.utils.JdkConfiguratorUtils.configureJavaToolChains
2627
import com.facebook.react.utils.JsonUtils
2728
import com.facebook.react.utils.NdkConfiguratorUtils.configureReactNativeNdk
29+
import com.facebook.react.utils.ProjectUtils.isNewArchEnabled
2830
import com.facebook.react.utils.ProjectUtils.needsCodegenFromPackageJson
2931
import com.facebook.react.utils.ProjectUtils.shouldWarnIfNewArchFlagIsSetInPrealpha
3032
import com.facebook.react.utils.findPackageJsonFile
@@ -222,6 +224,8 @@ class ReactPlugin : Plugin<Project> {
222224
project.layout.buildDirectory.dir("generated/autolinking")
223225
val generatedAutolinkingJavaDir: Provider<Directory> =
224226
project.layout.buildDirectory.dir("generated/autolinking/src/main/java")
227+
val generatedAutolinkingJniDir: Provider<Directory> =
228+
project.layout.buildDirectory.dir("generated/autolinking/src/main/jni")
225229
val configOutputFile = generatedAutolinkingDir.get().file("config-output.json")
226230

227231
val runAutolinkingConfigTask =
@@ -244,6 +248,21 @@ class ReactPlugin : Plugin<Project> {
244248
task.generatedOutputDirectory.set(generatedAutolinkingJavaDir)
245249
}
246250

251+
if (project.isNewArchEnabled(extension)) {
252+
// For New Arch, we also need to generate code for C++ Autolinking
253+
val generateAutolinkingNewArchitectureFilesTask =
254+
project.tasks.register(
255+
"generateAutolinkingNewArchitectureFiles",
256+
GenerateAutolinkingNewArchitecturesFileTask::class.java) { task ->
257+
task.dependsOn(runAutolinkingConfigTask)
258+
task.autolinkInputFile.set(configOutputFile)
259+
task.generatedOutputDirectory.set(generatedAutolinkingJniDir)
260+
}
261+
project.tasks
262+
.named("preBuild", Task::class.java)
263+
.dependsOn(generateAutolinkingNewArchitectureFilesTask)
264+
}
265+
247266
// We let generateAutolinkingPackageList depend on the preBuild task so it's executed before
248267
// everything else.
249268
project.tasks.named("preBuild", Task::class.java).dependsOn(generatePackageListTask)

packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/model/ModelAutolinkingDependenciesPlatformAndroidJson.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ data class ModelAutolinkingDependenciesPlatformAndroidJson(
1414
val buildTypes: List<String>,
1515
val libraryName: String,
1616
val componentDescriptors: List<String>,
17-
val cmakeListsPath: String,
17+
val cmakeListsPath: String? = null,
1818
val cxxModuleCMakeListsModuleName: String? = null,
1919
val cxxModuleCMakeListsPath: String? = null,
2020
val cxxModuleHeaderName: String? = null,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
package com.facebook.react.tasks
9+
10+
import com.facebook.react.model.ModelAutolinkingDependenciesJson
11+
import com.facebook.react.utils.JsonUtils
12+
import java.io.File
13+
import org.gradle.api.DefaultTask
14+
import org.gradle.api.file.DirectoryProperty
15+
import org.gradle.api.file.RegularFileProperty
16+
import org.gradle.api.tasks.InputFile
17+
import org.gradle.api.tasks.OutputDirectory
18+
import org.gradle.api.tasks.TaskAction
19+
20+
abstract class GenerateAutolinkingNewArchitecturesFileTask : DefaultTask() {
21+
22+
init {
23+
group = "react"
24+
}
25+
26+
@get:InputFile abstract val autolinkInputFile: RegularFileProperty
27+
28+
@get:OutputDirectory abstract val generatedOutputDirectory: DirectoryProperty
29+
30+
@TaskAction
31+
fun taskAction() {
32+
val model = JsonUtils.fromAutolinkingConfigJson(autolinkInputFile.get().asFile)
33+
34+
val packages = model?.dependencies?.values ?: emptyList()
35+
36+
val cmakeFileContent = generateCmakeFileContent(packages)
37+
val cppFileContent = generateCppFileContent(packages)
38+
39+
val outputDir = generatedOutputDirectory.get().asFile
40+
outputDir.mkdirs()
41+
File(outputDir, CMAKE_FILENAME).apply { writeText(cmakeFileContent) }
42+
File(outputDir, CPP_FILENAME).apply { writeText(cppFileContent) }
43+
File(outputDir, H_FILENAME).apply { writeText(hTemplate) }
44+
}
45+
46+
internal fun generateCmakeFileContent(
47+
packages: Collection<ModelAutolinkingDependenciesJson>
48+
): String {
49+
val libraryIncludes =
50+
packages.joinToString("\n") { dep ->
51+
var addDirectoryString = ""
52+
if (dep.platforms?.android?.libraryName != null &&
53+
dep.platforms.android.cmakeListsPath != null) {
54+
// If user provided a custom cmakeListsPath, let's honor it.
55+
val nativeFolderPath =
56+
dep.platforms.android.cmakeListsPath.replace("CMakeLists.txt", "")
57+
addDirectoryString +=
58+
"add_subdirectory($nativeFolderPath ${dep.platforms.android.libraryName}_autolinked_build)"
59+
}
60+
if (dep.platforms?.android?.cxxModuleCMakeListsPath != null) {
61+
// If user provided a custom cxxModuleCMakeListsPath, let's honor it.
62+
val nativeFolderPath =
63+
dep.platforms.android.cxxModuleCMakeListsPath.replace("CMakeLists.txt", "")
64+
addDirectoryString +=
65+
"\nadd_subdirectory($nativeFolderPath ${dep.platforms.android.libraryName}_cxxmodule_autolinked_build)"
66+
}
67+
addDirectoryString
68+
}
69+
70+
val libraryModules =
71+
packages.joinToString("\n ") { dep ->
72+
var autolinkedLibraries = ""
73+
if (dep.platforms?.android?.libraryName != null) {
74+
autolinkedLibraries += "$CODEGEN_LIB_PREFIX${dep.platforms.android.libraryName}"
75+
}
76+
if (dep.platforms?.android?.cxxModuleCMakeListsModuleName != null) {
77+
autolinkedLibraries += "\n${dep.platforms.android.cxxModuleCMakeListsModuleName}"
78+
}
79+
autolinkedLibraries
80+
}
81+
82+
return CMAKE_TEMPLATE.replace("{{ libraryIncludes }}", libraryIncludes)
83+
.replace("{{ libraryModules }}", libraryModules)
84+
}
85+
86+
internal fun generateCppFileContent(
87+
packages: Collection<ModelAutolinkingDependenciesJson>
88+
): String {
89+
val packagesWithLibraryNames = packages.filter { it.platforms?.android?.libraryName != null }
90+
91+
val cppIncludes =
92+
packagesWithLibraryNames.joinToString("\n") { dep ->
93+
var include = "#include <${dep.platforms?.android?.libraryName}.h>"
94+
if (dep.platforms?.android?.componentDescriptors != null &&
95+
dep.platforms.android.componentDescriptors.isNotEmpty()) {
96+
include +=
97+
"\n#include <${COMPONENT_INCLUDE_PATH}/${dep.platforms.android.libraryName}/${COMPONENT_DESCRIPTOR_FILENAME}>"
98+
}
99+
if (dep.platforms?.android?.cxxModuleHeaderName != null) {
100+
include += "\n#include <${dep.platforms.android.cxxModuleHeaderName}.h>"
101+
}
102+
include
103+
}
104+
105+
val cppTurboModuleJavaProviders =
106+
packagesWithLibraryNames.joinToString("\n") { dep ->
107+
val libraryName = dep.platforms?.android?.libraryName
108+
// language=cpp
109+
"""
110+
auto module_$libraryName = ${libraryName}_ModuleProvider(moduleName, params);
111+
if (module_$libraryName != nullptr) {
112+
return module_$libraryName;
113+
}
114+
"""
115+
.trimIndent()
116+
}
117+
118+
val cppTurboModuleCxxProviders =
119+
packagesWithLibraryNames
120+
.filter { it.platforms?.android?.cxxModuleHeaderName != null }
121+
.joinToString("\n") { dep ->
122+
val cxxModuleHeaderName = dep.platforms?.android?.cxxModuleHeaderName
123+
// language=cpp
124+
"""
125+
if (moduleName == $cxxModuleHeaderName::kModuleName) {
126+
return std::make_shared<$cxxModuleHeaderName>(jsInvoker);
127+
}
128+
"""
129+
.trimIndent()
130+
}
131+
132+
val cppComponentDescriptors =
133+
packagesWithLibraryNames
134+
.filter {
135+
it.platforms?.android?.componentDescriptors != null &&
136+
it.platforms.android.componentDescriptors.isNotEmpty()
137+
}
138+
.joinToString("\n") {
139+
it.platforms?.android?.componentDescriptors?.joinToString("\n") {
140+
"providerRegistry->add(concreteComponentDescriptorProvider<$it>());"
141+
} ?: ""
142+
}
143+
144+
return CPP_TEMPLATE.replace("{{ rncliCppIncludes }}", cppIncludes)
145+
.replace("{{ rncliCppTurboModuleJavaProviders }}", cppTurboModuleJavaProviders)
146+
.replace("{{ rncliCppTurboModuleCxxProviders }}", cppTurboModuleCxxProviders)
147+
.replace("{{ rncliCppComponentDescriptors }}", cppComponentDescriptors)
148+
}
149+
150+
companion object {
151+
const val CMAKE_FILENAME = "Android-autolinking.cmake"
152+
153+
// This needs to be changed to not be `rncli.h`, but requires change to CMake pipeline
154+
const val H_FILENAME = "rncli.h"
155+
const val CPP_FILENAME = "rncli.cpp"
156+
157+
const val CODEGEN_LIB_PREFIX = "react_codegen_"
158+
159+
const val COMPONENT_DESCRIPTOR_FILENAME = "ComponentDescriptors.h"
160+
const val COMPONENT_INCLUDE_PATH = "react/renderer/components"
161+
162+
// language=cmake
163+
val CMAKE_TEMPLATE =
164+
"""
165+
# This code was generated by [React Native](https://www.npmjs.com/package/@react-native/gradle-plugin)
166+
cmake_minimum_required(VERSION 3.13)
167+
set(CMAKE_VERBOSE_MAKEFILE on)
168+
169+
{{ libraryIncludes }}
170+
171+
set(AUTOLINKED_LIBRARIES
172+
{{ libraryModules }}
173+
)
174+
"""
175+
.trimIndent()
176+
177+
// language=cpp
178+
val CPP_TEMPLATE =
179+
"""
180+
/**
181+
* This code was generated by [React Native](https://www.npmjs.com/package/@react-native/gradle-plugin).
182+
*
183+
* Do not edit this file as changes may cause incorrect behavior and will be lost
184+
* once the code is regenerated.
185+
*
186+
*/
187+
188+
#include "rncli.h"
189+
{{ rncliCppIncludes }}
190+
191+
namespace facebook {
192+
namespace react {
193+
194+
std::shared_ptr<TurboModule> rncli_ModuleProvider(const std::string moduleName, const JavaTurboModule::InitParams &params) {
195+
{{ rncliCppTurboModuleJavaProviders }}
196+
return nullptr;
197+
}
198+
199+
std::shared_ptr<TurboModule> rncli_cxxModuleProvider(const std::string moduleName, const std::shared_ptr<CallInvoker>& jsInvoker) {
200+
{{ rncliCppTurboModuleCxxProviders }}
201+
return nullptr;
202+
}
203+
204+
void rncli_registerProviders(std::shared_ptr<ComponentDescriptorProviderRegistry const> providerRegistry) {
205+
{{ rncliCppComponentDescriptors }}
206+
return;
207+
}
208+
209+
} // namespace react
210+
} // namespace facebook
211+
"""
212+
.trimIndent()
213+
214+
// language=cpp
215+
val hTemplate =
216+
"""
217+
/**
218+
* This code was generated by [React Native](https://www.npmjs.com/package/@react-native/gradle-plugin).
219+
*
220+
* Do not edit this file as changes may cause incorrect behavior and will be lost
221+
* once the code is regenerated.
222+
*
223+
*/
224+
225+
#pragma once
226+
227+
#include <ReactCommon/CallInvoker.h>
228+
#include <ReactCommon/JavaTurboModule.h>
229+
#include <ReactCommon/TurboModule.h>
230+
#include <jsi/jsi.h>
231+
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
232+
233+
namespace facebook {
234+
namespace react {
235+
236+
std::shared_ptr<TurboModule> rncli_ModuleProvider(const std::string moduleName, const JavaTurboModule::InitParams &params);
237+
std::shared_ptr<TurboModule> rncli_cxxModuleProvider(const std::string moduleName, const std::shared_ptr<CallInvoker>& jsInvoker);
238+
void rncli_registerProviders(std::shared_ptr<ComponentDescriptorProviderRegistry const> providerRegistry);
239+
240+
} // namespace react
241+
} // namespace facebook
242+
"""
243+
.trimIndent()
244+
}
245+
}

0 commit comments

Comments
 (0)