Skip to content

Commit

Permalink
Introduce the "platform" option to generate-codegen-artifacts.js (#42012
Browse files Browse the repository at this point in the history
)

Summary:
Pull Request resolved: #42012

Up until now `generate-codegen-artifacts.js` has been iOS only. But its logic is actually quite general, and this diff makes it platform agnostic.

Changelog: [General][Added] - Introduce the "platform" option to generate-codegen-artifacts.js

Reviewed By: RSNara

Differential Revision: D52257542

fbshipit-source-id: b7e698c779f7c6dae9b0de98a19ba452111fea5e
  • Loading branch information
dmytrorykun authored and facebook-github-bot committed Dec 21, 2023
1 parent 4885743 commit 7b10609
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,8 @@ def testUseReactCodegenDiscovery_whenParametersAreGood_executeCodegen
"command" => "node",
"arguments"=> ["~/app/ios/../node_modules/react-native/scripts/generate-codegen-artifacts.js",
"-p", "~/app",
"-o", Pod::Config.instance.installation_root]
"-o", Pod::Config.instance.installation_root,
"-t", "ios"]
}
])
end
Expand Down
1 change: 1 addition & 0 deletions packages/react-native/scripts/cocoapods/codegen_utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ def use_react_native_codegen_discovery!(
"#{relative_installation_root}/#{react_native_path}/scripts/generate-codegen-artifacts.js",
"-p", "#{app_path}",
"-o", Pod::Config.instance.installation_root,
"-t", "ios",
])
Pod::UI.puts out;

Expand Down
171 changes: 137 additions & 34 deletions packages/react-native/scripts/codegen/generate-artifacts-executor.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,28 @@ const REACT_NATIVE_REPOSITORY_ROOT = path.join(
const REACT_NATIVE_PACKAGE_ROOT_FOLDER = path.join(__dirname, '..', '..');
const CODEGEN_REPO_PATH = `${REACT_NATIVE_REPOSITORY_ROOT}/packages/react-native-codegen`;
const CORE_LIBRARIES_WITH_OUTPUT_FOLDER = {
rncore: path.join(REACT_NATIVE_PACKAGE_ROOT_FOLDER, 'ReactCommon'),
FBReactNativeSpec: null,
rncore: {
ios: path.join(REACT_NATIVE_PACKAGE_ROOT_FOLDER, 'ReactCommon'),
android: path.join(
REACT_NATIVE_PACKAGE_ROOT_FOLDER,
'ReactAndroid',
'build',
'generated',
'source',
'codegen',
),
},
FBReactNativeSpec: {
ios: null,
android: path.join(
REACT_NATIVE_PACKAGE_ROOT_FOLDER,
'ReactAndroid',
'build',
'generated',
'source',
'codegen',
),
},
};
const REACT_NATIVE = 'react-native';

Expand Down Expand Up @@ -190,24 +210,69 @@ function buildCodegenIfNeeded() {
});
}

