crossbind 2.0.0-beta.68 → 2.0.0-beta.69
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +69 -59
- package/src/actions/addExtension.js +191 -0
- package/src/actions/androidGradle.js +26 -17
- package/src/actions/appInstaller.js +69 -153
- package/src/actions/appSwift.js +66 -0
- package/src/actions/buildApp.js +172 -74
- package/src/actions/buildNode.js +6 -1
- package/src/actions/buildWasm.js +0 -9
- package/src/actions/createInterface.js +17 -8
- package/src/actions/createLib.js +0 -4
- package/src/actions/extensionApi.js +298 -0
- package/src/actions/extensionCommands.js +41 -0
- package/src/actions/extensionsInApp.js +19 -0
- package/src/actions/gradleProject.js +196 -16
- package/src/actions/iosDevice.js +2 -2
- package/src/actions/iosSimulator.js +3 -3
- package/src/actions/licenses.js +83 -34
- package/src/actions/linuxPackages.js +48 -0
- package/src/actions/mavenVerification.js +37 -0
- package/src/actions/publish.js +220 -0
- package/src/actions/windowsSigning.js +1 -1
- package/src/actions/xcodeProject.js +49 -24
- package/src/actions/xcodeTargets.js +122 -0
- package/src/actions/xcodebuild.js +65 -0
- package/src/app/index.d.ts +126 -133
- package/src/app/index.js +126 -188
- package/src/assets/configure/install.sh +0 -0
- package/src/assets/toolchain-digests.json +20 -20
- package/src/bin.js +20 -28
- package/src/index.js +2 -1
- package/src/program.js +32 -3
- package/src/state/index.js +2 -1
- package/src/state/loadConfig.js +16 -5
- package/src/utils/appExtensions.js +761 -0
- package/src/utils/appFiles.js +58 -0
- package/src/utils/appLaunches.js +249 -0
- package/src/utils/appOptions.js +109 -100
- package/src/utils/appTargets.js +168 -0
- package/src/utils/bridgeTools.js +66 -0
- package/src/utils/configChanges.js +30 -0
- package/src/utils/configWriter.js +143 -26
- package/src/utils/extensionSteps.js +135 -0
- package/src/utils/openUrl.js +2 -1
- package/src/utils/plist.js +5 -0
- package/src/utils/resolveAppHost.js +7 -0
- package/src/utils/systemConfig.js +16 -3
- package/vitest.config.js +6 -1
- package/src/actions/appSetup.js +0 -116
- package/src/actions/appStoreConnect.js +0 -188
- package/src/actions/appUpdate.js +0 -68
- package/src/actions/extensions.js +0 -7
- package/src/actions/googlePlay.js +0 -213
- package/src/actions/googleSignIn.js +0 -78
- package/src/actions/playSetup.js +0 -19
- package/src/actions/publishAndroid.js +0 -102
- package/src/actions/publishIos.js +0 -146
package/src/actions/buildApp.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
-
import { spawnSync } from 'node:child_process';
|
|
5
4
|
import { fileURLToPath } from 'node:url';
|
|
6
5
|
import { rollup } from 'rollup';
|
|
7
6
|
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
|
@@ -20,8 +19,8 @@ import writeXcodeProject, { HERMES_SLICES, IOS_SDKS } from './xcodeProject.js';
|
|
|
20
19
|
import writeGradleProject, { ANDROID_ABIS } from './gradleProject.js';
|
|
21
20
|
import { attachedDevice } from './androidDevice.js';
|
|
22
21
|
import { packageAndroidRelease } from './androidGradle.js';
|
|
23
|
-
import
|
|
24
|
-
import
|
|
22
|
+
import { compileSwift, swiftLinkArgs } from './appSwift.js';
|
|
23
|
+
import { unpackPackages } from './linuxPackages.js';
|
|
25
24
|
import { APPLE_SIGNING, appleSigning, notarizeApp } from './appleSigning.js';
|
|
26
25
|
import { WINDOWS_SIGNING, signWindows, windowsSigning } from './windowsSigning.js';
|
|
27
26
|
import state from '../state/index.js';
|
|
@@ -30,10 +29,15 @@ import findFiles from '../utils/findFiles.js';
|
|
|
30
29
|
import { getContentHash, getFilesFingerprint } from '../utils/hash.js';
|
|
31
30
|
import { xmlPlist } from '../utils/plist.js';
|
|
32
31
|
import {
|
|
33
|
-
appBackgroundColor, appCategory, appCopyright, appDisplayName, appEncryption, appHeader, appId, appPermissions, appPrivacy,
|
|
34
|
-
usageDescriptions,
|
|
32
|
+
androidAppId, appBackgroundColor, appCategory, appCopyright, appDisplayName, appEncryption, appFiles, appHeader, appId, appPermissions, appPrivacy,
|
|
33
|
+
appUrlSchemes, iosAppGroup, iosMultipleWindows, urlSchemeOwners, usageDescriptions,
|
|
35
34
|
} from '../utils/appOptions.js';
|
|
35
|
+
import { carriedFilesOf, copyCarriedFiles } from '../utils/appFiles.js';
|
|
36
|
+
import { activityTypeOwners, fileTypeOwners, linkOwners, macDocumentTypes, shortcutItemOwners } from '../utils/appLaunches.js';
|
|
36
37
|
import { unreasonedApis, unreasonedWarning } from '../utils/requiredReasonApis.js';
|
|
38
|
+
import {
|
|
39
|
+
appExtensionsOf, extensionCmakeArgs, extensionPart, mergedEntitlements, mergedPlist, mergedPrivacy, registrationSource,
|
|
40
|
+
} from '../utils/appExtensions.js';
|
|
37
41
|
import { androidIcons, iosIcon, linuxIcon, macIcon, readAppIcon, windowsIcon } from '../utils/appIcon.js';
|
|
38
42
|
import writeIfChanged from '../utils/writeIfChanged.js';
|
|
39
43
|
import { writeNativeSourceStamp } from '../utils/nativeSourceStamp.js';
|
|
@@ -41,8 +45,10 @@ import resetCMakeCacheForSource from '../utils/resetCMakeCacheForSource.js';
|
|
|
41
45
|
import resolveAppHostRoot, { resolveAppEmbindJsiRoot } from '../utils/resolveAppHost.js';
|
|
42
46
|
import resolveHermes, { HERMES } from '../utils/hermes.js';
|
|
43
47
|
import { getDockerImage, imageRoleFor } from '../utils/pullDockerImage.js';
|
|
48
|
+
import { isUnderBase } from '../utils/replaceBasePathForDocker.js';
|
|
44
49
|
import { chosenRunner } from '../utils/selectRunner.js';
|
|
45
50
|
import { DARWIN_DEPLOYMENT_TARGET } from '../utils/darwinToolchain.js';
|
|
51
|
+
import extensionsInApp from './extensionsInApp.js';
|
|
46
52
|
|
|
47
53
|
const cpuCount = Math.max(1, os.cpus().length - 1);
|
|
48
54
|
const BRIDGE = 'AppBridge';
|
|
@@ -50,6 +56,17 @@ const LINUX_MULTIARCH = { x64: 'x86_64-linux-gnu', arm64: 'aarch64-linux-gnu' };
|
|
|
50
56
|
// Where the android-app, linux and windows images keep the Hermes of the release crossbind pins.
|
|
51
57
|
const IMAGE_HERMES = `/opt/crossbind/hermes/${HERMES.version}`;
|
|
52
58
|
|
|
59
|
+
// What the app's extensions add to an app of this platform.
|
|
60
|
+
const extensionsOf = (platform) => extensionPart(extensionsInApp(platform, (message) => console.warn(`crossbind: ${message}.`)), platform);
|
|
61
|
+
|
|
62
|
+
// The App Group an iOS app shares with the targets of its extensions' that ask for one, or none; app.ios.appGroup is
|
|
63
|
+
// checked all the same.
|
|
64
|
+
function appGroupOf(platform, extensions) {
|
|
65
|
+
if (platform !== 'ios') return null;
|
|
66
|
+
const group = iosAppGroup(state.config);
|
|
67
|
+
return extensions.targets.some(({ appGroup }) => appGroup) ? group : null;
|
|
68
|
+
}
|
|
69
|
+
|
|
53
70
|
// Where an app keeps its executable and its files: a macOS bundle, a Linux or Windows directory, or the app folder of an
|
|
54
71
|
// iOS app's Xcode project or of an Android app's Gradle project, which link the executable themselves.
|
|
55
72
|
export function appLayout(target) {
|
|
@@ -123,24 +140,12 @@ export function appTeam() {
|
|
|
123
140
|
return team;
|
|
124
141
|
}
|
|
125
142
|
|
|
126
|
-
// An Android application id: dot-separated parts of letters, digits and underscores that each start with a letter.
|
|
127
|
-
const ANDROID_APP_ID = /^[A-Za-z][A-Za-z0-9_]*(\.[A-Za-z][A-Za-z0-9_]*)+$/;
|
|
128
|
-
|
|
129
|
-
// An Android app's id: the project's app.id, else one made from the project's name.
|
|
130
|
-
export function androidAppId() {
|
|
131
|
-
const id = state.config.app.id ?? `dev.crossbind.${state.config.general.name.replace(/[^A-Za-z0-9.]/g, '_')}`;
|
|
132
|
-
if (!ANDROID_APP_ID.test(id)) {
|
|
133
|
-
throw new Error(`crossbind: ${JSON.stringify(id)} (app.id, else made from the project's name) is no Android application id, which takes dot-separated parts of letters, digits and underscores that each start with a letter, as com.example.app does. Set app.id in crossbind.config.js.`);
|
|
134
|
-
}
|
|
135
|
-
return id;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
143
|
// Apple takes dot-separated integers alone as an app's version.
|
|
139
144
|
export const appVersion = () => (state.config.package?.version ?? '1.0.0').replace(/[-+].*$/, '');
|
|
140
145
|
|
|
141
146
|
const BUILD_NUMBER = 'CROSSBIND_APP_BUILD_NUMBER';
|
|
142
147
|
// Google Play takes no larger version code.
|
|
143
|
-
const MAX_VERSION_CODE = 2100000000;
|
|
148
|
+
export const MAX_VERSION_CODE = 2100000000;
|
|
144
149
|
|
|
145
150
|
// The number CI or a publish gives a build, which iOS takes as its build and Android as its version code:
|
|
146
151
|
// CROSSBIND_APP_BUILD_NUMBER, a whole number both stores take, else none.
|
|
@@ -204,11 +209,16 @@ async function bundle(input, file, plugins) {
|
|
|
204
209
|
await build.close();
|
|
205
210
|
}
|
|
206
211
|
|
|
207
|
-
// A development build claims no scheme: the built app, of the same id, owns them, and
|
|
212
|
+
// A development build claims no scheme, no file type and no user activity: the built app, of the same id, owns them, and
|
|
213
|
+
// a link it opens shows its own page.
|
|
208
214
|
const urlSchemesOf = (target) => (target.buildType === 'release' ? appUrlSchemes(state.config) : []);
|
|
215
|
+
const fileTypesOf = (target) => (target.buildType === 'release' ? fileTypeOwners(state.config) : []);
|
|
216
|
+
const activityTypesOf = (target) => (target.buildType === 'release' ? activityTypeOwners(state.config).map(({ type }) => type) : []);
|
|
209
217
|
|
|
210
|
-
|
|
218
|
+
// The app's Info.plist, with the keys its extensions give.
|
|
219
|
+
const infoPlist = (name, version, hasIcon, urlSchemes, fileTypes, activityTypes) => xmlPlist(mergedPlist({
|
|
211
220
|
CFBundleDisplayName: appDisplayName(state.config),
|
|
221
|
+
...(fileTypes.length > 0 ? { CFBundleDocumentTypes: macDocumentTypes(fileTypes) } : {}),
|
|
212
222
|
CFBundleExecutable: name,
|
|
213
223
|
// Contents/Resources/icon.icns.
|
|
214
224
|
...(hasIcon ? { CFBundleIconFile: 'icon' } : {}),
|
|
@@ -224,8 +234,12 @@ const infoPlist = (name, version, hasIcon, urlSchemes) => xmlPlist({
|
|
|
224
234
|
NSHighResolutionCapable: true,
|
|
225
235
|
// The app menu's About item shows it.
|
|
226
236
|
...(appCopyright(state.config) ? { NSHumanReadableCopyright: appCopyright(state.config) } : {}),
|
|
237
|
+
...(activityTypes.length > 0 ? { NSUserActivityTypes: activityTypes } : {}),
|
|
227
238
|
...usageDescriptions(state.config, 'darwin'),
|
|
228
|
-
});
|
|
239
|
+
}, extensionsOf('darwin').plist));
|
|
240
|
+
|
|
241
|
+
// The app's own files, as app.files lists them, by the project's folder.
|
|
242
|
+
const ownFiles = () => ({ root: state.config.paths.project, paths: appFiles(state.config) });
|
|
229
243
|
|
|
230
244
|
// The host's bytecode and the data the packages ship, beside the page's folder.
|
|
231
245
|
function copyAppFiles(dir, hbc, target) {
|
|
@@ -234,6 +248,7 @@ function copyAppFiles(dir, hbc, target) {
|
|
|
234
248
|
Object.entries(getData('data', target)).forEach(([source, dataName]) => {
|
|
235
249
|
if (fs.existsSync(source)) fs.cpSync(source, `${dir}/data/${dataName}`, { recursive: true });
|
|
236
250
|
});
|
|
251
|
+
copyCarriedFiles(dir, extensionsOf(target.platform).files, ownFiles());
|
|
237
252
|
}
|
|
238
253
|
|
|
239
254
|
// Everything but the page: the host and the app's files, its icon, and on macOS Hermes beside them. A Windows host
|
|
@@ -248,7 +263,7 @@ function assembleApp(target, { executable, hbc, hermes, icon }) {
|
|
|
248
263
|
copyAppFiles(`${app}/${layout.resources}`, hbc, target);
|
|
249
264
|
if (target.platform === 'linux' && icon) fs.writeFileSync(`${app}/${layout.resources}/icon.png`, linuxIcon(icon));
|
|
250
265
|
if (target.platform !== 'darwin') return;
|
|
251
|
-
fs.writeFileSync(`${app}/Contents/Info.plist`, infoPlist(name, appVersion(), Boolean(icon), urlSchemesOf(target)));
|
|
266
|
+
fs.writeFileSync(`${app}/Contents/Info.plist`, infoPlist(name, appVersion(), Boolean(icon), urlSchemesOf(target), fileTypesOf(target), activityTypesOf(target)));
|
|
252
267
|
if (icon) fs.writeFileSync(`${app}/Contents/Resources/icon.icns`, macIcon(icon));
|
|
253
268
|
const framework = `${app}/Contents/Frameworks/hermesvm.framework`;
|
|
254
269
|
fs.cpSync(`${hermes}/Library/Frameworks/macosx/hermesvm.framework`, framework, { recursive: true, verbatimSymlinks: true });
|
|
@@ -301,20 +316,10 @@ const appParts = (target) => state.targets
|
|
|
301
316
|
.filter((t) => t.platform === target.platform && t.runtimeEnv === 'app' && t.buildType === target.buildType && currentApps.has(t.appName))
|
|
302
317
|
.map((t) => ({ arch: t.arch, dir: `${state.config.paths.build}/${t.appName}` }));
|
|
303
318
|
|
|
304
|
-
//
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
assertUnderBase(app, target);
|
|
309
|
-
fs.rmSync(`${app}.zip`, { force: true });
|
|
310
|
-
run(null, ['zip', '-q', '-r', '-X', `${path.basename(app)}.zip`, path.basename(app)], null, target, { workdir: path.dirname(app) });
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
313
|
-
const result = spawnSync('tar', ['-czf', `${app}.tar.gz`, '-C', path.dirname(app), path.basename(app)], {
|
|
314
|
-
encoding: 'utf8',
|
|
315
|
-
env: { ...process.env, COPYFILE_DISABLE: '1' },
|
|
316
|
-
});
|
|
317
|
-
if (result.status !== 0) throw new Error(`crossbind: cannot archive ${app}: ${result.stderr || result.error?.message}`);
|
|
319
|
+
// The container that signs a Windows app sees the project's base alone.
|
|
320
|
+
function assertUnderBase(app, target) {
|
|
321
|
+
if (isUnderBase(app, state.config.paths.base)) return;
|
|
322
|
+
throw new Error(`crossbind: the Windows app ${app} is outside ${state.config.paths.base}, the project's base and all the ${imageRoleFor(target)} container sees. Build the app into a directory under it.`);
|
|
318
323
|
}
|
|
319
324
|
|
|
320
325
|
const ENTITLEMENTS = {
|
|
@@ -329,10 +334,12 @@ const ENTITLEMENTS = {
|
|
|
329
334
|
function signApp(app, target, signing) {
|
|
330
335
|
const sign = signing ? ['--sign', signing.identity, '--options', 'runtime', '--timestamp'] : ['--sign', '-', '--timestamp=none'];
|
|
331
336
|
run(null, ['codesign', '--force', ...sign, `${app}/Contents/Frameworks/hermesvm.framework`], null, target);
|
|
332
|
-
// The hardened runtime keeps the app from the devices of app.permissions unless its signature claims them
|
|
333
|
-
|
|
334
|
-
const
|
|
335
|
-
|
|
337
|
+
// The hardened runtime keeps the app from the devices of app.permissions unless its signature claims them, beside what
|
|
338
|
+
// its extensions claim.
|
|
339
|
+
const devices = Object.fromEntries(Object.keys(appPermissions(state.config)).map((name) => [ENTITLEMENTS[name], true]));
|
|
340
|
+
const claims = mergedEntitlements([['app.permissions', devices], ...extensionsOf('darwin').entitlements]);
|
|
341
|
+
const entitlements = Object.keys(claims).length > 0 ? `${state.config.paths.build}/${path.basename(app)}.entitlements` : null;
|
|
342
|
+
if (entitlements) fs.writeFileSync(entitlements, xmlPlist(claims));
|
|
336
343
|
run(null, ['codesign', '--force', ...sign, ...(entitlements ? ['--entitlements', entitlements] : []), app], null, target);
|
|
337
344
|
}
|
|
338
345
|
|
|
@@ -363,22 +370,52 @@ function warnUnreasonedApis(project, privacy) {
|
|
|
363
370
|
if (warning) console.warn(warning);
|
|
364
371
|
}
|
|
365
372
|
|
|
366
|
-
// Where publishApp last put this project's
|
|
367
|
-
//
|
|
373
|
+
// Where publishApp last put this project's apps, for `crossbind app publish`, which runs Vite and so cannot know the
|
|
374
|
+
// outDir it builds into: an iOS or Android app's project, and each arch's desktop app under its platform's name on the
|
|
375
|
+
// command line.
|
|
368
376
|
const appOutputsFile = () => `${state.config.paths.build}/app-outputs.json`;
|
|
369
377
|
const readAppOutputs = () => (fs.existsSync(appOutputsFile()) ? JSON.parse(fs.readFileSync(appOutputsFile(), 'utf8')) : {});
|
|
378
|
+
// What each desktop app's installers wrote beside it, as builds recorded them.
|
|
379
|
+
const shippedFiles = () => new Set(Object.values(readAppOutputs()).filter(Array.isArray).flat()
|
|
380
|
+
.flatMap(({ installers = [] }) => installers.flatMap(({ files }) => files)));
|
|
381
|
+
// The command line's names of the desktop platforms.
|
|
382
|
+
export const DESKTOP_PLATFORMS = { darwin: 'macos', linux: 'linux', win32: 'windows' };
|
|
383
|
+
|
|
384
|
+
// Forgets what the builds wrote, as a publish's own build writes it anew, but for the installers' files, which a folder the
|
|
385
|
+
// bundler kept holds still, for the page to leave out.
|
|
386
|
+
export function clearAppOutputs() {
|
|
387
|
+
const earlier = [...shippedFiles()];
|
|
388
|
+
if (earlier.length > 0) fs.writeFileSync(appOutputsFile(), JSON.stringify({ earlier: [{ installers: [{ files: earlier }] }] }));
|
|
389
|
+
else fs.rmSync(appOutputsFile(), { force: true });
|
|
390
|
+
}
|
|
370
391
|
|
|
371
|
-
|
|
372
|
-
|
|
392
|
+
// What a publisher's upload gets of the app the build wrote for a platform: a desktop platform's apps, one for each arch.
|
|
373
393
|
export function appOutputOf(platform) {
|
|
374
394
|
const output = readAppOutputs()[platform];
|
|
375
395
|
if (!output) throw new Error(`crossbind: the build wrote no ${platform} app, so there is nothing to publish.`);
|
|
376
|
-
return output;
|
|
396
|
+
return Object.values(DESKTOP_PLATFORMS).includes(platform) ? { apps: output } : output;
|
|
377
397
|
}
|
|
378
398
|
|
|
379
|
-
|
|
399
|
+
const madeFile = (file) => (fs.existsSync(file) ? file : null);
|
|
400
|
+
|
|
401
|
+
// What a publisher's upload takes of an app: an iOS app's project, an Android app's with its APK, bundle and native
|
|
402
|
+
// debug symbols where the build made them, and each arch's desktop app with its installers.
|
|
403
|
+
export function recordAppOutput(target, to, { installers = [] } = {}) {
|
|
404
|
+
const outputs = readAppOutputs();
|
|
405
|
+
const app = path.resolve(to);
|
|
406
|
+
const desktop = DESKTOP_PLATFORMS[target.platform];
|
|
407
|
+
const mobile = target.platform === 'android'
|
|
408
|
+
? { project: app, apk: madeFile(`${app}.apk`), bundle: madeFile(`${app}.aab`), symbols: madeFile(`${app}-symbols.zip`) }
|
|
409
|
+
: { project: app };
|
|
410
|
+
const recorded = desktop
|
|
411
|
+
? { [desktop]: [...(outputs[desktop] ?? []).filter((entry) => entry.app !== app), {
|
|
412
|
+
app,
|
|
413
|
+
arch: target.arch,
|
|
414
|
+
installers: installers.map(({ name, files }) => ({ name, files: files.map((file) => path.resolve(file)) })),
|
|
415
|
+
}] }
|
|
416
|
+
: { [target.platform]: mobile };
|
|
380
417
|
fs.mkdirSync(state.config.paths.build, { recursive: true });
|
|
381
|
-
fs.writeFileSync(appOutputsFile(), `${JSON.stringify({ ...
|
|
418
|
+
fs.writeFileSync(appOutputsFile(), `${JSON.stringify({ ...outputs, ...recorded }, null, 4)}\n`);
|
|
382
419
|
}
|
|
383
420
|
|
|
384
421
|
// Where a build without a bundler puts an app: under its own name, or for iOS and Android as the project of its build
|
|
@@ -396,19 +433,34 @@ export function publishApp(target, { to = appOutputPath(target), page = null } =
|
|
|
396
433
|
if (target.platform === 'ios') {
|
|
397
434
|
const parts = appParts(target).map(({ arch, dir }) => ({ sdk: arch, dir }));
|
|
398
435
|
const icon = readAppIcon(state.config);
|
|
399
|
-
const
|
|
436
|
+
const ownPrivacy = appPrivacy(state.config);
|
|
400
437
|
const build = appBuildNumber();
|
|
401
|
-
|
|
438
|
+
// The app's own options are checked first, then what its extensions add.
|
|
439
|
+
const options = {
|
|
402
440
|
parts, identity: { id: appId(state.config), team: appTeam() }, label: appDisplayName(state.config), version: appVersion(),
|
|
403
441
|
build: build === null ? appVersion() : String(build), icon: icon && iosIcon(icon), urlSchemes: appUrlSchemes(state.config),
|
|
404
|
-
|
|
442
|
+
fileTypes: fileTypeOwners(state.config), links: linkOwners(state.config).map(({ link }) => link),
|
|
443
|
+
activityTypes: activityTypeOwners(state.config).map(({ type }) => type), shortcutItems: shortcutItemOwners(state.config),
|
|
444
|
+
background: appBackgroundColor(state.config), usage: usageDescriptions(state.config, 'ios'), encryption: appEncryption(state.config),
|
|
445
|
+
multipleWindows: iosMultipleWindows(state.config),
|
|
446
|
+
};
|
|
447
|
+
const extensions = extensionsOf('ios');
|
|
448
|
+
const privacy = mergedPrivacy(ownPrivacy, extensions.privacy);
|
|
449
|
+
writeXcodeProject(to, {
|
|
450
|
+
...options, privacy, entitlements: mergedEntitlements(extensions.entitlements), plist: extensions.plist, targets: extensions.targets,
|
|
451
|
+
appGroup: appGroupOf('ios', extensions),
|
|
405
452
|
});
|
|
406
453
|
if (target.buildType === 'release') warnUnreasonedApis(to, privacy);
|
|
407
454
|
} else if (target.platform === 'android') {
|
|
408
455
|
const icon = readAppIcon(state.config);
|
|
409
|
-
|
|
410
|
-
parts: appParts(target), id: androidAppId(), label: appDisplayName(state.config), version: androidVersion(), icons: icon && androidIcons(icon),
|
|
456
|
+
const options = {
|
|
457
|
+
parts: appParts(target), id: androidAppId(state.config), label: appDisplayName(state.config), version: androidVersion(), icons: icon && androidIcons(icon),
|
|
411
458
|
urlSchemes: appUrlSchemes(state.config), background: appBackgroundColor(state.config), permissions: Object.keys(appPermissions(state.config)),
|
|
459
|
+
fileTypes: fileTypeOwners(state.config), links: linkOwners(state.config).map(({ link }) => link), shortcutItems: shortcutItemOwners(state.config),
|
|
460
|
+
};
|
|
461
|
+
const extensions = extensionsOf('android');
|
|
462
|
+
writeGradleProject(to, {
|
|
463
|
+
...options, java: extensions.java, extensionPermissions: extensions.permissions, manifests: extensions.manifests, resources: extensions.resources, maven: extensions.maven,
|
|
412
464
|
});
|
|
413
465
|
} else if (path.resolve(to) !== path.resolve(built)) {
|
|
414
466
|
fs.rmSync(to, { recursive: true, force: true });
|
|
@@ -416,11 +468,14 @@ export function publishApp(target, { to = appOutputPath(target), page = null } =
|
|
|
416
468
|
}
|
|
417
469
|
if (page) {
|
|
418
470
|
// The app may land inside the page's own directory, which it then leaves out, with every app built there and what
|
|
419
|
-
// packages it
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
471
|
+
// packages it: what is named after a target of the app, and every installer's files as a build recorded them, which
|
|
472
|
+
// a folder the bundler left as it was holds still.
|
|
473
|
+
const apps = state.targets.filter((t) => t.runtimeEnv === 'app')
|
|
474
|
+
.flatMap((t) => [appOutputName(t), `${state.config.general.name}-${t.platform}-${t.arch}`]).filter((name) => !name.endsWith('.app'));
|
|
475
|
+
const shipped = shippedFiles();
|
|
476
|
+
const isApp = (entry) => entry === path.basename(to) || entry.endsWith('.app')
|
|
477
|
+
|| apps.some((app) => entry === app || entry.startsWith(`${app}.`) || entry.startsWith(`${app}-`))
|
|
478
|
+
|| shipped.has(path.resolve(page, entry));
|
|
424
479
|
fs.readdirSync(page).filter((entry) => !isApp(entry)).forEach((entry) => {
|
|
425
480
|
fs.cpSync(`${page}/${entry}`, `${to}/${appLayout(target).resources}/page/${entry}`, { recursive: true });
|
|
426
481
|
});
|
|
@@ -432,17 +487,8 @@ export function publishApp(target, { to = appOutputPath(target), page = null } =
|
|
|
432
487
|
} else if (target.platform === 'android' && target.buildType === 'release') {
|
|
433
488
|
packageAndroidRelease(to);
|
|
434
489
|
}
|
|
435
|
-
if (['ios', 'android'].includes(target.platform))
|
|
436
|
-
|
|
437
|
-
} else if (target.platform !== 'darwin') {
|
|
438
|
-
if (target.platform === 'win32') signWindowsApp(to, target, page);
|
|
439
|
-
archiveApp(to, target);
|
|
440
|
-
}
|
|
441
|
-
// A desktop app with its page ships with what installs it, and with an updater's key with its update too.
|
|
442
|
-
if (page && ['darwin', 'linux', 'win32'].includes(target.platform)) {
|
|
443
|
-
writeInstaller(to, target);
|
|
444
|
-
writeUpdate(to, target);
|
|
445
|
-
}
|
|
490
|
+
if (['ios', 'android'].includes(target.platform)) recordAppOutput(target, to);
|
|
491
|
+
else if (target.platform === 'win32') signWindowsApp(to, target, page);
|
|
446
492
|
return to;
|
|
447
493
|
}
|
|
448
494
|
|
|
@@ -457,14 +503,32 @@ export default async function buildApp(target, { bridges = [], force = false } =
|
|
|
457
503
|
logger.info(`[${target.path}] app skipped (cargo package - staticlib only)`);
|
|
458
504
|
return false;
|
|
459
505
|
}
|
|
460
|
-
//
|
|
461
|
-
// app section stops the build before anything compiles.
|
|
462
|
-
const header = appHeader(state.config, target.platform);
|
|
506
|
+
// A desktop host's title and window, a Windows one's version, the app's icon and its extensions with their options, as
|
|
507
|
+
// where the page opens files: a bad app section stops the build before anything compiles.
|
|
463
508
|
const icon = readAppIcon(state.config);
|
|
509
|
+
const extensions = extensionsOf(target.platform);
|
|
510
|
+
const header = appHeader(state.config, target.platform, appGroupOf(target.platform, extensions));
|
|
511
|
+
const carried = carriedFilesOf(extensions.files, ownFiles());
|
|
512
|
+
const carriedPaths = new Set(carried);
|
|
513
|
+
// Whether the extension that owns a launch has native code, or for the app's own one that holds the role.
|
|
514
|
+
const hasNative = (extension, role) => extensions.native.some(({ name, roles }) => (extension === null ? roles.includes(role) : name === extension));
|
|
515
|
+
// A desktop's system hands an app no https link: its owners there are those with native code, whose onOpenUrl a
|
|
516
|
+
// phone's code may share.
|
|
517
|
+
const isPhone = ['ios', 'android'].includes(target.platform);
|
|
518
|
+
const links = linkOwners(state.config).filter(({ extension }) => isPhone || hasNative(extension, 'links'));
|
|
519
|
+
// Another system continues no user activity: its owners there are those with native code, whose onUserActivity
|
|
520
|
+
// Apple's code may share.
|
|
521
|
+
const isApple = ['darwin', 'ios'].includes(target.platform);
|
|
522
|
+
const activities = activityTypeOwners(state.config).filter(({ extension }) => isApple || hasNative(extension, 'activities'));
|
|
523
|
+
// A desktop has no quick actions either.
|
|
524
|
+
const shortcuts = shortcutItemOwners(state.config).filter(({ extension }) => isPhone || hasNative(extension, 'shortcuts'));
|
|
525
|
+
const registration = registrationSource(extensions.native, urlSchemeOwners(state.config), fileTypeOwners(state.config), links, activities, shortcuts);
|
|
464
526
|
|
|
465
527
|
const buildType = target.buildType === 'release' ? 'Release' : 'Debug';
|
|
466
528
|
const { build } = state.config.paths;
|
|
467
529
|
const appHostRoot = resolveAppHostRoot();
|
|
530
|
+
appExtensionsOf(state.config.extensions).filter(({ replaces }) => replaces)
|
|
531
|
+
.forEach(({ name, root, replaces }) => logger.info(`[${target.path}] the extension ${name} of ${root} takes the host's ${replaces.join(', ')}`));
|
|
468
532
|
const jsiRoot = resolveAppEmbindJsiRoot();
|
|
469
533
|
const { hermes, cmakeArgs, inputs } = await hostInputs(target);
|
|
470
534
|
|
|
@@ -480,6 +544,9 @@ export default async function buildApp(target, { bridges = [], force = false } =
|
|
|
480
544
|
});
|
|
481
545
|
const { libs, linkArgs, extraSources } = linkInputs(target, { bridge: BRIDGE });
|
|
482
546
|
const sharedLibs = libs.filter((lib) => lib.endsWith('.so'));
|
|
547
|
+
// The extensions' sources compile with the host, which links what they need: a framework on macOS, a library elsewhere.
|
|
548
|
+
// An iOS host is a static library, whose frameworks the app's Xcode project links.
|
|
549
|
+
const hostLinkArgs = [...linkArgs, ...(target.platform === 'darwin' ? extensions.frameworks.map((framework) => `-framework ${framework}`) : extensions.libraries)];
|
|
483
550
|
|
|
484
551
|
const fingerprintFile = `${build}/${target.appName}.fingerprint`;
|
|
485
552
|
const fingerprint = getContentHash(JSON.stringify({
|
|
@@ -488,7 +555,8 @@ export default async function buildApp(target, { bridges = [], force = false } =
|
|
|
488
555
|
// A desktop app carries its icon; an iOS or Android one gets it as its project is written.
|
|
489
556
|
icon: ['ios', 'android'].includes(target.platform) ? null : icon?.hash ?? null,
|
|
490
557
|
// A macOS app's bundle takes its id, name and version from it.
|
|
491
|
-
infoPlist: target.platform === 'darwin'
|
|
558
|
+
infoPlist: target.platform === 'darwin'
|
|
559
|
+
? infoPlist(state.config.general.name, appVersion(), Boolean(icon), urlSchemesOf(target), fileTypesOf(target), activityTypesOf(target)) : null,
|
|
492
560
|
hermes: HERMES.version,
|
|
493
561
|
inputs,
|
|
494
562
|
linkArgs,
|
|
@@ -498,12 +566,25 @@ export default async function buildApp(target, { bridges = [], force = false } =
|
|
|
498
566
|
}),
|
|
499
567
|
env: getEnv(target),
|
|
500
568
|
data: getData('data', target),
|
|
569
|
+
// What the app carries, by its size and time, as a large model would take long to read at each build.
|
|
570
|
+
carried: carried.map((file) => {
|
|
571
|
+
const stat = fs.statSync(file);
|
|
572
|
+
return { file, size: stat.size, mtimeMs: stat.mtimeMs };
|
|
573
|
+
}),
|
|
501
574
|
version: state.config.package?.version,
|
|
502
575
|
runtime: getFilesFingerprint(filesUnder([
|
|
503
576
|
`${appHostRoot}/cpp`, `${appHostRoot}/js`, `${appHostRoot}/third_party`, `${jsiRoot}/cpp/src`, `${jsiRoot}/js`,
|
|
504
577
|
`${state.config.paths.cli}/assets/js-runtime/adapters`,
|
|
505
578
|
])),
|
|
506
579
|
extraSources: getFilesFingerprint(extraSources),
|
|
580
|
+
// An iOS app's frameworks reach its Xcode project through what the host's build writes.
|
|
581
|
+
extensions: {
|
|
582
|
+
registration,
|
|
583
|
+
files: getFilesFingerprint(filesUnder(extensions.roots).filter((file) => !carriedPaths.has(path.resolve(file)))),
|
|
584
|
+
compiled: extensions.compiled,
|
|
585
|
+
link: hostLinkArgs.slice(linkArgs.length),
|
|
586
|
+
frameworks: extensions.frameworks,
|
|
587
|
+
},
|
|
507
588
|
}));
|
|
508
589
|
const isChanged = !fs.existsSync(fingerprintFile) || fs.readFileSync(fingerprintFile, { encoding: 'utf8' }) !== fingerprint;
|
|
509
590
|
if (!force && !isChanged && fs.existsSync(`${build}/${target.appName}`) && fs.existsSync(`${build}/${target.appJsName}`)) {
|
|
@@ -521,11 +602,25 @@ export default async function buildApp(target, { bridges = [], force = false } =
|
|
|
521
602
|
resetCMakeCacheForSource(workDir, `${appHostRoot}/cpp`, target);
|
|
522
603
|
// The host includes it from its build directory; written only when it changed, it recompiles nothing otherwise.
|
|
523
604
|
writeIfChanged(`${workDir}/crossbind_app.h`, header);
|
|
605
|
+
writeIfChanged(`${workDir}/extensions.cpp`, registration);
|
|
524
606
|
// A Windows host's executable carries the app's icon, which its resource script takes from beside the header.
|
|
525
607
|
if (target.platform === 'win32') {
|
|
526
608
|
if (icon) writeIfChanged(`${workDir}/icon.ico`, windowsIcon(icon));
|
|
527
609
|
else fs.rmSync(`${workDir}/icon.ico`, { force: true });
|
|
528
610
|
}
|
|
611
|
+
// An Apple app's Swift, which CMake's Makefiles take none of: each extension's compiles first, its header joins the
|
|
612
|
+
// extension's includes, and its library the host's link, or an iOS app's Xcode project's.
|
|
613
|
+
const swift = ['darwin', 'ios'].includes(target.platform) ? compileSwift(target, extensions.compiled, workDir, buildType === 'Release') : [];
|
|
614
|
+
const swiftLink = swiftLinkArgs(target, swift.map(({ library }) => library));
|
|
615
|
+
// A Linux app's extensions' packages beside crossbind's sysroot, each extension's in a sysroot of its own, whose
|
|
616
|
+
// headers its sources include and whose libraries the host links against.
|
|
617
|
+
const sysroots = target.platform === 'linux' ? await unpackPackages(target, extensions.compiled, {
|
|
618
|
+
cache: `${build}/linux-packages`, workDir, unpack: (deb, root) => run(null, ['dpkg-deb', '-x', deb, root], platformPrefix, target),
|
|
619
|
+
}) : [];
|
|
620
|
+
const compiled = extensions.compiled.map((part) => ({
|
|
621
|
+
...part, includes: [...part.includes, ...[...swift, ...sysroots].filter(({ name: owner }) => owner === part.name).flatMap(({ includes }) => includes)],
|
|
622
|
+
}));
|
|
623
|
+
const ownLink = target.platform === 'darwin' ? swiftLink : sysroots.flatMap(({ libDir }) => [`-L${libDir}`, `-Wl,-rpath-link,${libDir}`]);
|
|
529
624
|
run(null, [
|
|
530
625
|
// An iOS host builds with crossbind's iOS toolchain file rather than as an Xcode project of its own.
|
|
531
626
|
target.platform === 'ios' ? 'ios-cmake' : 'cmake', `${appHostRoot}/cpp`,
|
|
@@ -534,7 +629,9 @@ export default async function buildApp(target, { bridges = [], force = false } =
|
|
|
534
629
|
`-DCROSSBIND_JSI_ROOT=${jsiRoot}`,
|
|
535
630
|
`-DCROSSBIND_HERMES=${hermes}`,
|
|
536
631
|
`-DCROSSBIND_EXTRA_SOURCES=${extraSources.join(';')}`,
|
|
537
|
-
`-
|
|
632
|
+
`-DCROSSBIND_EXTENSION_REGISTRATION=${workDir}/extensions.cpp`,
|
|
633
|
+
...extensionCmakeArgs(compiled),
|
|
634
|
+
`-DCROSSBIND_LINK_ARGS=${[...hostLinkArgs, ...ownLink].join(';')}`,
|
|
538
635
|
`-DCROSSBIND_LINK_DEPENDS=${libs.join(';')}`,
|
|
539
636
|
// An Android release ships the packages' shared libraries stripped as well, and keeps them as they come.
|
|
540
637
|
...(target.platform === 'android' ? [`-DCROSSBIND_SHARED_LIBS=${sharedLibs.join(';')}`] : []),
|
|
@@ -552,7 +649,8 @@ export default async function buildApp(target, { bridges = [], force = false } =
|
|
|
552
649
|
platformPrefix, target);
|
|
553
650
|
await bundle(`${appHostRoot}/js/page.js`, `${build}/${target.appJsName}`, []);
|
|
554
651
|
if (target.platform === 'ios') {
|
|
555
|
-
|
|
652
|
+
const frameworks = extensions.frameworks.flatMap((framework) => ['-framework', framework]);
|
|
653
|
+
assembleIosPart(target, { library: `${workDir}/lib${name}.a`, linkArgs: [...linkArgs, ...frameworks, ...swiftLink], hbc: `${workDir}/host.hbc`, hermes });
|
|
556
654
|
} else if (target.platform === 'android') {
|
|
557
655
|
assembleAndroidPart(target, { libDir: workDir, sharedLibs, hbc: `${workDir}/host.hbc` });
|
|
558
656
|
} else {
|
package/src/actions/buildNode.js
CHANGED
|
@@ -24,11 +24,16 @@ import toolchainNoticesDir from '../utils/toolchainNotices.js';
|
|
|
24
24
|
const cpuCount = Math.max(1, os.cpus().length - 1);
|
|
25
25
|
const WINDOWS_IMAGE_NOTICES = '/opt/licenses/llvm-mingw';
|
|
26
26
|
|
|
27
|
+
// What a build's output, a package's own packages and a repository's history hold, which no build reads.
|
|
28
|
+
const UNREAD_FOLDERS = ['.crossbind', 'node_modules', '.git'];
|
|
29
|
+
|
|
30
|
+
// The files under these folders a build reads, a link that leads nowhere left out.
|
|
27
31
|
export function filesUnder(dirs) {
|
|
28
32
|
return dirs.flatMap((dir) => (fs.existsSync(dir)
|
|
29
33
|
? fs.readdirSync(dir, { recursive: true })
|
|
34
|
+
.filter((file) => !file.split(/[\\/]/).some((part) => UNREAD_FOLDERS.includes(part)))
|
|
30
35
|
.map((file) => `${dir}/${file}`)
|
|
31
|
-
.filter((file) => fs.statSync(file)
|
|
36
|
+
.filter((file) => fs.statSync(file, { throwIfNoEntry: false })?.isFile())
|
|
32
37
|
: []));
|
|
33
38
|
}
|
|
34
39
|
|
package/src/actions/buildWasm.js
CHANGED
|
@@ -6,7 +6,6 @@ import getLinkInputs from './getLinkInputs.js';
|
|
|
6
6
|
import getData from './getData.js';
|
|
7
7
|
import getEnv from './getEnv.js';
|
|
8
8
|
import buildJs from './buildJs.js';
|
|
9
|
-
import triggerExtensions from './extensions.js';
|
|
10
9
|
import state from '../state/index.js';
|
|
11
10
|
import resolveEmbindRustRoot from '../utils/resolveEmbindRust.js';
|
|
12
11
|
import logger from '../utils/logger.js';
|
|
@@ -128,8 +127,6 @@ export default async function buildWasm(target, options = {}) {
|
|
|
128
127
|
if (!isProd && !/-s\s*STACK_OVERFLOW_CHECK=/.test(set)) emccFlags.push('-sSTACK_OVERFLOW_CHECK=1');
|
|
129
128
|
}
|
|
130
129
|
|
|
131
|
-
triggerExtensions('buildWasm', 'beforeBuild', [emccFlags]);
|
|
132
|
-
|
|
133
130
|
if (target.runtime === 'mt' && !emccFlags.includes('-pthread')) {
|
|
134
131
|
emccFlags.push('-pthread');
|
|
135
132
|
emccFlags.push('-sPTHREAD_POOL_SIZE=Math.min(navigator.hardwareConcurrency || 1, 2)');
|
|
@@ -203,8 +200,6 @@ export default async function buildWasm(target, options = {}) {
|
|
|
203
200
|
logger.startStep(target, 'wasm');
|
|
204
201
|
const t0 = performance.now();
|
|
205
202
|
|
|
206
|
-
triggerExtensions('buildWasm', 'beforeBuildBrowser', [emccFlags]);
|
|
207
|
-
|
|
208
203
|
const data = Object.entries(getData('data', target)).map(([key, value]) => ['--preload-file', `${key.replaceAll('@', '@@')}@/crossbind/${value}`]).flat();
|
|
209
204
|
run('em++', [
|
|
210
205
|
'-lembind',
|
|
@@ -260,8 +255,6 @@ export default async function buildWasm(target, options = {}) {
|
|
|
260
255
|
logger.startStep(target, 'wasm');
|
|
261
256
|
const t0 = performance.now();
|
|
262
257
|
|
|
263
|
-
triggerExtensions('buildWasm', 'beforeBuildEdge', [emccFlags]);
|
|
264
|
-
|
|
265
258
|
const data = Object.entries(getData('data', target)).map(([key, value]) => ['--preload-file', `${key.replaceAll('@', '@@')}@/crossbind/${value}`]).flat();
|
|
266
259
|
run('em++', [
|
|
267
260
|
'-lembind',
|
|
@@ -300,8 +293,6 @@ export default async function buildWasm(target, options = {}) {
|
|
|
300
293
|
if (target.runtimeEnv === 'node') {
|
|
301
294
|
logger.startStep(target, 'wasm');
|
|
302
295
|
|
|
303
|
-
triggerExtensions('buildWasm', 'beforeBuildNodeJS', [emccFlags]);
|
|
304
|
-
|
|
305
296
|
run('em++', [
|
|
306
297
|
'-lembind',
|
|
307
298
|
// The config's emccFlags follow the default level, so its -Oz or -Os wins (the last -O does).
|
|
@@ -24,6 +24,9 @@ import { withDirLockSync } from '../utils/dirLock.js';
|
|
|
24
24
|
import { conanImportOfHeader } from '../utils/conanImport.js';
|
|
25
25
|
import run, { cxxPreprocessorFor } from './run.js';
|
|
26
26
|
import isSourceCmakePackage from '../utils/isSourceCmakePackage.js';
|
|
27
|
+
import {
|
|
28
|
+
loadBridgeTools, runPreprocessor, runSwig, usesBridgeTools,
|
|
29
|
+
} from '../utils/bridgeTools.js';
|
|
27
30
|
|
|
28
31
|
// Part of every interface hash, so interfaces cached by an older generator are rebuilt.
|
|
29
32
|
const INTERFACE_FORMAT = 'swig-macros-4';
|
|
@@ -54,6 +57,8 @@ function bindHeader(headerOrModuleFilePath, target, { withDependencies = true, w
|
|
|
54
57
|
// dependency built since.
|
|
55
58
|
refreshConanDependencies(state.config);
|
|
56
59
|
refreshBuiltDependencies(state.config);
|
|
60
|
+
// Without bridge-tools on a Mac the macro step would fail quietly, and its interface would be kept without macros.
|
|
61
|
+
if (usesBridgeTools(target)) loadBridgeTools();
|
|
57
62
|
const interfaceFilePath = upath.resolve(headerOrModuleFilePath);
|
|
58
63
|
if (!fs.existsSync(`${state.config.paths.build}/interface`)) {
|
|
59
64
|
fs.mkdirSync(`${state.config.paths.build}/interface`, { recursive: true });
|
|
@@ -353,21 +358,25 @@ const RELEASE_DEFINE = '-DNDEBUG';
|
|
|
353
358
|
|
|
354
359
|
// One bridge serves every desktop target, so SWIG and the macro table it reads come from the web image's em++,
|
|
355
360
|
// which defines no operating system; an android bridge is read with the NDK it compiles with. The headers
|
|
356
|
-
// still come from the target's own packages.
|
|
361
|
+
// still come from the target's own packages. On a Mac, bridge-tools makes the same bridge, in the build directory the
|
|
362
|
+
// image's tools run in.
|
|
357
363
|
const toolTargetFor = (target) => (target?.platform === 'android' ? target : { ...target, platform: 'wasm' });
|
|
358
364
|
|
|
359
365
|
function dumpMacros(outputFile, includes, includePath, target, defines = []) {
|
|
360
|
-
const
|
|
361
|
-
run(cxxPreprocessorFor(tool), [
|
|
366
|
+
const args = [
|
|
362
367
|
'-x', 'c++', '-std=c++17', '-dM', '-E', ...defines,
|
|
363
368
|
...includePath,
|
|
364
369
|
...includes.flatMap((header) => ['-include', header]),
|
|
365
370
|
'-o', outputFile,
|
|
366
371
|
'/dev/null',
|
|
367
|
-
]
|
|
372
|
+
];
|
|
373
|
+
if (usesBridgeTools(target)) runPreprocessor(args, state.config.paths.build);
|
|
374
|
+
else run(cxxPreprocessorFor(toolTargetFor(target)), args, null, toolTargetFor(target));
|
|
368
375
|
return parseMacroDump(fs.readFileSync(outputFile, 'utf8'));
|
|
369
376
|
}
|
|
370
377
|
|
|
378
|
+
const runSwigFor = (args, target) => (usesBridgeTools(target) ? runSwig(args, state.config.paths.build) : run('swig', args, null, toolTargetFor(target)));
|
|
379
|
+
|
|
371
380
|
function swigIncludePath(target, sourceDir) {
|
|
372
381
|
const allHeaders = state.config.dependencyParameters.headerPathWithDepends.split(';');
|
|
373
382
|
const includePath = [
|
|
@@ -468,7 +477,7 @@ function createBridgeFileFromInterfaceFile(interfaceFilePath, target, sourceDir
|
|
|
468
477
|
const bridgeFilePath = `${state.config.paths.build}/bridge/${interfaceFilePath.split('/').at(-1)}.cpp`;
|
|
469
478
|
fs.writeFileSync(keyOf(bridgeFilePath), '');
|
|
470
479
|
// #error lines guard branches SWIG evaluates without the compiler's predefined macros, so they only warn.
|
|
471
|
-
const swig = () =>
|
|
480
|
+
const swig = () => runSwigFor([
|
|
472
481
|
'-c++',
|
|
473
482
|
'-embind',
|
|
474
483
|
'-cpperraswarn',
|
|
@@ -476,7 +485,7 @@ function createBridgeFileFromInterfaceFile(interfaceFilePath, target, sourceDir
|
|
|
476
485
|
...(swigView ? [`-I${swigView.dir}`] : []),
|
|
477
486
|
...swigIncludePath(target, sourceDir),
|
|
478
487
|
interfaceFilePath,
|
|
479
|
-
],
|
|
488
|
+
], target);
|
|
480
489
|
try {
|
|
481
490
|
swig();
|
|
482
491
|
} catch (e) {
|
|
@@ -517,8 +526,8 @@ function createConanDeclarations(interfaceFile, target, sourceDir, sourceHash, s
|
|
|
517
526
|
const hash = getContentHash([BRIDGE_FORMAT, getFileHash(file), sourceHash, swigView?.hash ?? ''].join('\n'));
|
|
518
527
|
if (!fs.existsSync(`${bridge}.exports.json`) || !fs.existsSync(keyOf(bridge)) || fs.readFileSync(keyOf(bridge), 'utf8') !== hash) {
|
|
519
528
|
fs.writeFileSync(keyOf(bridge), '');
|
|
520
|
-
|
|
521
|
-
...(swigView ? [`-I${swigView.dir}`] : []), ...swigIncludePath(target, sourceDir), file],
|
|
529
|
+
runSwigFor(['-c++', '-embind', '-cpperraswarn', '-o', bridge,
|
|
530
|
+
...(swigView ? [`-I${swigView.dir}`] : []), ...swigIncludePath(target, sourceDir), file], target);
|
|
522
531
|
fs.writeFileSync(keyOf(bridge), hash);
|
|
523
532
|
}
|
|
524
533
|
return `${bridge}.exports.json`;
|
package/src/actions/createLib.js
CHANGED
|
@@ -6,7 +6,6 @@ import run from './run.js';
|
|
|
6
6
|
import buildCargo from './buildCargo.js';
|
|
7
7
|
import { cargoTripleFor } from '../utils/cargoTarget.js';
|
|
8
8
|
import getCmakeParameters from './getCmakeParameters.js';
|
|
9
|
-
import triggerExtensions from './extensions.js';
|
|
10
9
|
import state from '../state/index.js';
|
|
11
10
|
import logger from '../utils/logger.js';
|
|
12
11
|
import { WASI_EMULATION_LIBS, WASI_LINK_LIBS, wasiCFlags, wasiCxxFlags } from '../utils/wasiToolchain.js';
|
|
@@ -132,7 +131,6 @@ export default function createLib(target, fileType, options = {}) {
|
|
|
132
131
|
|
|
133
132
|
const extraLibs = getExtraLibs ? getExtraLibs(target) : [];
|
|
134
133
|
|
|
135
|
-
triggerExtensions('createLib', 'setFlagWithBuildConfig', [buildEnv, cFlags, ldFlags]);
|
|
136
134
|
const archiveFlags = targetArchiveFlags(target);
|
|
137
135
|
cFlags.push(...archiveFlags);
|
|
138
136
|
ldFlags.push(...archiveFlags);
|
|
@@ -165,8 +163,6 @@ export default function createLib(target, fileType, options = {}) {
|
|
|
165
163
|
];
|
|
166
164
|
buildParams = getCmakeParameters(target, { ...options, nativeGlob, headerDirs });
|
|
167
165
|
|
|
168
|
-
triggerExtensions('createLib', 'setFlagWithoutBuildConfig', [buildEnv]);
|
|
169
|
-
|
|
170
166
|
const archiveFlags = targetArchiveFlags(target).join(' ');
|
|
171
167
|
if (archiveFlags) {
|
|
172
168
|
buildEnv.params.push('-e', `CFLAGS=${archiveFlags}`);
|