Skip to content

Commit 0ab7186

Browse files
committed
Dereference framework directories
1 parent f989aac commit 0ab7186

File tree

4 files changed

+66
-1
lines changed

4 files changed

+66
-1
lines changed

packages/cmake-rn/src/platforms/apple.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,7 @@ export const platform: Platform<Triplet[], AppleOpts> = {
391391
outputPath: xcframeworkOutputPath,
392392
frameworkPaths,
393393
autoLink,
394+
dereferenceFrameworkLinks: true,
394395
}),
395396
{
396397
text: `Assembling XCFramework (${libraryName})`,

packages/host/src/node/path-utils.test.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
isNodeApiModule,
1414
stripExtension,
1515
findNodeApiModulePathsByDependency,
16+
dereferenceDirectory,
1617
} from "./path-utils.js";
1718
import { setupTempDirectory } from "./test-utils.js";
1819

@@ -502,3 +503,37 @@ describe("findNodeAddonForBindings()", () => {
502503
});
503504
}
504505
});
506+
507+
describe("dereferenceDirectory", () => {
508+
describe("when directory contains symlinks", () => {
509+
it("should dereference symlinks", async (context) => {
510+
// Create a temp directory with a symlink
511+
const tempDir = setupTempDirectory(context, {
512+
"original/file.txt": "Hello, world!",
513+
});
514+
const originalPath = path.join(tempDir, "original");
515+
const symlinkPath = path.join(tempDir, "link");
516+
// Create a link to the original directory
517+
fs.symlinkSync(originalPath, symlinkPath, "dir");
518+
// And an internal link
519+
fs.symlinkSync(
520+
path.join(originalPath, "file.txt"),
521+
path.join(originalPath, "linked-file.txt"),
522+
"file",
523+
);
524+
525+
await dereferenceDirectory(symlinkPath);
526+
527+
// Verify that outer link is no longer a link
528+
const symlinkStat = await fs.promises.lstat(symlinkPath);
529+
assert(!symlinkStat.isSymbolicLink());
530+
531+
// Verify that the internal link is still a link to a readable file
532+
const internalLinkPath = path.join(symlinkPath, "linked-file.txt");
533+
const internalLinkStat = await fs.promises.lstat(internalLinkPath);
534+
assert(internalLinkStat.isSymbolicLink());
535+
const content = await fs.promises.readFile(internalLinkPath, "utf8");
536+
assert.equal(content, "Hello, world!");
537+
});
538+
});
539+
});

packages/host/src/node/path-utils.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,3 +483,16 @@ export function findNodeAddonForBindings(id: string, fromDir: string) {
483483
}
484484
return undefined;
485485
}
486+
487+
export async function dereferenceDirectory(dirPath: string) {
488+
const tempPath = dirPath + ".tmp";
489+
// Move the existing framework out of the way
490+
await fs.promises.rename(dirPath, tempPath);
491+
// Only dereference the symlink at tempPath (not recursively)
492+
const realPath = await fs.promises.realpath(tempPath);
493+
await fs.promises.cp(realPath, dirPath, {
494+
recursive: true,
495+
verbatimSymlinks: true,
496+
});
497+
await fs.promises.unlink(tempPath);
498+
}

packages/host/src/node/prebuilds/apple.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ import os from "node:os";
66
import { spawn } from "@react-native-node-api/cli-utils";
77

88
import { AppleTriplet } from "./triplets.js";
9-
import { determineLibraryBasename } from "../path-utils.js";
9+
import {
10+
dereferenceDirectory,
11+
determineLibraryBasename,
12+
} from "../path-utils.js";
1013

1114
type AppleArchitecture = "arm64" | "x86_64" | "arm64;x86_64";
1215

@@ -42,6 +45,7 @@ type XCframeworkOptions = {
4245
frameworkPaths: string[];
4346
outputPath: string;
4447
autoLink: boolean;
48+
dereferenceFrameworkLinks: boolean;
4549
};
4650

4751
export async function createAppleFramework(
@@ -97,6 +101,7 @@ export async function createXCframework({
97101
frameworkPaths,
98102
outputPath,
99103
autoLink,
104+
dereferenceFrameworkLinks,
100105
}: XCframeworkOptions) {
101106
// Delete any existing xcframework to prevent the error:
102107
// - A library with the identifier 'macos-arm64' already exists.
@@ -121,6 +126,17 @@ export async function createXCframework({
121126
outputMode: "buffered",
122127
},
123128
);
129+
if (dereferenceFrameworkLinks) {
130+
// TODO: Loop over the framework directories and copy their content if they're links
131+
for await (const entry of fs.promises.glob("**/*.framework", {
132+
cwd: xcodeOutputPath,
133+
withFileTypes: true,
134+
})) {
135+
if (entry.isSymbolicLink()) {
136+
await dereferenceDirectory(path.join(entry.parentPath, entry.name));
137+
}
138+
}
139+
}
124140
if (xcodeOutputPath !== outputPath) {
125141
// Rename the xcframework to the original output path
126142
await fs.promises.rename(xcodeOutputPath, outputPath);

0 commit comments

Comments
 (0)