function computeOutputPath(projectRoot, baseOutputPath, pkgJson) {
function readOutputDirFromPkgJson(pkgJson, platform) {
const codegenConfig = pkgJson.codegenConfig;
if (codegenConfig == null || typeof codegenConfig !== 'object') {
return null;
}
const outputDir = codegenConfig.outputDir;
if (outputDir == null) {
return null;
}
if (typeof outputDir === 'string') {
return outputDir;
}
if (typeof outputDir === 'object') {
return outputDir[platform];
}
return null;
}

function defaultOutputPathForAndroid(baseOutputPath) {
return path.join(
baseOutputPath,
'android',
'app',
'build',
'generated',
'source',
'codegen',
);
}

function defaultOutputPathForIOS(baseOutputPath) {
return path.join(baseOutputPath, 'build', 'generated', 'ios');
}

function computeOutputPath(projectRoot, baseOutputPath, pkgJson, platform) {
if (baseOutputPath == null) {
const baseOutputPathOverride = pkgJson.codegenConfig.outputDir;
if (baseOutputPathOverride && typeof baseOutputPathOverride === 'string') {
baseOutputPath = baseOutputPathOverride;
const outputDirFromPkgJson = readOutputDirFromPkgJson(pkgJson, platform);
if (outputDirFromPkgJson != null) {
baseOutputPath = outputDirFromPkgJson;
} else {
baseOutputPath = projectRoot;
}
}
if (pkgJsonIncludesGeneratedCode(pkgJson)) {
// Don't create nested directories for libraries to make importing generated headers easier.
return baseOutputPath;
} else {
return path.join(baseOutputPath, 'build', 'generated', 'ios');
}
if (platform === 'android') {
return defaultOutputPathForAndroid(baseOutputPath);
}
if (platform === 'ios') {
return defaultOutputPathForIOS(baseOutputPath);
}
return baseOutputPath;
}

function generateSchemaInfo(library) {
function reactNativeCoreLibraryOutputPath(libraryName, platform) {
return CORE_LIBRARIES_WITH_OUTPUT_FOLDER[libraryName]
? CORE_LIBRARIES_WITH_OUTPUT_FOLDER[libraryName][platform]
: null;
}

function generateSchemaInfo(library, platform) {
const pathToJavaScriptSources = path.join(
library.libraryPath,
library.config.jsSrcsDir,
Expand All @@ -220,22 +285,23 @@ function generateSchemaInfo(library) {
.getCombineJSToSchema()
.combineSchemasInFileList(
[pathToJavaScriptSources],
'ios',
platform,
/NativeSampleTurboModule/,
),
};
}

function generateCode(iosOutputDir, schemaInfo, includesGeneratedCode) {
function generateCode(outputPath, schemaInfo, includesGeneratedCode, platform) {
const tmpDir = fs.mkdtempSync(
path.join(os.tmpdir(), schemaInfo.library.config.name),
);
const tmpOutputDir = path.join(tmpDir, 'out');
fs.mkdirSync(tmpOutputDir, {recursive: true});

console.log(`[Codegen] >>>>> Generating Native Code for ${platform}`);
const useLocalIncludePaths = includesGeneratedCode;
generateSpecsCLIExecutor.generateSpecFromInMemorySchema(
'ios',
platform,
schemaInfo.schema,
tmpOutputDir,
schemaInfo.library.config.name,
Expand All @@ -246,8 +312,10 @@ function generateCode(iosOutputDir, schemaInfo, includesGeneratedCode) {

// Finally, copy artifacts to the final output directory.
const outputDir =
CORE_LIBRARIES_WITH_OUTPUT_FOLDER[schemaInfo.library.config.name] ??
iosOutputDir;
reactNativeCoreLibraryOutputPath(
schemaInfo.library.config.name,
platform,
) ?? outputPath;
fs.mkdirSync(outputDir, {recursive: true});
// TODO: Fix this. This will not work on Windows.
execSync(`cp -R ${tmpOutputDir}/* "${outputDir}"`);
Expand All @@ -258,17 +326,26 @@ function generateSchemaInfos(libraries) {
return libraries.map(generateSchemaInfo);
}

function generateNativeCode(iosOutputDir, schemaInfos, includesGeneratedCode) {
function generateNativeCode(
outputPath,
schemaInfos,
includesGeneratedCode,
platform,
) {
return schemaInfos.map(schemaInfo => {
generateCode(iosOutputDir, schemaInfo, includesGeneratedCode);
generateCode(outputPath, schemaInfo, includesGeneratedCode, platform);
});
}

function needsThirdPartyComponentProvider(schemaInfo) {
function rootCodegenTargetNeedsThirdPartyComponentProvider(pkgJson, platform) {
return !pkgJsonIncludesGeneratedCode(pkgJson) && platform === 'ios';
}

function dependencyNeedsThirdPartyComponentProvider(schemaInfo, platform) {
// Filter the react native core library out.
// In the future, core library and third party library should
// use the same way to generate/register the fabric components.
return !isReactNativeCoreLibrary(schemaInfo.library.config.name);
return !isReactNativeCoreLibrary(schemaInfo.library.config.name, platform);
}

function mustGenerateNativeCode(includeLibraryPath, schemaInfo) {
Expand Down Expand Up @@ -354,16 +431,29 @@ function cleanupEmptyFilesAndFolders(filepath) {
*
* @parameter projectRoot: the directory with the app source code, where the package.json lives.
* @parameter baseOutputPath: the base output path for the CodeGen.
* @parameter targetPlatform: the target platform. Supported values: 'android', 'ios', 'all'.
* @throws If it can't find a config file for react-native.
* @throws If it can't find a CodeGen configuration in the file.
* @throws If it can't find a cli for the CodeGen.
*/
function execute(projectRoot, baseOutputPath) {
function execute(projectRoot, targetPlatform, baseOutputPath) {
try {
console.log(
`[Codegen] Analyzing ${path.join(projectRoot, 'package.json')}`,
);

const supportedPlatforms = ['android', 'ios'];
if (
targetPlatform !== 'all' &&
!supportedPlatforms.includes(targetPlatform)
) {
throw new Error(
`Invalid target platform: ${targetPlatform}. Supported values are: ${supportedPlatforms.join(
', ',
)}, all`,
);
}

const pkgJson = readPkgJsonInDirectory(projectRoot);

buildCodegenIfNeeded();
Expand All @@ -375,24 +465,37 @@ function execute(projectRoot, baseOutputPath) {
return;
}

const outputPath = computeOutputPath(projectRoot, baseOutputPath, pkgJson);
let platforms =
targetPlatform === 'all' ? supportedPlatforms : [targetPlatform];

const schemaInfos = generateSchemaInfos(libraries);
generateNativeCode(
outputPath,
schemaInfos.filter(schemaInfo =>
mustGenerateNativeCode(projectRoot, schemaInfo),
),
pkgJsonIncludesGeneratedCode(pkgJson),
);
for (const platform of platforms) {
const outputPath = computeOutputPath(
projectRoot,
baseOutputPath,
pkgJson,
platform,
);

if (!pkgJsonIncludesGeneratedCode(pkgJson)) {
const schemas = schemaInfos
.filter(needsThirdPartyComponentProvider)
.map(schemaInfo => schemaInfo.schema);
createComponentProvider(schemas);
const schemaInfos = generateSchemaInfos(libraries);
generateNativeCode(
outputPath,
schemaInfos.filter(schemaInfo =>
mustGenerateNativeCode(projectRoot, schemaInfo),
),
pkgJsonIncludesGeneratedCode(pkgJson),
platform,
);

if (
rootCodegenTargetNeedsThirdPartyComponentProvider(pkgJson, platform)
) {
const schemas = schemaInfos
.filter(dependencyNeedsThirdPartyComponentProvider)
.map(schemaInfo => schemaInfo.schema);
createComponentProvider(schemas);
}
cleanupEmptyFilesAndFolders(outputPath);
}
cleanupEmptyFilesAndFolders(outputPath);
} catch (err) {
console.error(err);
process.exitCode = 1;
Expand Down
10 changes: 7 additions & 3 deletions packages/react-native/scripts/generate-codegen-artifacts.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,15 @@ const argv = yargs
alias: 'path',
description: 'Path to the React Native project root.',
})
.option('t', {
alias: 'targetPlatform',
description: 'Target platform. Supported values: "android", "ios", "all".',
})
.option('o', {
alias: 'outputPath',
description: 'Path where generated artifacts will be output to.',
})
.usage('Usage: $0 -p [path to app]')
.demandOption(['p']).argv;
.usage('Usage: $0 -p [path to app] -t [target platform] -o [output path]')
.demandOption(['p', 't']).argv;

executor.execute(argv.path, argv.outputPath);
executor.execute(argv.path, argv.targetPlatform, argv.outputPath);
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ generateCodegenArtifactsFromSchema () {
generateArtifacts () {
describe "Generating codegen artifacts"
pushd "$RCT_SCRIPT_RN_DIR" >/dev/null || exit 1
"$NODE_BINARY" "scripts/generate-codegen-artifacts.js" --path "$RCT_SCRIPT_APP_PATH" --outputPath "$TEMP_OUTPUT_DIR"
"$NODE_BINARY" "scripts/generate-codegen-artifacts.js" --path "$RCT_SCRIPT_APP_PATH" --outputPath "$TEMP_OUTPUT_DIR" --targetPlatform "ios"
popd >/dev/null || exit 1
}

Expand Down

0 comments on commit 7b10609

Please sign in to comment.