mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-02 00:25:34 +08:00
Preserve glibc 2.36 runtime compatibility (#365)
- Pin GNU runtime packs to glibc 2.36 Zig targets and reject incompatible imports. - Provision verified Zig builds and exercise published artifacts on Debian Bookworm. Fixes #349 Co-authored-by: Cruel <383999+Cruel@users.noreply.github.com>
This commit is contained in:
@@ -114,7 +114,7 @@ jobs:
|
||||
llvm_artifacts_linux_x64:
|
||||
name: test (Linux x64 LLVM artifacts, no clang)
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 25
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
@@ -135,10 +135,10 @@ jobs:
|
||||
echo "$RUNNER_TEMP/llvm-22.1.8/bin" >> "$GITHUB_PATH"
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm --filter @scriptc/llvm-linux-x64-gnu build:native
|
||||
- run: CC=clang AR=llvm-ar pnpm --filter @scriptc/runtime-linux-x64-gnu build:native
|
||||
- uses: vercel-labs/setup-zig@v1
|
||||
with:
|
||||
version: 0.16.0
|
||||
- run: CC=zig AR=zig pnpm --filter @scriptc/runtime-linux-x64-gnu build:native
|
||||
- name: Build and verify Linux x64 musl release packages
|
||||
run: |
|
||||
pnpm --filter @scriptc/llvm-linux-x64-musl build:native
|
||||
@@ -173,6 +173,14 @@ jobs:
|
||||
run: |
|
||||
node packages/cli/dist/main.js build tests/corpus/001-hello.ts -o "$RUNNER_TEMP/hello"
|
||||
test "$("$RUNNER_TEMP/hello")" = 'hello world'
|
||||
- name: Debian 12 glibc 2.36 runtime-pack smoke
|
||||
run: |
|
||||
docker run --rm --volume "$GITHUB_WORKSPACE:/work:ro" --workdir /work node:24-bookworm-slim sh -ec '
|
||||
apt-get update
|
||||
apt-get install --yes --no-install-recommends clang
|
||||
SCRIPTC_NO_CACHE=1 SCRIPTC_LEGACY_C_PIPELINE=0 node packages/cli/dist/main.js build tests/corpus/001-hello.ts -o /tmp/hello
|
||||
test "$(/tmp/hello)" = "hello world"
|
||||
'
|
||||
- name: WASI helper object/runtime-pack smoke
|
||||
run: pnpm test packages/cli/test/wasi-runtime-pack.test.ts
|
||||
|
||||
|
||||
@@ -70,11 +70,13 @@ jobs:
|
||||
helper: llvm-linux-x64-gnu
|
||||
runtime: runtime-linux-x64-gnu
|
||||
llvm_asset: LLVM-22.1.8-Linux-X64
|
||||
use_zig: true
|
||||
- platform: linux-arm64
|
||||
runner: ubuntu-24.04-arm
|
||||
helper: llvm-linux-arm64-gnu
|
||||
runtime: runtime-linux-arm64-gnu
|
||||
llvm_asset: LLVM-22.1.8-Linux-ARM64
|
||||
use_zig: true
|
||||
- platform: windows-x64
|
||||
runner: windows-2022
|
||||
helper: llvm-win32-x64-msvc
|
||||
|
||||
@@ -13,12 +13,7 @@ pnpm install && pnpm -r build # build the workspace
|
||||
pnpm test:sandbox # full gate: ~4m custom image, ~9m cold managed fallback
|
||||
```
|
||||
|
||||
The ordinary workspace build does not rebuild packaged native artifacts.
|
||||
When changing native assembly/object emission or runtime-pack selection,
|
||||
install CMake, Ninja, and the pinned LLVM 22 development package, then run the
|
||||
matching `@scriptc/llvm-<platform>` and `@scriptc/runtime-<platform>`
|
||||
`build:native` scripts explicitly. The macOS full test suite also needs its
|
||||
generated artifacts.
|
||||
The ordinary workspace build does not rebuild packaged native artifacts. When changing native assembly/object emission or runtime-pack selection, install CMake, Ninja, the pinned LLVM 22 development package, and Zig 0.16.0, then run the matching `@scriptc/llvm-<platform>` and `@scriptc/runtime-<platform>` `build:native` scripts explicitly. The macOS full test suite also needs its generated artifacts.
|
||||
|
||||
Use focused local tests while iterating, then use `pnpm test:sandbox` whenever a
|
||||
full validation gate is required. It loads Sandbox configuration from the
|
||||
|
||||
@@ -3,6 +3,7 @@ FROM ubuntu:24.04
|
||||
|
||||
ARG NODE_VERSION
|
||||
ARG PNPM_VERSION=11.1.3
|
||||
ARG ZIG_VERSION=0.16.0
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
@@ -45,6 +46,10 @@ RUN curl --fail --silent --show-error --location \
|
||||
&& tar -xJf /tmp/node.tar.xz --directory /usr/local --strip-components=1 \
|
||||
&& rm /tmp/node.tar.xz /tmp/SHASUMS256.txt
|
||||
|
||||
COPY scripts/install-zig.sh /tmp/install-zig.sh
|
||||
RUN sh /tmp/install-zig.sh "$ZIG_VERSION" \
|
||||
&& rm /tmp/install-zig.sh
|
||||
|
||||
RUN npm install --global "pnpm@${PNPM_VERSION}"
|
||||
|
||||
WORKDIR /workspace
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import { dirname } from "node:path"; import { fileURLToPath } from "node:url";
|
||||
if (process.platform !== "linux" || process.arch !== "arm64") { process.stdout.write("@scriptc/runtime-linux-arm64-gnu: skipped on this host\n"); process.exit(0); }
|
||||
import { dirname } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { glibcRuntimeToolchain } from "../../runtime-pack-common/scripts/glibc-toolchain.mjs";
|
||||
|
||||
if (process.platform !== "linux" || process.arch !== "arm64") {
|
||||
process.stdout.write("@scriptc/runtime-linux-arm64-gnu: skipped on this host\n");
|
||||
process.exit(0);
|
||||
}
|
||||
process.env.SCRIPTC_RUNTIME_PACK_ROOT = dirname(dirname(fileURLToPath(import.meta.url)));
|
||||
process.env.SCRIPTC_RUNTIME_PACK_CONFIG = JSON.stringify({ platform: "linux", runtimeDefines: ["_GNU_SOURCE"], threadArgs: ["-pthread"], target: { name: "linux-arm64-gnu", llvm_triple: "aarch64-unknown-linux-gnu", architecture: "arm64", object_format: "elf", minimum_os: "glibc 2.36" }, targetArgs: ["-target", "aarch64-unknown-linux-gnu"], compileFlags: ["-ffunction-sections", "-fdata-sections"], systemLibraries: [{ name: "m", predicate: true }] });
|
||||
const { minimumOs, ...toolchain } = glibcRuntimeToolchain("arm64");
|
||||
process.env.SCRIPTC_RUNTIME_PACK_CONFIG = JSON.stringify({ platform: "linux", runtimeDefines: ["_GNU_SOURCE"], threadArgs: ["-pthread"], target: { name: "linux-arm64-gnu", llvm_triple: "aarch64-unknown-linux-gnu", architecture: "arm64", object_format: "elf", minimum_os: minimumOs }, ...toolchain, compileFlags: ["-ffunction-sections", "-fdata-sections"], systemLibraries: [{ name: "m", predicate: true }] });
|
||||
await import("../../runtime-pack-common/scripts/build.mjs");
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import { dirname } from "node:path"; import { fileURLToPath } from "node:url";
|
||||
if (process.platform !== "linux" || process.arch !== "x64") { process.stdout.write("@scriptc/runtime-linux-x64-gnu: skipped on this host\n"); process.exit(0); }
|
||||
import { dirname } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { glibcRuntimeToolchain } from "../../runtime-pack-common/scripts/glibc-toolchain.mjs";
|
||||
|
||||
if (process.platform !== "linux" || process.arch !== "x64") {
|
||||
process.stdout.write("@scriptc/runtime-linux-x64-gnu: skipped on this host\n");
|
||||
process.exit(0);
|
||||
}
|
||||
process.env.SCRIPTC_RUNTIME_PACK_ROOT = dirname(dirname(fileURLToPath(import.meta.url)));
|
||||
process.env.SCRIPTC_RUNTIME_PACK_CONFIG = JSON.stringify({ platform: "linux", runtimeDefines: ["_GNU_SOURCE"], threadArgs: ["-pthread"], target: { name: "linux-x64-gnu", llvm_triple: "x86_64-unknown-linux-gnu", architecture: "x64", object_format: "elf", minimum_os: "glibc 2.36" }, targetArgs: ["-target", "x86_64-unknown-linux-gnu"], compileFlags: ["-ffunction-sections", "-fdata-sections"], systemLibraries: [{ name: "m", predicate: true }] });
|
||||
const { minimumOs, ...toolchain } = glibcRuntimeToolchain("x64");
|
||||
process.env.SCRIPTC_RUNTIME_PACK_CONFIG = JSON.stringify({ platform: "linux", runtimeDefines: ["_GNU_SOURCE"], threadArgs: ["-pthread"], target: { name: "linux-x64-gnu", llvm_triple: "x86_64-unknown-linux-gnu", architecture: "x64", object_format: "elf", minimum_os: minimumOs }, ...toolchain, compileFlags: ["-ffunction-sections", "-fdata-sections"], systemLibraries: [{ name: "m", predicate: true }] });
|
||||
await import("../../runtime-pack-common/scripts/build.mjs");
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import { readFile, readdir } from "node:fs/promises";
|
||||
import { join, relative, sep } from "node:path";
|
||||
|
||||
export async function assertArtifactsExcludeStrings(root, forbiddenStrings) {
|
||||
if (!Array.isArray(forbiddenStrings)) {
|
||||
throw new Error("runtime-pack forbidden artifact strings must be an array");
|
||||
}
|
||||
if (forbiddenStrings.length === 0) return;
|
||||
if (forbiddenStrings.some((value) => typeof value !== "string" || value.length === 0)) {
|
||||
throw new Error("runtime-pack forbidden artifact strings must be non-empty strings");
|
||||
}
|
||||
const forbidden = forbiddenStrings.map((value) => ({ value, bytes: Buffer.from(value) }));
|
||||
const visit = async (directory) => {
|
||||
for (const entry of await readdir(directory, { withFileTypes: true })) {
|
||||
const path = join(directory, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
await visit(path);
|
||||
continue;
|
||||
}
|
||||
if (!entry.isFile()) continue;
|
||||
const bytes = await readFile(path);
|
||||
const match = forbidden.find((candidate) => bytes.includes(candidate.bytes));
|
||||
if (match !== undefined) {
|
||||
const artifact = relative(root, path).split(sep).join("/");
|
||||
throw new Error(
|
||||
`runtime-pack artifact ${artifact} contains forbidden symbol family ${match.value}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
await visit(root);
|
||||
}
|
||||
@@ -3,10 +3,11 @@ import { execFile } from "node:child_process";
|
||||
import { createHash } from "node:crypto";
|
||||
import { availableParallelism, tmpdir } from "node:os";
|
||||
import { copyFile, mkdir, mkdtemp, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
|
||||
import { basename, dirname, join, relative, sep } from "node:path";
|
||||
import { dirname, join, relative, sep } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { promisify } from "node:util";
|
||||
import { createRuntimePackMatrix } from "../runtime-pack-matrix.mjs";
|
||||
import { assertArtifactsExcludeStrings } from "./artifact-policy.mjs";
|
||||
import { createDeterministicArchive } from "./archive.mjs";
|
||||
import { installRuntimePack, withBuildLock } from "./build-state.mjs";
|
||||
|
||||
@@ -35,7 +36,7 @@ async function build() {
|
||||
const archiver = process.env.AR ?? config.archiver ?? "ar";
|
||||
const archiverArgs = config.archiverArgs ?? [];
|
||||
const commonFlags = [
|
||||
...config.targetArgs, "-std=c11", ...(config.threadArgs ?? []), "-fno-math-errno", "-fno-strict-aliasing",
|
||||
...config.targetArgs, ...(config.compilerFlags ?? []), "-std=c11", ...(config.threadArgs ?? []), "-fno-math-errno", "-fno-strict-aliasing",
|
||||
...matrix.executable_section_elimination.compile_flags, "-Wno-deprecated-declarations", "-I", runtimeSrc,
|
||||
...(config.runtimeDefines ?? []).map((define) => `-D${define}`),
|
||||
];
|
||||
@@ -55,6 +56,7 @@ async function build() {
|
||||
for (let i = 0; i < items.length; i += width) await Promise.all(items.slice(i, i + width).map(task));
|
||||
};
|
||||
const archive = async (id, sources, sourceRoot, flags) => {
|
||||
process.stdout.write(`building ${packageManifest.name} ${id} archive\n`);
|
||||
const root = join(stagedOutputRoot, "vendor", id);
|
||||
const objectRoot = join(root, "objects");
|
||||
await parallel(sources, async (source) => compile(join(sourceRoot, source), join(objectRoot, source.replace(/\.c$/, ".o")), flags));
|
||||
@@ -80,6 +82,7 @@ async function build() {
|
||||
}
|
||||
const flavors = {};
|
||||
for (const [flavor, flavorSpec] of Object.entries(matrix.flavors)) {
|
||||
process.stdout.write(`building ${packageManifest.name} ${flavor} runtime\n`);
|
||||
const units = [];
|
||||
for (const unit of matrix.runtime_units) {
|
||||
const variants = [];
|
||||
@@ -103,6 +106,7 @@ async function build() {
|
||||
// selected, so vendor sources inherit the target's runtime defines too.
|
||||
const vendorTarget = [
|
||||
...config.targetArgs,
|
||||
...(config.compilerFlags ?? []),
|
||||
...(config.runtimeDefines ?? []).map((define) => `-D${define}`),
|
||||
];
|
||||
const requestedArchives = new Set(matrix.archives.map((entry) => entry.id));
|
||||
@@ -112,6 +116,7 @@ async function build() {
|
||||
...(requestedArchives.has("zlib") ? [await archive("zlib", zlibSources, zlib, [...vendorTarget, "-std=c11", "-Os", "-I", zlib])] : []),
|
||||
...(requestedArchives.has("mbedtls") ? [await archive("mbedtls", mbedtlsSources, join(mbedtls, "library"), [...vendorTarget, "-std=c11", "-Os", "-I", join(mbedtls, "include"), "-I", join(mbedtls, "library")])] : []),
|
||||
];
|
||||
await assertArtifactsExcludeStrings(stagedOutputRoot, config.forbiddenArtifactStrings ?? []);
|
||||
const archiveSpecs = new Map(matrix.archives.map((entry) => [entry.id, entry]));
|
||||
const licensed = [[join(runtimeRoot, "LICENSE"), "artifacts/licenses/scriptc-runtime.txt", "Apache-2.0"], [join(quickjs, "LICENSE"), "artifacts/licenses/quickjs-ng.txt", "MIT"], [join(vendorRoot, "ryu", "LICENSE-Boost"), "artifacts/licenses/ryu.txt", "BSL-1.0"], [join(zlib, "LICENSE"), "artifacts/licenses/zlib.txt", "Zlib"], [join(mbedtls, "LICENSE"), "artifacts/licenses/mbedtls.txt", "Apache-2.0"]];
|
||||
await Promise.all(licensed.map(async ([source, destination]) => { const output = join(buildRoot, destination); await mkdir(dirname(output), { recursive: true }); await copyFile(source, output); }));
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
const GLIBC_RUNTIME_FLOOR = "2.36";
|
||||
|
||||
const GNU_ARCHITECTURES = {
|
||||
x64: "x86_64",
|
||||
arm64: "aarch64",
|
||||
};
|
||||
|
||||
export function glibcRuntimeToolchain(architecture) {
|
||||
const targetArchitecture = GNU_ARCHITECTURES[architecture];
|
||||
if (targetArchitecture === undefined) {
|
||||
throw new Error(`unsupported GNU runtime architecture: ${architecture}`);
|
||||
}
|
||||
return {
|
||||
minimumOs: `glibc ${GLIBC_RUNTIME_FLOOR}`,
|
||||
compiler: "zig",
|
||||
compilerArgs: ["cc"],
|
||||
archiver: "zig",
|
||||
archiverArgs: ["ar"],
|
||||
targetArgs: ["-target", `${targetArchitecture}-linux-gnu.${GLIBC_RUNTIME_FLOOR}`],
|
||||
compilerFlags: ["-fno-sanitize=undefined"],
|
||||
forbiddenArtifactStrings: ["__isoc23_", "__ubsan_"],
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { expect, test } from "vitest";
|
||||
import { assertArtifactsExcludeStrings } from "../scripts/artifact-policy.mjs";
|
||||
|
||||
test("accepts artifacts whose imports stay within the declared libc floor", async () => {
|
||||
const root = await mkdtemp(join(tmpdir(), "scriptc-artifact-policy-"));
|
||||
try {
|
||||
await writeFile(join(root, "runtime.o"), Buffer.from("strtol\0__isoc99_sscanf\0"));
|
||||
await expect(assertArtifactsExcludeStrings(root, ["__isoc23_", "__ubsan_"])).resolves.toBeUndefined();
|
||||
} finally {
|
||||
await rm(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test.each([
|
||||
["__isoc23_sscanf", "__isoc23_"],
|
||||
["__ubsan_handle_add_overflow", "__ubsan_"],
|
||||
])("rejects the %s import in nested runtime artifacts", async (symbol, family) => {
|
||||
const root = await mkdtemp(join(tmpdir(), "scriptc-artifact-policy-"));
|
||||
try {
|
||||
await mkdir(join(root, "release", "runtime"), { recursive: true });
|
||||
await writeFile(join(root, "release", "runtime", "scr_lib.o"), Buffer.from(`${symbol}\0`));
|
||||
await expect(assertArtifactsExcludeStrings(root, ["__isoc23_", "__ubsan_"])).rejects.toThrow(
|
||||
`runtime-pack artifact release/runtime/scr_lib.o contains forbidden symbol family ${family}`,
|
||||
);
|
||||
} finally {
|
||||
await rm(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
import { expect, test } from "vitest";
|
||||
import { glibcRuntimeToolchain } from "../scripts/glibc-toolchain.mjs";
|
||||
|
||||
test.each([
|
||||
["x64", "x86_64-linux-gnu.2.36"],
|
||||
["arm64", "aarch64-linux-gnu.2.36"],
|
||||
])("pins the %s GNU runtime to its glibc floor", (architecture, target) => {
|
||||
expect(glibcRuntimeToolchain(architecture)).toEqual({
|
||||
minimumOs: "glibc 2.36",
|
||||
compiler: "zig",
|
||||
compilerArgs: ["cc"],
|
||||
archiver: "zig",
|
||||
archiverArgs: ["ar"],
|
||||
targetArgs: ["-target", target],
|
||||
compilerFlags: ["-fno-sanitize=undefined"],
|
||||
forbiddenArtifactStrings: ["__isoc23_", "__ubsan_"],
|
||||
});
|
||||
});
|
||||
|
||||
test("rejects unknown GNU runtime architectures", () => {
|
||||
expect(() => glibcRuntimeToolchain("riscv64")).toThrow(
|
||||
"unsupported GNU runtime architecture: riscv64",
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,72 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
version=${1:?usage: install-zig.sh <version>}
|
||||
case "$version" in
|
||||
*[!0-9A-Za-z.+-]*) echo "invalid Zig version: $version" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
case "$(uname -s)-$(uname -m)" in
|
||||
Linux-x86_64) target=x86_64-linux ;;
|
||||
Linux-aarch64 | Linux-arm64) target=aarch64-linux ;;
|
||||
*) echo "unsupported Zig host: $(uname -s)/$(uname -m)" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
if command -v zig >/dev/null 2>&1 && [ "$(zig version)" = "$version" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
temporary=$(mktemp -d)
|
||||
trap 'rm -rf "$temporary"' EXIT HUP INT TERM
|
||||
|
||||
curl --fail --silent --show-error --location \
|
||||
https://ziglang.org/download/index.json \
|
||||
--output "$temporary/index.json"
|
||||
index_size=$(wc -c <"$temporary/index.json" | tr -d ' ')
|
||||
if [ "$index_size" -gt 2097152 ]; then
|
||||
echo "Zig download index exceeds 2 MiB" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
node --input-type=module - "$version" "$target" "$temporary/index.json" >"$temporary/metadata" <<'NODE'
|
||||
import { readFile } from "node:fs/promises";
|
||||
|
||||
const [version, target, indexPath] = process.argv.slice(2);
|
||||
const release = JSON.parse(await readFile(indexPath, "utf8"))[version];
|
||||
const artifact = release?.[target];
|
||||
if (!artifact?.tarball || !artifact?.shasum || !artifact?.size) {
|
||||
throw new Error(`Zig ${version} does not publish ${target}`);
|
||||
}
|
||||
const url = new URL(artifact.tarball);
|
||||
if (url.protocol !== "https:" || !/^[0-9a-f]{64}$/.test(artifact.shasum)) {
|
||||
throw new Error(`Zig ${version} returned invalid ${target} metadata`);
|
||||
}
|
||||
process.stdout.write(`${url.href}\n${artifact.shasum}\n${artifact.size}\n`);
|
||||
NODE
|
||||
|
||||
url=$(sed -n '1p' "$temporary/metadata")
|
||||
sha256=$(sed -n '2p' "$temporary/metadata")
|
||||
expected_size=$(sed -n '3p' "$temporary/metadata")
|
||||
archive="$temporary/zig.tar.xz"
|
||||
curl --fail --silent --show-error --location "$url" --output "$archive"
|
||||
printf '%s %s\n' "$sha256" "$archive" | sha256sum --check --strict -
|
||||
actual_size=$(wc -c <"$archive" | tr -d ' ')
|
||||
if [ "$actual_size" != "$expected_size" ]; then
|
||||
echo "Zig archive size mismatch: expected $expected_size, got $actual_size" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
as_root() {
|
||||
if [ "$(id -u)" -eq 0 ]; then
|
||||
"$@"
|
||||
else
|
||||
sudo "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
destination="/opt/zig-$version"
|
||||
as_root rm -rf "$destination"
|
||||
as_root mkdir -p "$destination"
|
||||
as_root tar -xJf "$archive" --directory "$destination" --strip-components=1
|
||||
as_root ln -sf "$destination/zig" /usr/local/bin/zig
|
||||
test "$(zig version)" = "$version"
|
||||
@@ -3,8 +3,9 @@ set -eu
|
||||
|
||||
node_version=$(tr -d '\r\n' < .node-version)
|
||||
pnpm_version=$(sed -n 's/^ARG PNPM_VERSION=//p' Dockerfile.sandbox)
|
||||
if [ -z "$node_version" ] || [ -z "$pnpm_version" ]; then
|
||||
echo "could not read the pinned Node or pnpm version" >&2
|
||||
zig_version=$(sed -n 's/^ARG ZIG_VERSION=//p' Dockerfile.sandbox)
|
||||
if [ -z "$node_version" ] || [ -z "$pnpm_version" ] || [ -z "$zig_version" ]; then
|
||||
echo "could not read the pinned Node, pnpm, or Zig version" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -50,6 +51,7 @@ grep " ${node_archive}$" /tmp/node-SHASUMS256.txt \
|
||||
| sed "s# ${node_archive}# /tmp/${node_archive}#" \
|
||||
| sha256sum --check --strict -
|
||||
sudo tar -xJf "/tmp/${node_archive}" --directory /usr/local --strip-components=1
|
||||
sh scripts/install-zig.sh "$zig_version"
|
||||
sudo npm install --global "pnpm@${pnpm_version}"
|
||||
|
||||
rm -f "/tmp/${node_archive}" /tmp/node-SHASUMS256.txt /tmp/llvm-snapshot.gpg.key /tmp/llvm-snapshot.gpg
|
||||
@@ -57,4 +59,5 @@ sudo rm -rf /var/lib/apt/lists/*
|
||||
|
||||
node --version
|
||||
pnpm --version
|
||||
zig version
|
||||
clang --version | sed -n '1p'
|
||||
|
||||
@@ -725,7 +725,28 @@ try {
|
||||
// Workspace builds deliberately do not rebuild packaged native artifacts.
|
||||
// Every remote lane needs the Linux helper and runtime from this worktree.
|
||||
await execIn(worker, "pnpm", ["--filter", "@scriptc/llvm-linux-x64-gnu", "build:native"], {}, "LLVM helper", 5 * 60_000);
|
||||
await execIn(worker, "pnpm", ["--filter", "@scriptc/runtime-linux-x64-gnu", "build:native"], { CC: "clang-22", AR: "llvm-ar-22" }, "runtime pack", 5 * 60_000);
|
||||
await execIn(
|
||||
worker,
|
||||
"pnpm",
|
||||
["--filter", "@scriptc/runtime-linux-x64-gnu", "build:native"],
|
||||
{ CC: "zig", AR: "zig" },
|
||||
"runtime pack",
|
||||
5 * 60_000,
|
||||
"/workspace",
|
||||
3 * 60_000,
|
||||
);
|
||||
// Zig is a build-only dependency in this lane. Cross-target suites own
|
||||
// the conditional Zig tests; exposing it here would silently expand the
|
||||
// native-cache shard while that shard deliberately disables stable
|
||||
// toolchain caching.
|
||||
await execIn(
|
||||
worker,
|
||||
"sudo",
|
||||
["rm", "-f", "/usr/local/bin/zig"],
|
||||
{},
|
||||
"runtime toolchain cleanup",
|
||||
60_000,
|
||||
);
|
||||
}, imageConfig.custom ? workers.length : 8);
|
||||
|
||||
await allWorkers("Testing", async (worker) => {
|
||||
|
||||
Reference in New Issue
Block a user