mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-02 08:35:07 +08:00
- Remove C emission, debugging options, and automatic backend fallback. - Complete LLVM lowering and native bootstrap coverage across supported targets. - Link executables and libraries with precompiled C runtime packs, including iOS and Android.
98 lines
4.1 KiB
JavaScript
98 lines
4.1 KiB
JavaScript
#!/usr/bin/env node
|
|
import { createHash } from "node:crypto";
|
|
import { spawnSync } from "node:child_process";
|
|
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
import { dirname, join, resolve } from "node:path";
|
|
|
|
const [mode, infoArg, outputArg] = process.argv.slice(2);
|
|
if ((mode !== "cc" && mode !== "ld") || !infoArg || !outputArg) {
|
|
console.error("usage: node link.mjs <cc|ld> <native-link-info.json> <output>");
|
|
process.exitCode = 2;
|
|
} else {
|
|
const info = JSON.parse(readFileSync(infoArg, "utf8"));
|
|
if (info.schema !== "scriptc.native-link-info.v1") {
|
|
throw new Error(`unsupported native link info schema: ${info.schema}`);
|
|
}
|
|
const runtimePackage = JSON.parse(
|
|
readFileSync(join(info.runtime_pack.root, "package.json"), "utf8"),
|
|
);
|
|
if (
|
|
runtimePackage.name !== info.runtime_pack.package ||
|
|
runtimePackage.version !== info.runtime_pack.version
|
|
) {
|
|
throw new Error(
|
|
`runtime pack identity mismatch: expected ${info.runtime_pack.package}@${info.runtime_pack.version} ` +
|
|
`at ${info.runtime_pack.root}, found ${runtimePackage.name ?? "<unnamed>"}@${runtimePackage.version ?? "<unversioned>"}`,
|
|
);
|
|
}
|
|
const run = (command, args, options = {}) => {
|
|
const result = spawnSync(command, args, { stdio: "inherit", ...options });
|
|
if (result.error) throw result.error;
|
|
if (result.status !== 0) throw new Error(`${command} exited ${result.status}`);
|
|
};
|
|
const capture = (command, args) => {
|
|
const result = spawnSync(command, args, { encoding: "utf8" });
|
|
if (result.error) throw result.error;
|
|
if (result.status !== 0) throw new Error(result.stderr || `${command} exited ${result.status}`);
|
|
return result.stdout.trim();
|
|
};
|
|
|
|
const infoPath = resolve(infoArg);
|
|
const output = resolve(outputArg);
|
|
const buildDir = join(dirname(infoPath), `.native-link-${mode}`);
|
|
rmSync(buildDir, { recursive: true, force: true });
|
|
mkdirSync(buildDir, { recursive: true });
|
|
const runtimeObjects = [];
|
|
const vendorArchives = [];
|
|
for (const [kind, artifacts] of [["objects", info.runtime_pack.objects], ["archives", info.runtime_pack.archives]]) {
|
|
for (const artifact of artifacts) {
|
|
if (artifact.path.startsWith("/") || artifact.path.split(/[\\/]/).includes("..")) throw new Error("invalid runtime artifact path");
|
|
const bytes = readFileSync(join(info.runtime_pack.root, artifact.path));
|
|
if (bytes.length !== artifact.size || createHash("sha256").update(bytes).digest("hex") !== artifact.sha256) {
|
|
throw new Error(`runtime pack hash mismatch: ${artifact.path}`);
|
|
}
|
|
const destination = join(buildDir, artifact.path);
|
|
mkdirSync(dirname(destination), { recursive: true });
|
|
writeFileSync(destination, bytes, { mode: 0o400 });
|
|
(kind === "objects" ? runtimeObjects : vendorArchives).push(destination);
|
|
}
|
|
}
|
|
|
|
const inputs = [
|
|
info.program.object,
|
|
...info.ffi.libraries,
|
|
...runtimeObjects,
|
|
...vendorArchives,
|
|
];
|
|
const libraries = info.link.system_libraries.map((name) => `-l${name}`);
|
|
const frameworks = info.link.frameworks.flatMap((name) => ["-framework", name]);
|
|
if (mode === "cc") {
|
|
// Darwin compiler drivers add libSystem themselves. It remains explicit
|
|
// in the document because a direct ld invocation must name it.
|
|
const driverLibraries = info.link.system_libraries
|
|
.filter((name) => name !== "System")
|
|
.map((name) => `-l${name}`);
|
|
run("clang", [
|
|
...info.link.driver_flags,
|
|
...inputs,
|
|
...driverLibraries,
|
|
...frameworks,
|
|
"-o", output,
|
|
]);
|
|
} else {
|
|
const sdk = capture("xcrun", ["--sdk", "macosx", "--show-sdk-path"]);
|
|
const sdkVersion = capture("xcrun", ["--sdk", "macosx", "--show-sdk-version"]);
|
|
const linker = capture("xcrun", ["--sdk", "macosx", "--find", "ld"]);
|
|
run(linker, [
|
|
"-arch", info.target.architecture,
|
|
"-platform_version", "macos", info.target.minimum_os, sdkVersion,
|
|
"-syslibroot", sdk,
|
|
...(info.link.driver_flags.includes("-Wl,-dead_strip") ? ["-dead_strip"] : []),
|
|
...inputs,
|
|
...libraries,
|
|
...frameworks,
|
|
"-o", output,
|
|
]);
|
|
}
|
|
}
|