Skip to content

Commit 90e6657

Browse files
committed
Handling non-framework dylibs too
1 parent 15e6b8b commit 90e6657

File tree

3 files changed

+160
-107
lines changed

3 files changed

+160
-107
lines changed

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

Lines changed: 148 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,6 @@ export function createPlistContent(values: Record<string, string>) {
129129
].join("\n");
130130
}
131131

132-
export function getAppleBuildArgs() {
133-
// We expect the final application to sign these binaries
134-
return ["CODE_SIGNING_ALLOWED=NO"];
135-
}
136-
137132
const xcframeworkExtensionOption = new Option(
138133
"--xcframework-extension",
139134
"Don't rename the xcframework to .apple.node",
@@ -147,6 +142,30 @@ function getBuildPath(baseBuildPath: string, triplet: Triplet) {
147142
return path.join(baseBuildPath, triplet.replace(/;/g, "_"));
148143
}
149144

145+
async function readCmakeSharedLibraryTarget(
146+
buildPath: string,
147+
configuration: string,
148+
target: string[],
149+
) {
150+
const targets = await cmakeFileApi.readCurrentTargetsDeep(
151+
buildPath,
152+
configuration,
153+
"2.0",
154+
);
155+
const sharedLibraries = targets.filter(
156+
({ type, name }) =>
157+
type === "SHARED_LIBRARY" &&
158+
(target.length === 0 || target.includes(name)),
159+
);
160+
assert.equal(
161+
sharedLibraries.length,
162+
1,
163+
"Expected exactly one shared library",
164+
);
165+
const [sharedLibrary] = sharedLibraries;
166+
return sharedLibrary;
167+
}
168+
150169
export const platform: Platform<Triplet[], AppleOpts> = {
151170
id: "apple",
152171
name: "Apple",
@@ -222,68 +241,94 @@ export const platform: Platform<Triplet[], AppleOpts> = {
222241
}
223242

224243
const buildPath = getBuildPath(build, triplet);
225-
const { project } = listXcodeProject(buildPath);
226244

227-
const schemes = project.schemes.filter(
228-
(scheme) => scheme !== "ALL_BUILD" && scheme !== "ZERO_CHECK",
245+
const sharedLibrary = await readCmakeSharedLibraryTarget(
246+
buildPath,
247+
configuration,
248+
target,
229249
);
230250

231-
assert(
232-
schemes.length === 1,
233-
`Expected exactly one buildable scheme, got ${schemes.join(", ")}`,
234-
);
251+
const isFramework = sharedLibrary.nameOnDisk?.includes(".framework/");
235252

236-
const [scheme] = schemes;
253+
if (isFramework) {
254+
const { project } = listXcodeProject(buildPath);
237255

238-
if (target.length === 1) {
239-
assert.equal(
240-
scheme,
241-
target[0],
242-
"Expected the only scheme to match the requested target",
256+
const schemes = project.schemes.filter(
257+
(scheme) => scheme !== "ALL_BUILD" && scheme !== "ZERO_CHECK",
243258
);
244-
}
245-
246-
// TODO: Don't forget "CODE_SIGNING_ALLOWED=NO"
247-
await spawn(
248-
"xcodebuild",
249-
[
250-
"archive",
251-
"-scheme",
252-
scheme,
253-
"-configuration",
254-
configuration,
255259

256-
// Ideally, we would just pass -destination here,
257-
// but I'm not able to configure / generate a single Xcode project supporting all
258-
"-destination",
259-
DESTINATION_BY_TRIPLET[triplet],
260+
assert(
261+
schemes.length === 1,
262+
`Expected exactly one buildable scheme, got ${schemes.join(", ")}`,
263+
);
260264

261-
// // TODO: Should this be outputPath?
262-
// "-archivePath",
263-
// "archives/MyFramework.xcarchive",
264-
],
265-
buildPath,
266-
);
267-
await spawn(
268-
"xcodebuild",
269-
[
270-
"install",
271-
"-scheme",
272-
scheme,
273-
"-configuration",
274-
configuration,
265+
const [scheme] = schemes;
275266

276-
// Ideally, we would just pass -destination here,
277-
// but I'm not able to configure / generate a single Xcode project supporting all
278-
"-destination",
279-
DESTINATION_BY_TRIPLET[triplet],
267+
if (target.length === 1) {
268+
assert.equal(
269+
scheme,
270+
target[0],
271+
"Expected the only scheme to match the requested target",
272+
);
273+
}
280274

281-
// // TODO: Should this be outputPath?
282-
// "-archivePath",
283-
// "archives/MyFramework.xcarchive",
284-
],
285-
buildPath,
286-
);
275+
await spawn(
276+
"xcodebuild",
277+
[
278+
"archive",
279+
"-scheme",
280+
scheme,
281+
"-configuration",
282+
configuration,
283+
284+
// Ideally, we would just pass -destination here,
285+
// but I'm not able to configure / generate a single Xcode project supporting all
286+
"-destination",
287+
DESTINATION_BY_TRIPLET[triplet],
288+
],
289+
buildPath,
290+
);
291+
await spawn(
292+
"xcodebuild",
293+
[
294+
"install",
295+
"-scheme",
296+
scheme,
297+
"-configuration",
298+
configuration,
299+
300+
// Ideally, we would just pass -destination here,
301+
// but I'm not able to configure / generate a single Xcode project supporting all
302+
"-destination",
303+
DESTINATION_BY_TRIPLET[triplet],
304+
],
305+
buildPath,
306+
);
307+
} else {
308+
await spawn("cmake", [
309+
"--build",
310+
buildPath,
311+
"--config",
312+
configuration,
313+
...(target.length > 0 ? ["--target", ...target] : []),
314+
"--",
315+
316+
// Skip code-signing (needed when building free dynamic libraries)
317+
// TODO: Make this configurable
318+
"CODE_SIGNING_ALLOWED=NO",
319+
]);
320+
// Create a framework
321+
const { artifacts } = sharedLibrary;
322+
assert(
323+
artifacts && artifacts.length === 1,
324+
"Expected exactly one artifact",
325+
);
326+
const [artifact] = artifacts;
327+
await createAppleFramework(
328+
path.join(buildPath, artifact.path),
329+
triplet.endsWith("-darwin"),
330+
);
331+
}
287332
},
288333
isSupportedByHost: function (): boolean | Promise<boolean> {
289334
return process.platform === "darwin";
@@ -293,72 +338,70 @@ export const platform: Platform<Triplet[], AppleOpts> = {
293338
triplets,
294339
{ configuration, autoLink, xcframeworkExtension, target, build },
295340
) {
296-
const prebuilds: Record<string, string[]> = {};
341+
const libraryNames = new Set<string>();
342+
const frameworkPaths: string[] = [];
297343
for (const { triplet } of triplets) {
298344
const buildPath = getBuildPath(build, triplet);
299345
assert(fs.existsSync(buildPath), `Expected a directory at ${buildPath}`);
300-
const targets = await cmakeFileApi.readCurrentTargetsDeep(
346+
const sharedLibrary = await readCmakeSharedLibraryTarget(
301347
buildPath,
302348
configuration,
303-
"2.0",
304-
);
305-
const sharedLibraries = targets.filter(
306-
({ type, name }) =>
307-
type === "SHARED_LIBRARY" &&
308-
(target.length === 0 || target.includes(name)),
309-
);
310-
assert.equal(
311-
sharedLibraries.length,
312-
1,
313-
"Expected exactly one shared library",
349+
target,
314350
);
315-
const [sharedLibrary] = sharedLibraries;
316351
const { artifacts } = sharedLibrary;
317352
assert(
318353
artifacts && artifacts.length === 1,
319354
"Expected exactly one artifact",
320355
);
321356
const [artifact] = artifacts;
322-
// Add prebuild entry, creating a new entry if needed
323-
if (!(sharedLibrary.name in prebuilds)) {
324-
prebuilds[sharedLibrary.name] = [];
357+
libraryNames.add(sharedLibrary.name);
358+
// Locate the path of the framework, if a free dynamic library was built
359+
if (artifact.path.includes(".framework/")) {
360+
frameworkPaths.push(path.dirname(path.join(buildPath, artifact.path)));
361+
} else {
362+
const libraryName = path.basename(
363+
artifact.path,
364+
path.extname(artifact.path),
365+
);
366+
const frameworkPath = path.join(
367+
buildPath,
368+
path.dirname(artifact.path),
369+
`${libraryName}.framework`,
370+
);
371+
assert(
372+
fs.existsSync(frameworkPath),
373+
`Expected to find a framework at: ${frameworkPath}`,
374+
);
375+
frameworkPaths.push(frameworkPath);
325376
}
326-
prebuilds[sharedLibrary.name].push(path.join(buildPath, artifact.path));
327377
}
328378

329379
const extension = xcframeworkExtension ? ".xcframework" : ".apple.node";
330380

331-
for (const [libraryName, libraryPaths] of Object.entries(prebuilds)) {
332-
const frameworkPaths = await Promise.all(
333-
libraryPaths.map(async (libraryPath) => {
334-
const parentDir = path.dirname(libraryPath);
335-
if (path.extname(parentDir) === ".framework") {
336-
return parentDir;
337-
} else {
338-
return createAppleFramework(libraryPath);
339-
}
340-
}),
341-
);
381+
assert(
382+
libraryNames.size === 1,
383+
"Expected all libraries to have the same name",
384+
);
385+
const [libraryName] = libraryNames;
342386

343-
// Create the xcframework
344-
const xcframeworkOutputPath = path.resolve(
345-
outputPath,
346-
`${libraryName}${extension}`,
347-
);
387+
// Create the xcframework
388+
const xcframeworkOutputPath = path.resolve(
389+
outputPath,
390+
`${libraryName}${extension}`,
391+
);
348392

349-
await oraPromise(
350-
createXCframework({
351-
outputPath: xcframeworkOutputPath,
352-
frameworkPaths,
353-
autoLink,
354-
}),
355-
{
356-
text: `Assembling XCFramework (${libraryName})`,
357-
successText: `XCFramework (${libraryName}) assembled into ${prettyPath(xcframeworkOutputPath)}`,
358-
failText: ({ message }) =>
359-
`Failed to assemble XCFramework (${libraryName}): ${message}`,
360-
},
361-
);
362-
}
393+
await oraPromise(
394+
createXCframework({
395+
outputPath: xcframeworkOutputPath,
396+
frameworkPaths,
397+
autoLink,
398+
}),
399+
{
400+
text: `Assembling XCFramework (${libraryName})`,
401+
successText: `XCFramework (${libraryName}) assembled into ${prettyPath(xcframeworkOutputPath)}`,
402+
failText: ({ message }) =>
403+
`Failed to assemble XCFramework (${libraryName}): ${message}`,
404+
},
405+
);
363406
},
364407
};

packages/ferric/src/build.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,10 @@ export const buildCommand = new Command("build")
237237
if (appleLibraries.length > 0) {
238238
const libraryPaths = await combineLibraries(appleLibraries);
239239
const frameworkPaths = await Promise.all(
240-
libraryPaths.map(createAppleFramework),
240+
libraryPaths.map((libraryPath) =>
241+
// TODO: Pass true as `versioned` argument for -darwin targets
242+
createAppleFramework(libraryPath),
243+
),
241244
);
242245
const xcframeworkFilename = determineXCFrameworkFilename(
243246
frameworkPaths,

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,14 @@ type XCframeworkOptions = {
3030
autoLink: boolean;
3131
};
3232

33-
export async function createAppleFramework(libraryPath: string) {
33+
export async function createAppleFramework(
34+
libraryPath: string,
35+
versioned = false,
36+
) {
37+
if (versioned) {
38+
// TODO: Add support for generating a Versions/Current/Resources/Info.plist convention framework
39+
throw new Error("Creating versioned frameworks is not supported yet");
40+
}
3441
assert(fs.existsSync(libraryPath), `Library not found: ${libraryPath}`);
3542
// Write a info.plist file to the framework
3643
const libraryName = path.basename(libraryPath, path.extname(libraryPath));

0 commit comments

Comments
 (0)