mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-01 07:33:12 +08:00
Stack the libnode packs on the in-process loader (#1685) and use its pack assembler and manifest format instead of a second one: build-pack.mjs keeps its CLI and fields (schema, nodeVersion, moduleVersion, bridgeAbi, platform, arch, files), adds the libnode and bridge names, strips and (on macOS) re-signs the bridge and links it with -z defs, and exports buildPack(), which the platform packs call with their package, target and build inputs as extra manifest fields. libnodeRecord falls back to the installed @scriptc/libnode-<platform> pack, found from the entry's directory and then next to the compiler, when neither --libnode nor SCRIPTC_LIBNODE names one. The Linux test lanes restore the libnode build that the libnode-packs workflow cached, assemble the linux-x64 pack from it in seconds (build.mjs --from-cache never builds Node) and export SCRIPTC_LIBNODE, so the Node island corpus and harness tests run instead of skipping. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
91 lines
3.5 KiB
JavaScript
91 lines
3.5 KiB
JavaScript
// The libnode pin and the platform table shared by the libnode pack build,
|
|
// its CI cache keys, the pack verifier, and the smoke test.
|
|
//
|
|
// A libnode pack (`@scriptc/libnode-<platform>`) holds a stripped Node.js
|
|
// shared library built from the pinned release, the C++ bridge compiled
|
|
// against that release's headers, Node's license, and manifest.json. The
|
|
// scriptc runtime dlopens the bridge on its first call into Node and talks
|
|
// to it only through the C ABI in packages/runtime/src/scr_node_bridge.h.
|
|
import { createHash } from "node:crypto";
|
|
import { readFileSync } from "node:fs";
|
|
import { dirname, join } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
export const commonRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
export const repoRoot = dirname(dirname(commonRoot));
|
|
export const bridgeSource = join(commonRoot, "bridge", "scr_node_bridge.cc");
|
|
export const bridgeHeader = join(repoRoot, "packages", "runtime", "src", "scr_node_bridge.h");
|
|
|
|
export { LIBNODE_PACK_SCHEMA, bridgeAbi } from "../build-pack.mjs";
|
|
|
|
/** Bump to invalidate every cached libnode build (a change to how the
|
|
* library is built or staged that the pin does not capture). */
|
|
const BUILD_RECIPE = 1;
|
|
|
|
/**
|
|
* @typedef {{
|
|
* nodeVersion: string,
|
|
* tarballSha256: string,
|
|
* moduleVersion: number,
|
|
* configureFlags: string[],
|
|
* icu: "full" | "small",
|
|
* }} LibnodePin
|
|
*/
|
|
|
|
/** @returns {LibnodePin} */
|
|
export function readPin() {
|
|
return JSON.parse(readFileSync(join(commonRoot, "libnode.json"), "utf8"));
|
|
}
|
|
|
|
/** Pack platforms: the npm package suffix, the Node `os`/`arch`, and the
|
|
* file names inside the pack. The darwin packs build only on macOS hosts. */
|
|
export const LIBNODE_PLATFORMS = {
|
|
"linux-x64-gnu": { os: "linux", arch: "x64", target: "linux-x64-gnu" },
|
|
"linux-arm64-gnu": { os: "linux", arch: "arm64", target: "linux-arm64-gnu" },
|
|
"darwin-arm64": { os: "darwin", arch: "arm64", target: "macos-arm64" },
|
|
"darwin-x64": { os: "darwin", arch: "x64", target: "macos-x64" },
|
|
};
|
|
|
|
/** @param {string} platform */
|
|
export function platformInfo(platform) {
|
|
const info = LIBNODE_PLATFORMS[/** @type {keyof typeof LIBNODE_PLATFORMS} */ (platform)];
|
|
if (info === undefined) throw new Error(`unknown libnode pack platform ${platform}`);
|
|
return info;
|
|
}
|
|
|
|
/** The library names inside a pack for one platform and module version. */
|
|
export function packFileNames(platform, moduleVersion) {
|
|
const { os } = platformInfo(platform);
|
|
return os === "darwin"
|
|
? { libnode: `libnode.${moduleVersion}.dylib`, bridge: "libscr_node_bridge.dylib" }
|
|
: { libnode: `libnode.so.${moduleVersion}`, bridge: "libscr_node_bridge.so" };
|
|
}
|
|
|
|
function sha256(text) {
|
|
return createHash("sha256").update(text).digest("hex");
|
|
}
|
|
|
|
/** The cache key of the libnode build itself: the Node release, how it is
|
|
* configured, the platform and toolchain. The bridge is not part of it; a
|
|
* bridge change rebuilds only the bridge against the cached headers. */
|
|
export function libnodeCacheKey(platform, toolchain = process.env.SCRIPTC_LIBNODE_TOOLCHAIN) {
|
|
const pin = readPin();
|
|
platformInfo(platform);
|
|
return sha256(
|
|
JSON.stringify({
|
|
recipe: BUILD_RECIPE,
|
|
nodeVersion: pin.nodeVersion,
|
|
tarballSha256: pin.tarballSha256,
|
|
configureFlags: pin.configureFlags,
|
|
icu: pin.icu,
|
|
platform,
|
|
toolchain: toolchain ?? "default",
|
|
}),
|
|
);
|
|
}
|
|
|
|
/** The hash of everything the bridge is compiled from. */
|
|
export function bridgeHash() {
|
|
return sha256(readFileSync(bridgeSource, "utf8") + "\0" + readFileSync(bridgeHeader, "utf8"));
|
|
}
|