mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-14 10:35:47 +08:00
Program builds have not imported runtime bitcode since fc38e6279, but
every runtime pack still built and listed it: release units through the
helper's prune-import, speed units as runtime-unit's second output. That
is 24 MB of the linux-x64-gnu pack.
Building that bitcode also cost scr_glibc_math its runtime profile: the
pruned import module keeps the floor, ceil and trunc ifuncs without their
resolvers and fails verification, and runtime-unit built it before the
object, so the whole speed unit fell back to a direct compile. The build
printed only the first line of the helper's stderr, a CPU feature
warning.
- runtime-unit's --bitcode is optional (feature
"runtime-unit-optional-bitcode"), and pack builds no longer pass it or
run prune-import. Speed objects come out as before, scr_glibc_math's now
with the runtime profile.
- Pack manifests list no bitcode, and the compiler no longer validates the
field. verify and share-artifacts check objects only.
- A unit the helper can't emit reports the helper's JSON diagnostic.
- The zero-cost gate names changed runtime functions from the objects'
disassembly instead of the bitcode.
45 lines
1.7 KiB
JavaScript
45 lines
1.7 KiB
JavaScript
import { readdir, rm, rmdir } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
|
|
/** Points the artifacts of one runtime unit that hold the same bytes at one
|
|
* file and deletes the copies. Variants whose defines a unit does not read,
|
|
* and flavors that compile a unit the same way, produce identical objects.
|
|
* Each link selects one flavor and one variant of each unit, so
|
|
* no link names a shared file twice. `root` is the directory artifact paths
|
|
* are relative to; flavors keep the order they were built in, so the first
|
|
* flavor's path holds the shared file. */
|
|
export async function shareIdenticalArtifacts(flavors, root) {
|
|
const firstPaths = new Map();
|
|
for (const flavor of Object.values(flavors)) {
|
|
for (const unit of flavor.runtime_units) {
|
|
let paths = firstPaths.get(unit.source);
|
|
if (paths === undefined) {
|
|
paths = new Map();
|
|
firstPaths.set(unit.source, paths);
|
|
}
|
|
for (const variant of unit.variants) {
|
|
const first = paths.get(variant.sha256);
|
|
if (first === undefined) {
|
|
paths.set(variant.sha256, variant.path);
|
|
} else if (first !== variant.path) {
|
|
await rm(join(root, variant.path));
|
|
variant.path = first;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
await removeEmptyDirectories(join(root, "artifacts"));
|
|
}
|
|
|
|
async function removeEmptyDirectories(directory) {
|
|
const entries = await readdir(directory, { withFileTypes: true });
|
|
let remaining = entries.length;
|
|
for (const entry of entries) {
|
|
if (entry.isDirectory() && (await removeEmptyDirectories(join(directory, entry.name))))
|
|
remaining--;
|
|
}
|
|
if (remaining > 0) return false;
|
|
await rmdir(directory);
|
|
return true;
|
|
}
|