Skip to content

Commit 6554402

Browse files
chrfalchfacebook-github-bot
authored andcommitted
Add script to prepare the .build folder to prebuild React Native with SwiftPM (#51195)
Summary: Pull Request resolved: #51195 This change adds a script that prepares the repository by creating hard links to the header files in the `.build` folder that is also gitignored ## Changelog: [Internal] - Add sdcript to setup the repository so that we can build it properly. Test Plan: run: ``` node packages/react-native/scripts/ios-prebuilds.js ``` observe the folder `.build` being created with all the files. Reviewed By: cortinico Differential Revision: D74393116 Pulled By: cipolleschi fbshipit-source-id: 4951e61b49db83fbebbcc265ae025f53185fec81
1 parent 500f458 commit 6554402

3 files changed

Lines changed: 184 additions & 1 deletion

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ vendor/
124124
!/packages/rn-tester/Pods/__offline_mirrors_hermes__
125125
!/packages/rn-tester/Pods/__offline_mirrors_jsc__
126126

127+
# Swift Package build folder
128+
/packages/react-native/.build
129+
127130
# @react-native/codegen
128131
/packages/react-native/React/FBReactNativeSpec/
129132
/packages/react-native-codegen/lib
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
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+
* @flow
8+
* @format
9+
* @oncall react_native
10+
*/
11+
12+
const {prepareHermesArtifactsAsync} = require('./ios-prebuild/hermes');
13+
const {
14+
createFolderIfNotExists,
15+
throwIfOnEden,
16+
} = require('./ios-prebuild/utils');
17+
const {execSync} = require('child_process');
18+
const fs = require('fs');
19+
const path = require('path');
20+
21+
async function main() {
22+
console.log('Prebuilding React Native iOS...');
23+
console.log('');
24+
25+
throwIfOnEden();
26+
27+
try {
28+
// Root
29+
const root = process.cwd();
30+
31+
// Create build folder
32+
const buildFolder = path.resolve(root, '.build');
33+
createFolderIfNotExists(buildFolder);
34+
35+
// Create the hard links folder
36+
const linksFolder = path.resolve(buildFolder, 'headers');
37+
createFolderIfNotExists(linksFolder);
38+
39+
/**
40+
* Creates a hard link from one path to another. For each subfolder
41+
* in the source path, it creates a link in the target path with an
42+
* underscore prefix.
43+
* @param {string} fromPath - The path to the source file or directory
44+
* @param {string} includePath - Path in the headers folder to create the link
45+
* @throws {Error} If the source path does not exist or if the link creation fails
46+
* @returns {void}
47+
*/
48+
const link = (fromPath /*:string*/, includePath /*:string*/) => {
49+
const source = path.resolve(root, fromPath);
50+
const target = path.resolve(linksFolder, includePath);
51+
console.log(`Linking ${source} to ${target}...`);
52+
53+
createFolderIfNotExists(target);
54+
55+
// get subfolders in source - make sure we only copy folders with header files
56+
const entries = fs.readdirSync(source, {withFileTypes: true});
57+
if (
58+
entries.some(
59+
dirent =>
60+
dirent.isFile() &&
61+
(String(dirent.name).endsWith('.h') ||
62+
String(dirent.name).endsWith('.hpp')),
63+
)
64+
) {
65+
// Create link for all header files (*.h, *.hpp) in the source directory
66+
entries.forEach(entry => {
67+
const entryName = String(entry.name);
68+
if (entry.isFile() && /\.(h|hpp)$/.test(entryName)) {
69+
const sourceFile = path.join(source, entryName);
70+
const targetFile = path.join(target, entryName);
71+
// Skip if the file already exists
72+
if (fs.existsSync(targetFile)) {
73+
return;
74+
}
75+
try {
76+
fs.linkSync(sourceFile, targetFile);
77+
} catch (e) {
78+
console.error(
79+
`Failed to create link for ${sourceFile} to ${targetFile}: ${e}`,
80+
);
81+
}
82+
}
83+
});
84+
}
85+
86+
const subfolders = entries
87+
.filter(dirent => dirent.isDirectory())
88+
.filter(dirent => dirent.name !== '__tests__')
89+
.map(dirent => dirent.name);
90+
91+
// Create links for subfolders
92+
subfolders.forEach(folder => {
93+
link(path.join(fromPath, String(folder)), includePath);
94+
});
95+
};
96+
97+
// CODEGEN
98+
console.log('Running codegen...');
99+
const codegenPath = path.join(root, '.build/codegen');
100+
createFolderIfNotExists(codegenPath);
101+
102+
const command = `node scripts/generate-codegen-artifacts -p "${root}" -o "${codegenPath}" -t ios`;
103+
console.log(command);
104+
execSync(command, {stdio: 'inherit'});
105+
106+
// HERMES ARTIFACTS
107+
console.log('Download hermes...');
108+
// Temporary hardcoded hermes version to make the script work
109+
// We will make it right in a future diff.
110+
// TODO: T223708709
111+
await prepareHermesArtifactsAsync('0.80.0-rc.0', 'release');
112+
113+
// LINKING
114+
link('Libraries/WebSocket/', 'React');
115+
link('React/Base', 'React');
116+
link('React/Base/Surface', 'React');
117+
link('React/CxxBridge', 'React');
118+
link('React/CxxModule', 'React');
119+
link('React/CxxUtils', 'React');
120+
link('React/DevSupport', 'React');
121+
link('React/Inspector', 'React');
122+
link('React/I18n', 'React');
123+
link('React/Views', 'React');
124+
link('React/CoreModules', 'React');
125+
link('React/Modules', 'React');
126+
link('React/Fabric', 'React');
127+
link('React/Profiler', 'React');
128+
link('React/CoreModules', 'React');
129+
link('React/Runtime', 'React');
130+
link('React/Views/ScrollView', 'React');
131+
link('React/Views/RefreshControl', 'React');
132+
link('Libraries/Text', 'React');
133+
link(
134+
'ReactApple/Libraries/RCTFoundation/RCTDeprecation/Exported',
135+
'RCTDeprecation',
136+
);
137+
link('Libraries/Required', 'RCTRequired');
138+
link('Libraries/TypeSafety', 'RCTTypeSafety');
139+
link('Libraries/Text', 'React');
140+
link('Libraries/Image', 'React');
141+
link('Libraries/Network', 'React');
142+
link('Libraries/Blob', 'React');
143+
link('Libraries/NativeAnimation', 'React');
144+
link('Libraries/LinkingIOS', 'React');
145+
146+
link('ReactCommon/hermes', 'reacthermes');
147+
link('ReactCommon/hermes', 'jsireact');
148+
149+
link(
150+
'ReactCommon/react/renderer/imagemanager',
151+
'react/renderer/imagemanager',
152+
);
153+
154+
// Done!
155+
console.log('🏁 Done!');
156+
} catch (err) {
157+
console.error(err);
158+
process.exitCode = 1;
159+
}
160+
}
161+
162+
if (require.main === module) {
163+
// eslint-disable-next-line no-void
164+
void main();
165+
}

packages/react-native/scripts/ios-prebuild/utils.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
* @oncall react_native
1010
*/
1111

12+
const {execSync} = require('child_process');
1213
const fs = require('fs');
1314

1415
/**
@@ -26,4 +27,18 @@ function createFolderIfNotExists(folderPath /*:string*/) /*: string*/ {
2627
return folderPath;
2728
}
2829

29-
module.exports = {createFolderIfNotExists};
30+
function throwIfOnEden() {
31+
try {
32+
execSync('eden info');
33+
} catch (error) {
34+
// eden info failed, we are not on Eden, do nothing
35+
return;
36+
}
37+
38+
throw new Error('Cannot prepare the iOS prebuilds on an Eden checkout');
39+
}
40+
41+
module.exports = {
42+
createFolderIfNotExists,
43+
throwIfOnEden,
44+
};

0 commit comments

Comments
 (0)