diff --git a/.github/workflows/prebuild-ios-dependencies.yml b/.github/workflows/prebuild-ios-dependencies.yml index 3ae438892382ae..70ca3fe2a5c70c 100644 --- a/.github/workflows/prebuild-ios-dependencies.yml +++ b/.github/workflows/prebuild-ios-dependencies.yml @@ -179,8 +179,9 @@ jobs: - name: Compress and Rename dSYM if: steps.restore-xcframework.outputs.cache-hit != 'true' run: | - tar -cz -f packages/react-native/third-party/Symbols/ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz \ - packages/react-native/third-party/Symbols/ReactNativeDependencies.framework.dSYM + cd packages/react-native/third-party/Symbols/ + tar -cz -f ../ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz . + mv ../ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz ./ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz - name: Upload XCFramework Artifact uses: actions/upload-artifact@v4 with: diff --git a/scripts/releases/ios-prebuild/compose-framework.js b/scripts/releases/ios-prebuild/compose-framework.js index e3887b38365e88..599622af6bc4a3 100644 --- a/scripts/releases/ios-prebuild/compose-framework.js +++ b/scripts/releases/ios-prebuild/compose-framework.js @@ -63,17 +63,12 @@ async function createFramework( // Copy bundles into the framework copyBundles(scheme, dependencies, output, frameworkPaths); - // Copy headers to the framework - start by building the Header folder - await copyHeaders(scheme, dependencies, rootFolder); + // Copy Symbols to symbols folder - copy before headers since we're using the folders inside the xcframework + // to get the arch slices. + copySymbols(scheme, output, frameworkPaths); - // Copy Symbols to symbols folder - const symbolPaths = frameworkPaths.map(framework => - path.join(framework, `${scheme}.framework.dSYM`), - ); - console.log('Copying symbols to symbols folder...'); - const symbolOutput = path.join(rootFolder, 'Symbols'); - fs.mkdirSync(symbolOutput, {recursive: true}); - symbolPaths.forEach(symbol => execSync(`cp -r ${symbol} ${symbolOutput}`)); + // Copy headers to the framework - start by building the Header folder + copyHeaders(scheme, dependencies, rootFolder); if (identity) { signXCFramework(identity, output); @@ -84,7 +79,7 @@ async function createFramework( * Copies headers needed from the package to a Header folder that we'll pass to * each framework arch type */ -async function copyHeaders( +function copyHeaders( scheme /*: string */, dependencies /*: $ReadOnlyArray */, rootFolder /*: string */, @@ -134,9 +129,15 @@ function copyBundles( // A bundle is the name of the framework + _ + target name + .bundle. We can // check if the target has a bundle by checking if it defines one or more resources. frameworkPaths.forEach(frameworkPath => { - const frameworkPlatforms = execSync( - `vtool -show-build ${path.join(frameworkPath, 'PackageFrameworks', scheme + '.framework', scheme)}|grep platform`, - ).toString(); + const frameworkPlatforms = getArchsFromFramework( + path.join( + frameworkPath, + 'PackageFrameworks', + scheme + '.framework', + scheme, + ), + ); + dependencies.forEach(dep => { const resources = dep.files.resources; if (!resources || resources.length === 0) { @@ -147,29 +148,25 @@ function copyBundles( const sourceBundlePath = path.join(frameworkPath, bundleName); if (fs.existsSync(sourceBundlePath)) { // Target folder - needs to be copied to the resulting framework - let targetArchFolderFound = false; - targetArchFolders.forEach(targetArchFolder => { - const targetPlatforms = execSync( - `vtool -show-build ${path.join(targetArchFolder, scheme + '.framework', scheme)}|grep platform`, - ).toString(); - - if (targetPlatforms === frameworkPlatforms) { - console.log( - ` ${path.relative(outputFolder, sourceBundlePath)} → ${path.basename(targetArchFolder)}`, - ); - const targetBundlePath = path.join( - targetArchFolder, - `${scheme}.framework`, - bundleName, - ); - - // A bundle is a directory, so we need to copy the whole directory - execSync(`cp -r "${sourceBundlePath}/" "${targetBundlePath}"`); - targetArchFolderFound = true; - } - }); - - if (!targetArchFolderFound) { + const targetFolder = targetArchFolders.find( + targetArchFolder => + getArchsFromFramework( + path.join(targetArchFolder, scheme + '.framework', scheme), + ) === frameworkPlatforms, + ); + if (targetFolder) { + console.log( + ` ${path.relative(outputFolder, sourceBundlePath)} → ${path.basename(targetFolder)}`, + ); + const targetBundlePath = path.join( + targetFolder, + `${scheme}.framework`, + bundleName, + ); + + // A bundle is a directory, so we need to copy the whole directory + execSync(`cp -r "${sourceBundlePath}/" "${targetBundlePath}"`); + } else { throw Error( `Could not find target architecture for folder ${path.relative(outputFolder, frameworkPath)}. Expected to find ${frameworkPlatforms}`, ); @@ -181,6 +178,75 @@ function copyBundles( }); } +function copySymbols( + scheme /*: string */, + outputFolder /*:string*/, + frameworkPaths /*:Array*/, +) { + console.log('Copying dSym files...'); + + const targetArchFolders = fs + .readdirSync(outputFolder) + .map(p => path.join(outputFolder, p)) + .filter(p => fs.statSync(p).isDirectory()); + + // For each framework (in frameworkPaths), copy the symbols from the source folder. + frameworkPaths.forEach(frameworkPath => { + const frameworkPlatforms = getArchsFromFramework( + path.join( + frameworkPath, + 'PackageFrameworks', + scheme + '.framework', + scheme, + ), + ); + + // Find the correct target folder based on the current architectures + const targetFolder = targetArchFolders.find( + targetArchFolder => + frameworkPlatforms === + getArchsFromFramework( + path.join(targetArchFolder, scheme + '.framework', scheme), + ), + ); + + if (!targetFolder) { + throw new Error(`Could not find target folder for ${frameworkPath}`); + } + const sourceSymbolPath = path.join( + frameworkPath, + scheme + '.framework.dSYM', + ); + if (!fs.existsSync(sourceSymbolPath)) { + throw new Error(`dSYM folder ${sourceSymbolPath} not found`); + } + + const archName = path.basename(targetFolder); + console.log( + ` ${path.relative(outputFolder, sourceSymbolPath)} → ${archName}`, + ); + + const targetSymbolPath = path.join( + outputFolder, + '..', + 'Symbols', + archName, + scheme + '.framework.dSYM', + ); + fs.mkdirSync(targetSymbolPath, {recursive: true}); + execSync(`cp -r "${sourceSymbolPath}/" "${targetSymbolPath}"`); + }); +} + +function getArchsFromFramework(frameworkPath /*:string*/) { + return execSync(`vtool -show-build ${frameworkPath}|grep platform`) + .toString() + .split('\n') + .map(p => p.trim().split(' ')[1]) + .sort((a, b) => a.localeCompare(b)) + .join(' '); +} + function signXCFramework( identity /*: string */, xcframeworkPath /*: string */,