crossbind 2.0.0-beta.68 → 2.0.0-beta.72
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 +70 -59
- package/src/actions/addExtension.js +196 -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 +177 -74
- package/src/actions/buildDependencies.js +3 -3
- package/src/actions/buildNode.js +6 -1
- package/src/actions/buildWasm.js +0 -9
- package/src/actions/createImportedBridges.js +10 -8
- package/src/actions/createInterface.js +40 -29
- package/src/actions/createLib.js +3 -7
- package/src/actions/extensionApi.js +298 -0
- package/src/actions/extensionCommands.js +41 -0
- package/src/actions/extensionsInApp.js +19 -0
- package/src/actions/getAllBridges.js +20 -5
- package/src/actions/getDependLibs.js +5 -0
- package/src/actions/getLinkInputs.js +2 -1
- package/src/actions/gradleProject.js +207 -16
- package/src/actions/iosDevice.js +2 -2
- package/src/actions/iosSimulator.js +3 -3
- package/src/actions/licenses.js +113 -58
- package/src/actions/linuxPackages.js +48 -0
- package/src/actions/mavenVerification.js +37 -0
- package/src/actions/{prepareConanDependencies.js → preparePackageSources.js} +13 -12
- package/src/actions/publish.js +220 -0
- package/src/actions/windowsSigning.js +1 -1
- package/src/actions/writeRuntimeEntry.js +2 -2
- package/src/actions/xcodeProject.js +60 -29
- package/src/actions/xcodeTargets.js +122 -0
- package/src/actions/xcodebuild.js +65 -0
- package/src/app/index.d.ts +144 -132
- package/src/app/index.js +147 -185
- package/src/assets/configure/install.sh +0 -0
- package/src/assets/node-import-hooks.mjs +7 -6
- package/src/assets/toolchain-digests.json +20 -20
- package/src/bin.js +37 -37
- package/src/index.js +4 -3
- package/src/integration/getCrossbindScript.js +3 -2
- package/src/integration/getDependFilePath.js +10 -10
- package/src/program.js +32 -3
- package/src/state/{attachConanDependencies.js → attachPackageSources.js} +20 -16
- package/src/state/index.js +8 -6
- package/src/state/loadConfig.js +26 -9
- package/src/state/refreshPackageSources.js +19 -0
- package/src/utils/appExtensions.js +777 -0
- package/src/utils/appFiles.js +58 -0
- package/src/utils/appLaunches.js +249 -0
- package/src/utils/appOptions.js +142 -112
- package/src/utils/appRustCrates.js +2 -2
- package/src/utils/appTargets.js +168 -0
- package/src/utils/bridgeTools.js +71 -0
- package/src/utils/configChanges.js +30 -0
- package/src/utils/configWriter.js +143 -26
- package/src/utils/cppDts.js +11 -11
- package/src/utils/extensionSteps.js +172 -0
- package/src/utils/nativeImports.js +9 -2
- package/src/utils/nodeDevBuild.js +2 -1
- package/src/utils/openUrl.js +2 -1
- package/src/utils/packageSourceApi.js +87 -0
- package/src/utils/packageSourceImport.js +69 -0
- package/src/utils/packageSourceInstall.js +162 -0
- package/src/utils/{conanStage.js → packageSourceStage.js} +64 -90
- package/src/utils/packageSources.js +108 -0
- package/src/utils/plist.js +5 -0
- package/src/utils/printableText.js +5 -0
- package/src/utils/resolveAppHost.js +7 -0
- package/src/utils/runPackageSource.js +251 -0
- package/src/utils/rustBridgeGen.js +3 -3
- package/src/utils/systemConfig.js +16 -3
- package/src/utils/targetToolchain.js +77 -0
- 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/state/refreshConanDependencies.js +0 -17
- package/src/utils/conanDependencies.js +0 -66
- package/src/utils/conanImport.js +0 -58
- package/src/utils/conanInstall.js +0 -154
- package/src/utils/conanProfile.js +0 -203
- package/src/utils/runConan.js +0 -257
|
@@ -1,177 +1,93 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
-
import os from 'node:os';
|
|
3
2
|
import path from 'node:path';
|
|
4
|
-
import
|
|
3
|
+
import extensionApi from './extensionApi.js';
|
|
5
4
|
import { appleSigning } from './appleSigning.js';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
5
|
+
import { DESKTOP_PLATFORMS, recordAppOutput } from './buildApp.js';
|
|
6
|
+
import { windowsSigning } from './windowsSigning.js';
|
|
8
7
|
import state from '../state/index.js';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
8
|
+
import { hasTerminal } from '../utils/ask.js';
|
|
9
|
+
import { appInstallers } from '../utils/appOptions.js';
|
|
10
|
+
import {
|
|
11
|
+
extensionStep, ownExtensions, withListed, withoutNamed,
|
|
12
|
+
} from '../utils/appExtensions.js';
|
|
13
13
|
import resolveAppHostRoot from '../utils/resolveAppHost.js';
|
|
14
14
|
|
|
15
|
-
const
|
|
16
|
-
// What a Linux app runs on: WebKitGTK 4.1 from its 2.40 release, and the GTK its window is.
|
|
17
|
-
const DEBIAN_DEPENDS = 'libwebkit2gtk-4.1-0 (>= 2.40), libgtk-3-0';
|
|
15
|
+
const listed = (names) => (names.length > 1 ? `${names.slice(0, -1).join(', ')} and ${names.at(-1)}` : names[0]);
|
|
18
16
|
|
|
19
|
-
|
|
17
|
+
// crossbind's own installers, which the host brings as it brings its other extensions.
|
|
18
|
+
export const builtInInstallers = () => withoutNamed(ownExtensions(resolveAppHostRoot()), state.config?.app).filter(({ installer }) => installer);
|
|
20
19
|
|
|
21
|
-
// The
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
20
|
+
// The installers an app has: crossbind's own, but for those whose role the app's extensions take, each in the place of the
|
|
21
|
+
// app's extension of its name that has an installer, then those of the app's other extensions.
|
|
22
|
+
export function installersOf(extensions) {
|
|
23
|
+
const taken = extensions.flatMap(({ replaces }) => replaces ?? []);
|
|
24
|
+
return withListed(builtInInstallers().filter(({ name }) => !taken.includes(name)), extensions.filter((extension) => extension.installer));
|
|
26
25
|
}
|
|
27
26
|
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
export function
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
|
|
27
|
+
// The installers of the target's platform that make what installs its app: every one, or those app.installers names,
|
|
28
|
+
// which names none that is no installer, and those that run last whatever it names.
|
|
29
|
+
export function installersFor(target) {
|
|
30
|
+
const all = installersOf(state.config.extensions ?? []);
|
|
31
|
+
const named = appInstallers(state.config);
|
|
32
|
+
const unknown = named?.find((name) => !all.some((extension) => extension.name === name));
|
|
33
|
+
if (unknown) throw new Error(`crossbind: app.installers names ${unknown}, which is no installer: ${listed(all.filter(({ installer }) => !installer.isLast).map(({ name }) => name))} are.`);
|
|
34
|
+
const platform = DESKTOP_PLATFORMS[target.platform];
|
|
35
|
+
const taken = all.filter(({ name, installer }) => installer.platforms.includes(platform) && (!named || named.includes(name) || installer.isLast));
|
|
36
|
+
return [...taken.filter(({ installer }) => !installer.isLast), ...taken.filter(({ installer }) => installer.isLast)];
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
export const debianVersion = (version) => version.replace('-', '~');
|
|
40
|
-
|
|
41
|
-
// package.json's author as Debian names a maintainer, by name and email address.
|
|
42
|
-
export function maintainer(author) {
|
|
43
|
-
if (typeof author === 'string') return author.replace(/\(.*\)/, '').trim() || null;
|
|
44
|
-
if (!author?.name) return null;
|
|
45
|
-
return author.email ? `${author.name} <${author.email}>` : author.name;
|
|
46
|
-
}
|
|
39
|
+
const apiOf = (name, target) => extensionApi(name, { platform: DESKTOP_PLATFORMS[target.platform], isGuided: hasTerminal(), target });
|
|
47
40
|
|
|
48
|
-
// The
|
|
49
|
-
|
|
50
|
-
export function debianControl({ name, version, arch, author, description, label }) {
|
|
51
|
-
return [
|
|
52
|
-
`Package: ${name}`,
|
|
53
|
-
`Version: ${debianVersion(version)}`,
|
|
54
|
-
`Architecture: ${DEBIAN_ARCH[arch]}`,
|
|
55
|
-
`Maintainer: ${maintainer(author) ?? label}`,
|
|
56
|
-
`Depends: ${DEBIAN_DEPENDS}`,
|
|
57
|
-
`Description: ${(description || label).replace(/\s+/g, ' ').trim()}`,
|
|
58
|
-
'',
|
|
59
|
-
].join('\n');
|
|
60
|
-
}
|
|
41
|
+
// The installers an extension replaces, told once a run, which checks them for each of its targets.
|
|
42
|
+
const toldReplacing = new Set();
|
|
61
43
|
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const image = app.replace(/\.app$/, '.dmg');
|
|
79
|
-
const folder = fs.mkdtempSync(path.join(os.tmpdir(), 'crossbind-dmg-'));
|
|
80
|
-
try {
|
|
81
|
-
// The image's root takes the folder's permissions, which mkdtemp keeps to its owner.
|
|
82
|
-
fs.chmodSync(folder, 0o755);
|
|
83
|
-
fs.cpSync(app, path.join(folder, path.basename(app)), { recursive: true, verbatimSymlinks: true });
|
|
84
|
-
fs.symlinkSync('/Applications', path.join(folder, 'Applications'));
|
|
85
|
-
fs.rmSync(image, { force: true });
|
|
86
|
-
run(null, ['hdiutil', 'create', '-quiet', '-volname', appDisplayName(state.config), '-srcfolder', folder, '-fs', 'HFS+', '-format', 'UDZO', image], null, target);
|
|
87
|
-
} finally {
|
|
88
|
-
fs.rmSync(folder, { recursive: true, force: true });
|
|
44
|
+
// What a desktop app ships with stops a build that could not make it here, before anything compiles: the keys that sign
|
|
45
|
+
// the app, the installers app.installers names, and what each installer checks, which it does knowing those that run.
|
|
46
|
+
export async function checkInstaller(target) {
|
|
47
|
+
if (!DESKTOP_PLATFORMS[target.platform]) return;
|
|
48
|
+
if (target.platform === 'darwin') appleSigning();
|
|
49
|
+
if (target.platform === 'win32') windowsSigning();
|
|
50
|
+
const installers = installersFor(target);
|
|
51
|
+
const own = builtInInstallers().map(({ name }) => name);
|
|
52
|
+
installers.filter((extension) => own.includes(extension.name) && state.config.extensions?.includes(extension) && !toldReplacing.has(extension.name))
|
|
53
|
+
.forEach(({ name, root }) => {
|
|
54
|
+
toldReplacing.add(name);
|
|
55
|
+
console.log(`crossbind: the extension ${name} of ${root} replaces crossbind's own installer of its name.`);
|
|
56
|
+
});
|
|
57
|
+
const names = Object.freeze(installers.map(({ name }) => name));
|
|
58
|
+
for (const { name, installer } of installers) {
|
|
59
|
+
if (installer.check) await extensionStep(name, 'check', () => installer.check(apiOf(name, target), Object.freeze({ installers: names })));
|
|
89
60
|
}
|
|
90
61
|
}
|
|
91
62
|
|
|
92
|
-
//
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const { general, paths } = state.config;
|
|
97
|
-
const name = debianName(general.name);
|
|
98
|
-
const label = appDisplayName(state.config);
|
|
99
|
-
const root = `${paths.build}/${path.basename(app)}.deb`;
|
|
100
|
-
const dir = (relative) => {
|
|
101
|
-
fs.mkdirSync(`${root}/${relative}`, { recursive: true });
|
|
102
|
-
return `${root}/${relative}`;
|
|
103
|
-
};
|
|
104
|
-
fs.rmSync(root, { recursive: true, force: true });
|
|
105
|
-
fs.cpSync(app, `${dir('usr/lib')}/${name}`, { recursive: true, verbatimSymlinks: true });
|
|
106
|
-
fs.symlinkSync(`../lib/${name}/${general.name}`, `${dir('usr/bin')}/${name}`);
|
|
107
|
-
const icon = `${app}/resources/icon.png`;
|
|
108
|
-
const hasIcon = fs.existsSync(icon);
|
|
109
|
-
if (hasIcon) fs.copyFileSync(icon, `${dir('usr/share/icons/hicolor/512x512/apps')}/${name}.png`);
|
|
110
|
-
fs.writeFileSync(`${dir('usr/share/applications')}/${name}.desktop`, desktopEntry({
|
|
111
|
-
label, command: name, hasIcon, urlSchemes: appUrlSchemes(state.config), categories: appCategory(state.config)?.linux,
|
|
112
|
-
}));
|
|
113
|
-
const { author, description } = state.config.package ?? {};
|
|
114
|
-
fs.writeFileSync(`${dir('DEBIAN')}/control`, debianControl({ name, version: packageVersion(), arch: target.arch, author, description, label }));
|
|
115
|
-
run(null, ['dpkg-deb', '--build', '--root-owner-group', root, `${app}.deb`], null, target);
|
|
116
|
-
fs.rmSync(root, { recursive: true, force: true });
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// The name a Windows app's setup program gives its Start menu shortcut and folder, which Windows takes as a file name.
|
|
120
|
-
function windowsName() {
|
|
121
|
-
const label = appDisplayName(state.config);
|
|
122
|
-
if (/[<>:/|?*]|[ .]$/.test(label)) {
|
|
123
|
-
throw new Error(`crossbind: ${JSON.stringify(label)}, the name of a Windows app's Start menu shortcut and folder, is no file name Windows takes, which holds none of < > : / | ? * and ends in neither a space nor a dot. Change app.name in crossbind.config.js.`);
|
|
63
|
+
// The files an installer made, by their paths, a relative one beside the app.
|
|
64
|
+
function madeFiles(name, app, files) {
|
|
65
|
+
if (!Array.isArray(files) || !files.every((file) => typeof file === 'string')) {
|
|
66
|
+
throw new Error(`crossbind: the installer ${name} made no list of files, which its make returns.`);
|
|
124
67
|
}
|
|
125
|
-
return
|
|
68
|
+
return files.map((file) => {
|
|
69
|
+
const made = path.resolve(path.dirname(app), file);
|
|
70
|
+
if (!fs.statSync(made, { throwIfNoEntry: false })?.isFile()) throw new Error(`crossbind: the installer ${name} made ${made}, which is no file.`);
|
|
71
|
+
return made;
|
|
72
|
+
});
|
|
126
73
|
}
|
|
127
74
|
|
|
128
|
-
//
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
function windowsSetup(app) {
|
|
137
|
-
const signing = windowsSigning();
|
|
138
|
-
const icon = readAppIcon(state.config);
|
|
139
|
-
const iconFile = `${state.config.paths.build}/${path.basename(app)}.ico`;
|
|
140
|
-
if (icon) fs.writeFileSync(iconFile, windowsIcon(icon));
|
|
141
|
-
const urlSchemes = appUrlSchemes(state.config);
|
|
142
|
-
const schemesFile = `${state.config.paths.build}/${path.basename(app)}.schemes.nsh`;
|
|
143
|
-
if (urlSchemes.length > 0) fs.writeFileSync(schemesFile, schemesMacro(urlSchemes));
|
|
144
|
-
inWindowsImage([
|
|
145
|
-
'makensis', '-V2', '-INPUTCHARSET', 'UTF8',
|
|
146
|
-
`-DNAME=${nsisText(windowsName())}`,
|
|
147
|
-
`-DEXE=${nsisText(`${state.config.general.name}.exe`)}`,
|
|
148
|
-
`-DID=${appId(state.config)}`,
|
|
149
|
-
`-DVERSION=${nsisText(packageVersion())}`,
|
|
150
|
-
`-DAPP=${app}`,
|
|
151
|
-
`-DOUTFILE=${app}-setup.exe`,
|
|
152
|
-
...(icon ? [`-DICON=${iconFile}`] : []),
|
|
153
|
-
...(urlSchemes.length > 0 ? [`-DSCHEMES=${schemesFile}`] : []),
|
|
154
|
-
...(signing ? [`-DSIGNER=${jsignScript()}`] : []),
|
|
155
|
-
`${resolveAppHostRoot()}/windows/installer.nsi`,
|
|
156
|
-
], path.dirname(app), signing);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// What an app's installer takes from the app and the environment, checked before anything compiles: the names, the keys
|
|
160
|
-
// that sign a macOS or Windows app, and the one that signs a desktop app's update.
|
|
161
|
-
export function checkInstaller(target) {
|
|
162
|
-
if (target.platform === 'darwin') appleSigning();
|
|
163
|
-
else if (target.platform === 'linux') debianName(state.config.general.name);
|
|
164
|
-
else if (target.platform === 'win32') {
|
|
165
|
-
windowsName();
|
|
166
|
-
windowsSigning();
|
|
75
|
+
// What installs a desktop app, beside it: each installer's that made any, by its name, with the files it made, in the
|
|
76
|
+
// order they run, each seeing what those before it made.
|
|
77
|
+
export async function writeInstallers(app, target) {
|
|
78
|
+
const made = [];
|
|
79
|
+
for (const { name, installer } of installersFor(target)) {
|
|
80
|
+
const files = await extensionStep(name, 'make', () => installer.make(apiOf(name, target), Object.freeze({ app, arch: target.arch, made: structuredClone(made) })));
|
|
81
|
+
const madeNow = madeFiles(name, app, files);
|
|
82
|
+
if (madeNow.length > 0) made.push({ name, files: madeNow });
|
|
167
83
|
}
|
|
168
|
-
|
|
84
|
+
return made;
|
|
169
85
|
}
|
|
170
86
|
|
|
171
|
-
//
|
|
172
|
-
//
|
|
173
|
-
export
|
|
174
|
-
if (target.platform
|
|
175
|
-
|
|
176
|
-
|
|
87
|
+
// A desktop app with its page ships with what installs it. Installers write beside the app, in the page's own folder, so
|
|
88
|
+
// they run once every app of the build has its page.
|
|
89
|
+
export async function shipApp(target, to) {
|
|
90
|
+
if (!DESKTOP_PLATFORMS[target.platform]) return;
|
|
91
|
+
const app = path.resolve(to);
|
|
92
|
+
recordAppOutput(target, app, { installers: await writeInstallers(app, target) });
|
|
177
93
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { spawnSync } from 'node:child_process';
|
|
4
|
+
import { DARWIN_DEPLOYMENT_TARGET } from '../utils/darwinToolchain.js';
|
|
5
|
+
import { IOS_DEPLOYMENT_TARGET } from '../utils/iosToolchain.js';
|
|
6
|
+
|
|
7
|
+
// An Apple app's extensions' Swift, which CMake's Makefiles generator compiles none of: swiftc makes each extension's a
|
|
8
|
+
// static library first, with the Objective-C header its own sources import, before the host builds.
|
|
9
|
+
|
|
10
|
+
// The module an extension's Swift makes: its name, with underscores for dashes, as a Swift module's name takes it.
|
|
11
|
+
export const swiftModule = (name) => name.replace(/-/g, '_');
|
|
12
|
+
|
|
13
|
+
// What swiftc compiles an Apple target's Swift for: the target's triple, at the app's deployment target, and its SDK.
|
|
14
|
+
export function swiftTarget(target) {
|
|
15
|
+
if (target.platform === 'darwin') return { triple: `${target.arch === 'x64' ? 'x86_64' : 'arm64'}-apple-macos${DARWIN_DEPLOYMENT_TARGET}`, sdk: 'macosx' };
|
|
16
|
+
const isDevice = target.arch === 'iphoneos';
|
|
17
|
+
return { triple: `arm64-apple-ios${IOS_DEPLOYMENT_TARGET}${isDevice ? '' : '-simulator'}`, sdk: isDevice ? 'iphoneos' : 'iphonesimulator' };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// The swiftc arguments that make one extension's Swift a static library and the Objective-C header of its @objc classes
|
|
21
|
+
// and @_cdecl functions.
|
|
22
|
+
export function swiftArgs({ module, sources, library, header, triple, sdkPath, isRelease }) {
|
|
23
|
+
return [
|
|
24
|
+
'swiftc', '-parse-as-library', ...(isRelease ? ['-O'] : ['-Onone', '-g']), '-module-name', module,
|
|
25
|
+
'-emit-library', '-static', '-o', library, '-emit-objc-header', '-emit-objc-header-path', header,
|
|
26
|
+
'-target', triple, '-sdk', sdkPath, ...sources,
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function xcrun(args, what) {
|
|
31
|
+
const result = spawnSync('xcrun', args, { encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 });
|
|
32
|
+
if (result.error) throw new Error(`crossbind: ${what} needs Xcode's xcrun: ${result.error.message}`);
|
|
33
|
+
if (result.status !== 0) throw new Error(`crossbind: ${what} failed:\n${`${result.stdout}${result.stderr}`.trim()}`);
|
|
34
|
+
return result.stdout.trim();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Compiles each extension's Swift for an Apple target into its folder of workDir: the library, and the header beside it,
|
|
38
|
+
// which the folder, added to the extension's includes, gives its sources as <module>-Swift.h.
|
|
39
|
+
export function compileSwift(target, compiled, workDir, isRelease) {
|
|
40
|
+
const withSwift = compiled.filter(({ swift }) => swift.length > 0);
|
|
41
|
+
if (withSwift.length === 0) return [];
|
|
42
|
+
const { triple, sdk } = swiftTarget(target);
|
|
43
|
+
const sdkPath = xcrun(['--sdk', sdk, '--show-sdk-path'], `the ${sdk} SDK's path`);
|
|
44
|
+
return withSwift.map(({ name, swift }) => {
|
|
45
|
+
const module = swiftModule(name);
|
|
46
|
+
const dir = path.join(workDir, 'swift', module);
|
|
47
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
48
|
+
const library = path.join(dir, `lib${module}.a`);
|
|
49
|
+
const header = path.join(dir, `${module}-Swift.h`);
|
|
50
|
+
xcrun(swiftArgs({ module, sources: swift, library, header, triple, sdkPath, isRelease }), `the extension ${name}'s Swift`);
|
|
51
|
+
return { name, library, includes: [dir] };
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// What links the libraries: each whole, as an @objc class may be reached by its name alone, and Swift's own libraries,
|
|
56
|
+
// which the system holds on the app's deployment targets, beside the toolchain's back-deployed parts. An iOS app's
|
|
57
|
+
// Xcode project names them by its own settings, the back-deployed parts in Xcode's default toolchain, whose swiftc
|
|
58
|
+
// compiled them: TOOLCHAIN_DIR may name another, as the Metal toolchain.
|
|
59
|
+
export function swiftLinkArgs(target, libraries) {
|
|
60
|
+
if (libraries.length === 0) return [];
|
|
61
|
+
const searched = target.platform === 'darwin'
|
|
62
|
+
? [`-L${xcrun(['--sdk', 'macosx', '--show-sdk-path'], "the macosx SDK's path")}/usr/lib/swift`,
|
|
63
|
+
`-L${path.dirname(path.dirname(xcrun(['--find', 'swiftc'], "Swift's compiler")))}/lib/swift/macosx`]
|
|
64
|
+
: ['-L$(SDKROOT)/usr/lib/swift', '-L$(DEVELOPER_DIR)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/$(PLATFORM_NAME)'];
|
|
65
|
+
return [...libraries.map((library) => `-Wl,-force_load,${library}`), ...searched, '-Wl,-rpath,/usr/lib/swift'];
|
|
66
|
+
}
|