From 3ee4b8f5a1107d9c126c31ea21f43f6334232a3e Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Wed, 22 Nov 2023 13:52:51 -0800 Subject: [PATCH] Create genrule to generate appmodules.so (#41466) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/41466 ## Context In open source, all apps use the same turbomodulemanager delegate (i.e: the default delegate). This diff introduces the buck infra that makes the oss default delegate work for meta apps. Concretely, we are going to make React Native use the same delegate for **all** Meta apps. Each Meta app will: 1. At build time, generate a unique TMProvider map 2. At app init time, initialize the default delegate with the TMProvider map. ## Implementation **Step #1:** At build time, generate a unique TMProvider map **Insight:** Buck genrules can accept, as input, the output of a buck query. So, here's how we get this done: 1. Buck query (i.e: input to Genrule): Given the app's deps, query all the schemas in the app. 2. Genrule: Read the schemas to generate the TMProvider map. The TMProvider map will also contain **all** the app's C++ module codegen. Concretely: 1. This diff introduces a macro: rn_codegen_appmodules(deps). 2. rn_codegen_appmodules(deps) generates appmodules.so, which contains the TMProvider map. **Step #2:** At app init time, initialize the default delegate with the TMProvider map. This is how we'll initialize the DefaultTurboModuleManagerDelegate: 1. DefaultTurboModuleManagerDelegate will load appmodules.so during init. 2. When loaded, appmodules.so will assign the code-generated TMProvider map to DefaultTurboModuleManagerDelegate. ## Impact This should allow us to: 1. Get one step closer to getting rid of the `js1 build turbomodule-manager-delegates --target ` script 3. Remove the TurboModuleManagerDelegate from React Native's public API. (Because we use one delegate for all React Native apps in Meta and OSS) Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D50988397 fbshipit-source-id: 0ca5dec14e2dae89ec97f5d39a182c7937c5c7bf --- .../src/cli/combine/combine-schemas-cli.js | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 packages/react-native-codegen/src/cli/combine/combine-schemas-cli.js diff --git a/packages/react-native-codegen/src/cli/combine/combine-schemas-cli.js b/packages/react-native-codegen/src/cli/combine/combine-schemas-cli.js new file mode 100644 index 00000000000000..d8425e10ef018a --- /dev/null +++ b/packages/react-native-codegen/src/cli/combine/combine-schemas-cli.js @@ -0,0 +1,85 @@ +/** + * 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 strict-local + * @format + */ + +'use strict'; + +import type { + ComponentSchema, + NativeModuleSchema, + SchemaType, +} from '../../CodegenSchema.js'; + +const assert = require('assert'); +const fs = require('fs'); +const util = require('util'); + +const {values: args} = util.parseArgs({ + options: { + platform: { + type: 'string', + }, + output: { + type: 'string', + }, + ['schema-query']: { + type: 'string', + }, + }, +}); +if (!['iOS', 'android'].includes(args.platform)) { + throw new Error(`Invalid platform ${args.platform}`); +} +const platform = args.platform; +const output = args.output; +const schemaQuery: string = args['schema-query']; + +if (!schemaQuery.startsWith('@')) { + throw new Error( + "The argument provided to --schema-query must be a filename that starts with '@'.", + ); +} + +const schemaQueryOutputFile = schemaQuery.replace(/^@/, ''); +const schemaQueryOutput = fs.readFileSync(schemaQueryOutputFile, 'utf8'); + +const schemaFiles = schemaQueryOutput.split(' '); +const modules: { + [hasteModuleName: string]: NativeModuleSchema | ComponentSchema, +} = {}; +const specNameToFile: {[hasteModuleName: string]: string} = {}; + +for (const file of schemaFiles) { + const schema: SchemaType = JSON.parse(fs.readFileSync(file, 'utf8')); + + if (schema.modules) { + for (const specName in schema.modules) { + const module = schema.modules[specName]; + if (modules[specName]) { + assert.deepEqual( + module, + modules[specName], + `App contained two specs with the same file name '${specName}'. Schemas: ${specNameToFile[specName]}, ${file}. Please rename one of the specs.`, + ); + } + + if ( + module.excludedPlatforms && + module.excludedPlatforms.indexOf(platform) >= 0 + ) { + continue; + } + + modules[specName] = module; + specNameToFile[specName] = file; + } + } +} + +fs.writeFileSync(output, JSON.stringify({modules}, null, 2));