mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-02 08:35:07 +08:00
Expand LLVM native output targets (#280)
* Expand LLVM native output targets - Add owned helper and runtime-pack contracts for macOS x64, Linux glibc/musl, Windows x64, and WASI. - Generalize LLVM target selection, package validation, linker plans, and release/CI matrices. - Document linker boundaries and add focused native-output and runtime-pack coverage. * Pin Windows LLVM helper CI to VS 2022 The official LLVM archive needs the Visual Studio 2022 CMake generator, which is not guaranteed by windows-latest. * Align bootstrap cache with LLVM runtime-pack builds Use the same target-specific helper and linker identity before and after compiler loading so routed executable cache hits remain lightweight. * Install Windows LLVM CI tools with Chocolatey windows-2022 includes Visual Studio but not winget; use its available Chocolatey bootstrap for CMake and Ninja. * Prevent Zig version probes from leaving runtime-pack objects Run runtime-pack compiler version probes in a private temporary directory and remove the accidental tracked WASI a.o file. * Use 7-Zip for Windows LLVM setup Extract the official LLVM development archive with two-stage 7-Zip instead of Windows tar.exe, which timed out while materializing the toolchain tree. * Define ssize_t for the MSVC runtime pack Clang's MSVC target does not expose POSIX ssize_t through sys/types.h; define the pointer-sized runtime type without affecting MinGW. * Build the Windows runtime pack with Zig Use the MinGW-compatible Windows sysroot required by the runtime while retaining COFF helper output and installing Zig in the Windows native CI lane. * Give macOS LLVM differential shard time to finish Shard 1 passed its setup and focused contracts but was cancelled during its cold LLVM differential slice at the 20-minute job limit.
This commit is contained in:
+144
-2
@@ -111,10 +111,61 @@ jobs:
|
||||
pnpm test packages/compiler/test/cc-driver.test.ts
|
||||
--testNamePattern "host-native clang static build"
|
||||
|
||||
llvm_artifacts_linux_x64:
|
||||
name: test (Linux x64 LLVM artifacts, no clang)
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 25
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 11.1.3
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: .node-version
|
||||
cache: pnpm
|
||||
- name: Install pinned LLVM development distribution
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --yes libzstd-dev
|
||||
curl -fL --retry 3 -o "$RUNNER_TEMP/llvm.tar.xz" https://github.com/llvm/llvm-project/releases/download/llvmorg-22.1.8/LLVM-22.1.8-Linux-X64.tar.xz
|
||||
tar -xJf "$RUNNER_TEMP/llvm.tar.xz" -C "$RUNNER_TEMP"
|
||||
mv "$RUNNER_TEMP/LLVM-22.1.8-Linux-X64" "$RUNNER_TEMP/llvm-22.1.8"
|
||||
echo "LLVM_DIR=$RUNNER_TEMP/llvm-22.1.8/lib/cmake/llvm" >> "$GITHUB_ENV"
|
||||
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: pnpm --filter @scriptc/runtime-wasm32-wasi build:native
|
||||
- run: pnpm build
|
||||
- name: Linux helper object format and no-clang output contract
|
||||
run: |
|
||||
PATH="$RUNNER_TEMP/traps:$PATH"
|
||||
mkdir -p "$RUNNER_TEMP/traps"
|
||||
for tool in clang cc gcc ar ld; do printf '#!/bin/sh\nexit 97\n' > "$RUNNER_TEMP/traps/$tool"; chmod +x "$RUNNER_TEMP/traps/$tool"; done
|
||||
node packages/cli/dist/main.js build tests/corpus/001-hello.ts --emit=obj -o "$RUNNER_TEMP/hello.o"
|
||||
file "$RUNNER_TEMP/hello.o" | grep 'ELF 64-bit LSB relocatable, x86-64'
|
||||
- name: Linux helper/runtime-pack executable differential smoke
|
||||
env:
|
||||
SCRIPTC_NO_CACHE: "1"
|
||||
SCRIPTC_LEGACY_C_PIPELINE: "0"
|
||||
run: |
|
||||
node packages/cli/dist/main.js build tests/corpus/001-hello.ts -o "$RUNNER_TEMP/hello"
|
||||
test "$("$RUNNER_TEMP/hello")" = 'hello world'
|
||||
- name: WASI helper object/runtime-pack smoke
|
||||
run: pnpm test packages/cli/test/wasi-runtime-pack.test.ts
|
||||
|
||||
llvm_artifacts_macos_arm64:
|
||||
name: test (macOS arm64 LLVM artifacts, no clang, ${{ matrix.shard }}/3)
|
||||
runs-on: macos-15
|
||||
timeout-minutes: 20
|
||||
# Shard 1 additionally runs package/install and link-parity contracts
|
||||
# before its LLVM differential slice. The slice itself can take ~10
|
||||
# minutes on a cold hosted runner, so 20 minutes cancels an otherwise
|
||||
# healthy job before the differential completes.
|
||||
timeout-minutes: 35
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -191,6 +242,38 @@ jobs:
|
||||
"$RUNNER_TEMP/installed-link.json" "$RUNNER_TEMP/installed-program"
|
||||
test "$("$RUNNER_TEMP/installed-program")" = 'hello world'
|
||||
|
||||
llvm_artifacts_macos_x64:
|
||||
name: test (macOS x64 LLVM artifacts, no clang)
|
||||
runs-on: macos-15-intel
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 11.1.3
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: .node-version
|
||||
cache: pnpm
|
||||
- run: brew install llvm@22
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: LLVM_DIR=/usr/local/opt/llvm@22/lib/cmake/llvm pnpm --filter @scriptc/llvm-darwin-x64 build:native
|
||||
- run: pnpm --filter @scriptc/runtime-darwin-x64 build:native
|
||||
- run: pnpm build
|
||||
- name: Intel Mach-O no-clang object contract
|
||||
run: |
|
||||
mkdir -p "$RUNNER_TEMP/traps"
|
||||
for tool in clang cc gcc ar ld; do printf '#!/bin/sh\nexit 97\n' > "$RUNNER_TEMP/traps/$tool"; chmod +x "$RUNNER_TEMP/traps/$tool"; done
|
||||
PATH="$RUNNER_TEMP/traps:$PATH" node packages/cli/dist/main.js build tests/corpus/001-hello.ts --emit=obj -o "$RUNNER_TEMP/hello.o"
|
||||
file "$RUNNER_TEMP/hello.o" | grep 'Mach-O 64-bit object x86_64'
|
||||
- name: Intel helper/runtime-pack executable smoke
|
||||
env:
|
||||
SCRIPTC_NO_CACHE: "1"
|
||||
SCRIPTC_LEGACY_C_PIPELINE: "0"
|
||||
run: |
|
||||
node packages/cli/dist/main.js build tests/corpus/001-hello.ts -o "$RUNNER_TEMP/hello"
|
||||
test "$($RUNNER_TEMP/hello)" = 'hello world'
|
||||
|
||||
# Exercises the supported Windows GNU target and the built CLI end to end:
|
||||
# TS7 must open its synthetic project, ambient files must resolve across
|
||||
# slash styles, and the default executable must use the .exe suffix.
|
||||
@@ -262,11 +345,67 @@ jobs:
|
||||
pnpm exec vitest run packages/compiler/test/cc-driver.test.ts
|
||||
--testNamePattern "Windows CA roots honor"
|
||||
|
||||
llvm_artifacts_windows_x64:
|
||||
name: test (Windows x64 MSVC LLVM artifacts)
|
||||
# The official LLVM 22 Windows archives are MSVC-built and the helper
|
||||
# selects CMake's VS 2022 generator. `windows-latest` can move to an
|
||||
# image without that generator, so retain the hosted VS 2022 contract.
|
||||
runs-on: windows-2022
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 11.1.3
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: .node-version
|
||||
cache: pnpm
|
||||
- name: Install pinned LLVM development distribution
|
||||
shell: pwsh
|
||||
run: |
|
||||
# windows-2022 already provides CMake, Ninja, VS 2022, and 7-Zip.
|
||||
# Use the complete archive because it supplies LLVM's exported CMake
|
||||
# targets and static libraries. Windows tar.exe takes 25+ minutes to
|
||||
# materialize it; two-stage 7-Zip extraction takes seconds.
|
||||
$archive = "$env:RUNNER_TEMP\clang+llvm-22.1.8-x86_64-pc-windows-msvc.tar.xz"
|
||||
$llvm = "$env:RUNNER_TEMP\llvm-22.1.8"
|
||||
$expanded = "$env:RUNNER_TEMP\llvm-expanded"
|
||||
$sevenZip = "$env:ProgramFiles\7-Zip\7z.exe"
|
||||
if (-not (Test-Path $sevenZip)) {
|
||||
choco install 7zip --no-progress -y
|
||||
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
||||
}
|
||||
if (-not (Test-Path $sevenZip)) { throw "7-Zip is unavailable" }
|
||||
curl.exe -fL --retry 3 -o $archive https://github.com/llvm/llvm-project/releases/download/llvmorg-22.1.8/clang%2Bllvm-22.1.8-x86_64-pc-windows-msvc.tar.xz
|
||||
& $sevenZip x -y "-o$expanded" $archive
|
||||
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
||||
& $sevenZip x -y "-o$expanded" "$expanded\clang+llvm-22.1.8-x86_64-pc-windows-msvc.tar"
|
||||
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
||||
Move-Item "$expanded\clang+llvm-22.1.8-x86_64-pc-windows-msvc" $llvm
|
||||
echo "LLVM_DIR=$llvm\lib\cmake\llvm" >> $env:GITHUB_ENV
|
||||
echo "$llvm\bin" >> $env:GITHUB_PATH
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- name: Build Windows helper
|
||||
run: pnpm --filter @scriptc/llvm-win32-x64-msvc build:native
|
||||
- uses: vercel-labs/setup-zig@v1
|
||||
with:
|
||||
version: 0.16.0
|
||||
- name: Build Windows runtime pack
|
||||
run: pnpm --filter @scriptc/runtime-win32-x64-msvc build:native
|
||||
- run: pnpm build
|
||||
- name: Windows COFF no-clang object contract
|
||||
shell: pwsh
|
||||
run: |
|
||||
node packages/cli/dist/main.js build tests/corpus/001-hello.ts --emit=obj -o "$env:RUNNER_TEMP\hello.obj"
|
||||
$bytes = [System.IO.File]::ReadAllBytes("$env:RUNNER_TEMP\hello.obj")
|
||||
if ($bytes[0] -ne 0x64 -or $bytes[1] -ne 0x86) { throw "expected AMD64 COFF object" }
|
||||
|
||||
# Aggregate gate with the pre-matrix job's name, so anything keyed on the
|
||||
# single "test" check (branch protection, badges) keeps resolving. Fails
|
||||
# unless every matrix shard and both platform integration jobs succeeded.
|
||||
test:
|
||||
needs: [tests, linux_host_clang, llvm_artifacts_macos_arm64, windows_cli]
|
||||
needs: [tests, linux_host_clang, llvm_artifacts_linux_x64, llvm_artifacts_macos_arm64, llvm_artifacts_macos_x64, windows_cli, llvm_artifacts_windows_x64]
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -274,5 +413,8 @@ jobs:
|
||||
run: |
|
||||
test "${{ needs.tests.result }}" = success
|
||||
test "${{ needs.linux_host_clang.result }}" = success
|
||||
test "${{ needs.llvm_artifacts_linux_x64.result }}" = success
|
||||
test "${{ needs.llvm_artifacts_macos_arm64.result }}" = success
|
||||
test "${{ needs.llvm_artifacts_macos_x64.result }}" = success
|
||||
test "${{ needs.windows_cli.result }}" = success
|
||||
test "${{ needs.llvm_artifacts_windows_x64.result }}" = success
|
||||
|
||||
+147
-10
@@ -49,9 +49,133 @@ jobs:
|
||||
fi
|
||||
echo "version=$LOCAL_VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
build-native-packages:
|
||||
name: Build native package (${{ matrix.platform }})
|
||||
needs: check-release
|
||||
if: needs.check-release.outputs.should_release == 'true'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- platform: darwin-arm64
|
||||
runner: macos-15
|
||||
helper: llvm-darwin-arm64
|
||||
runtime: runtime-darwin-arm64
|
||||
- platform: darwin-x64
|
||||
runner: macos-15-intel
|
||||
helper: llvm-darwin-x64
|
||||
runtime: runtime-darwin-x64
|
||||
- platform: linux-x64
|
||||
runner: ubuntu-24.04
|
||||
helper: llvm-linux-x64-gnu
|
||||
runtime: runtime-linux-x64-gnu
|
||||
llvm_asset: LLVM-22.1.8-Linux-X64
|
||||
- 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
|
||||
- platform: windows-x64
|
||||
runner: windows-2022
|
||||
helper: llvm-win32-x64-msvc
|
||||
runtime: runtime-win32-x64-msvc
|
||||
use_zig: true
|
||||
- platform: linux-x64-musl
|
||||
runner: ubuntu-24.04
|
||||
helper: llvm-linux-x64-musl
|
||||
runtime: runtime-linux-x64-musl
|
||||
llvm_asset: LLVM-22.1.8-Linux-X64
|
||||
use_zig: true
|
||||
- platform: linux-arm64-musl
|
||||
runner: ubuntu-24.04-arm
|
||||
helper: llvm-linux-arm64-musl
|
||||
runtime: runtime-linux-arm64-musl
|
||||
llvm_asset: LLVM-22.1.8-Linux-ARM64
|
||||
use_zig: true
|
||||
- platform: wasm32-wasi
|
||||
runner: ubuntu-24.04
|
||||
helper: llvm-linux-x64-gnu
|
||||
runtime: runtime-wasm32-wasi
|
||||
llvm_asset: LLVM-22.1.8-Linux-X64
|
||||
use_zig: true
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 11.1.3
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "24"
|
||||
cache: pnpm
|
||||
- name: Install toolchain (macOS)
|
||||
if: startsWith(matrix.platform, 'darwin')
|
||||
run: brew install llvm@22
|
||||
- name: Install pinned LLVM development distribution (Linux)
|
||||
if: startsWith(matrix.platform, 'linux') || matrix.platform == 'wasm32-wasi'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --yes libzstd-dev
|
||||
curl -fL --retry 3 -o "$RUNNER_TEMP/llvm.tar.xz" "https://github.com/llvm/llvm-project/releases/download/llvmorg-22.1.8/${{ matrix.llvm_asset }}.tar.xz"
|
||||
tar -xJf "$RUNNER_TEMP/llvm.tar.xz" -C "$RUNNER_TEMP"
|
||||
mv "$RUNNER_TEMP/${{ matrix.llvm_asset }}" "$RUNNER_TEMP/llvm-22.1.8"
|
||||
echo "LLVM_DIR=$RUNNER_TEMP/llvm-22.1.8/lib/cmake/llvm" >> "$GITHUB_ENV"
|
||||
echo "$RUNNER_TEMP/llvm-22.1.8/bin" >> "$GITHUB_PATH"
|
||||
- uses: vercel-labs/setup-zig@v1
|
||||
if: matrix.use_zig == true
|
||||
with:
|
||||
version: 0.16.0
|
||||
- name: Install pinned LLVM development distribution (Windows)
|
||||
if: matrix.platform == 'windows-x64'
|
||||
shell: pwsh
|
||||
run: |
|
||||
# The complete archive supplies LLVM's exported CMake targets and
|
||||
# static libraries. windows-2022 includes CMake, Ninja, VS 2022,
|
||||
# and 7-Zip; unlike tar.exe, 7-Zip expands this archive quickly.
|
||||
$archive = "$env:RUNNER_TEMP\clang+llvm-22.1.8-x86_64-pc-windows-msvc.tar.xz"
|
||||
$llvm = "$env:RUNNER_TEMP\llvm-22.1.8"
|
||||
$expanded = "$env:RUNNER_TEMP\llvm-expanded"
|
||||
$sevenZip = "$env:ProgramFiles\7-Zip\7z.exe"
|
||||
if (-not (Test-Path $sevenZip)) {
|
||||
choco install 7zip --no-progress -y
|
||||
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
||||
}
|
||||
if (-not (Test-Path $sevenZip)) { throw "7-Zip is unavailable" }
|
||||
curl.exe -fL --retry 3 -o $archive https://github.com/llvm/llvm-project/releases/download/llvmorg-22.1.8/clang%2Bllvm-22.1.8-x86_64-pc-windows-msvc.tar.xz
|
||||
& $sevenZip x -y "-o$expanded" $archive
|
||||
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
||||
& $sevenZip x -y "-o$expanded" "$expanded\clang+llvm-22.1.8-x86_64-pc-windows-msvc.tar"
|
||||
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
||||
Move-Item "$expanded\clang+llvm-22.1.8-x86_64-pc-windows-msvc" $llvm
|
||||
echo "LLVM_DIR=$llvm\lib\cmake\llvm" >> $env:GITHUB_ENV
|
||||
echo "$llvm\bin" >> $env:GITHUB_PATH
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- name: Build native packages (POSIX)
|
||||
if: matrix.platform != 'windows-x64'
|
||||
run: |
|
||||
pnpm --filter @scriptc/${{ matrix.helper }} build:native
|
||||
if [ "${{ matrix.use_zig }}" = true ]; then
|
||||
CC=zig AR=zig pnpm --filter @scriptc/${{ matrix.runtime }} build:native
|
||||
else
|
||||
CC=clang AR=llvm-ar pnpm --filter @scriptc/${{ matrix.runtime }} build:native
|
||||
fi
|
||||
- name: Build native packages (Windows)
|
||||
if: matrix.platform == 'windows-x64'
|
||||
run: |
|
||||
pnpm --filter @scriptc/${{ matrix.helper }} build:native
|
||||
pnpm --filter @scriptc/${{ matrix.runtime }} build:native
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: native-${{ matrix.platform }}
|
||||
path: |
|
||||
packages/${{ matrix.helper }}
|
||||
packages/${{ matrix.runtime }}
|
||||
retention-days: 1
|
||||
|
||||
publish:
|
||||
name: Publish to npm
|
||||
needs: check-release
|
||||
needs: [check-release, build-native-packages]
|
||||
if: needs.check-release.outputs.should_release == 'true'
|
||||
runs-on: macos-15
|
||||
timeout-minutes: 15
|
||||
@@ -63,6 +187,13 @@ jobs:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download native packages
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: native-*
|
||||
path: native-artifacts
|
||||
merge-multiple: true
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
@@ -74,14 +205,10 @@ jobs:
|
||||
node-version: "24"
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
|
||||
- name: Install pinned LLVM
|
||||
run: brew install llvm@22
|
||||
|
||||
# Publishing uses npm trusted publishing (OIDC): the job's id-token
|
||||
# permission lets npm mint short-lived credentials, so no npm token
|
||||
# secret exists anywhere in this repo. All five packages —
|
||||
# @scriptc/runtime, @scriptc/runtime-darwin-arm64,
|
||||
# @scriptc/llvm-darwin-arm64, @scriptc/compiler, and scriptc — must each be
|
||||
# secret exists anywhere in this repo. The runtime, every shipped
|
||||
# platform runtime/helper package, compiler, and CLI must each be
|
||||
# configured on npmjs.com with a GitHub Actions trusted publisher
|
||||
# pointing at repository vercel-labs/scriptc, workflow release.yml,
|
||||
# environment Release. A package missing that configuration fails
|
||||
@@ -91,14 +218,13 @@ jobs:
|
||||
- name: Install and build
|
||||
run: |
|
||||
pnpm install --frozen-lockfile
|
||||
pnpm --filter @scriptc/llvm-darwin-arm64 build:native
|
||||
pnpm --filter @scriptc/runtime-darwin-arm64 build:native
|
||||
cp -R native-artifacts/. packages/
|
||||
pnpm -r build
|
||||
|
||||
- name: Check version sync
|
||||
run: |
|
||||
VERSION="${{ needs.check-release.outputs.version }}"
|
||||
for pkg in packages/runtime packages/runtime-darwin-arm64 packages/llvm-darwin-arm64 packages/compiler packages/cli; do
|
||||
for pkg in packages/runtime packages/runtime-darwin-arm64 packages/llvm-darwin-arm64 packages/runtime-linux-x64-gnu packages/llvm-linux-x64-gnu packages/runtime-linux-arm64-gnu packages/llvm-linux-arm64-gnu packages/runtime-linux-x64-musl packages/llvm-linux-x64-musl packages/runtime-linux-arm64-musl packages/llvm-linux-arm64-musl packages/runtime-wasm32-wasi packages/runtime-win32-x64-msvc packages/llvm-win32-x64-msvc packages/compiler packages/cli; do
|
||||
V=$(node -p "require('./$pkg/package.json').version")
|
||||
if [ "$V" != "$VERSION" ]; then
|
||||
echo "Version mismatch: $pkg is $V, expected $VERSION"
|
||||
@@ -152,6 +278,17 @@ jobs:
|
||||
publish_dir packages/runtime
|
||||
publish_dir packages/runtime-darwin-arm64
|
||||
publish_dir packages/llvm-darwin-arm64 "$HELPER_TARBALL"
|
||||
publish_dir packages/runtime-linux-x64-gnu
|
||||
publish_dir packages/llvm-linux-x64-gnu
|
||||
publish_dir packages/runtime-linux-arm64-gnu
|
||||
publish_dir packages/llvm-linux-arm64-gnu
|
||||
publish_dir packages/runtime-linux-x64-musl
|
||||
publish_dir packages/llvm-linux-x64-musl
|
||||
publish_dir packages/runtime-linux-arm64-musl
|
||||
publish_dir packages/llvm-linux-arm64-musl
|
||||
publish_dir packages/runtime-wasm32-wasi
|
||||
publish_dir packages/runtime-win32-x64-msvc
|
||||
publish_dir packages/llvm-win32-x64-msvc
|
||||
publish_dir packages/compiler
|
||||
publish_dir packages/cli
|
||||
env:
|
||||
|
||||
@@ -18,6 +18,10 @@ dist/
|
||||
/packages/runtime-darwin-arm64/artifacts/
|
||||
/packages/runtime-darwin-arm64/runtime-pack.json
|
||||
/packages/runtime-darwin-arm64/.runtime-pack-*
|
||||
/packages/llvm-*/bin/
|
||||
/packages/runtime-*/artifacts/
|
||||
/packages/runtime-*/runtime-pack.json
|
||||
/packages/runtime-*/.runtime-pack-*
|
||||
!tests/fixtures/fetch/node_modules/eventsource-parser/dist/
|
||||
!tests/fixtures/npm/node_modules/*/dist/
|
||||
!tests/fixtures/npm/workspace/*/dist/
|
||||
|
||||
@@ -9,12 +9,12 @@ 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 macOS native artifacts.
|
||||
The ordinary workspace build does not rebuild packaged native artifacts.
|
||||
When changing native assembly/object emission or runtime-pack selection,
|
||||
install CMake, Ninja, and Homebrew `llvm@22`, then run
|
||||
`pnpm --filter @scriptc/llvm-darwin-arm64 build:native` and
|
||||
`pnpm --filter @scriptc/runtime-darwin-arm64 build:native` explicitly. The
|
||||
macOS full test suite also needs those generated artifacts.
|
||||
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.
|
||||
|
||||
Use focused local tests while iterating, then use `pnpm test:sandbox` whenever a
|
||||
full validation gate is required. It loads Sandbox configuration from the
|
||||
|
||||
@@ -8,7 +8,7 @@ scriptc is experimental and targets macOS, Linux, Windows, and WebAssembly via W
|
||||
|
||||
## Installation
|
||||
|
||||
The compiler requires Node.js 24 or newer. `--emit=ir|c|llvm` needs only Node. On macOS 15+ arm64, `--emit=asm|obj` additionally uses the optional platform helper installed with scriptc, but needs no compiler, archiver, linker, or SDK. Ordinary LLVM-tier executable builds need a platform linker driver and SDK, but use the bundled helper plus precompiled runtime pack rather than compiling generated or runtime C. Set `SCRIPTC_LINKER` to choose that driver. Explicit C builds, LLVM fallbacks, `--sanitize`, and the deprecated `SCRIPTC_CC=clang|zigcc` compatibility route additionally need a C compiler. The executables it produces do not require Node.
|
||||
The compiler requires Node.js 24 or newer. `--emit=ir|c|llvm` needs only Node. `--emit=asm|obj` uses the matching optional platform helper installed with scriptc on supported macOS, Linux, and Windows hosts (and for WASI), but needs no compiler, archiver, linker, or SDK. Ordinary LLVM-tier executable builds need a platform linker driver and SDK/sysroot, but use the bundled helper plus precompiled runtime pack rather than compiling generated or runtime C. Set `SCRIPTC_LINKER` to choose that driver. Explicit C builds, LLVM fallbacks, `--sanitize`, and the deprecated `SCRIPTC_CC=clang|zigcc` compatibility route additionally need a C compiler. The executables it produces do not require Node.
|
||||
|
||||
```console
|
||||
$ npm install -g scriptc
|
||||
@@ -153,12 +153,11 @@ $ vercel link && vercel env pull # writes a project-scoped VERCEL_OIDC_TOKEN
|
||||
$ pnpm test:sandbox
|
||||
```
|
||||
|
||||
The normal workspace build needs no local LLVM installation. To rebuild the
|
||||
optional macOS arm64 native artifacts, install CMake, Ninja, and Homebrew
|
||||
`llvm@22`, then run
|
||||
`pnpm --filter @scriptc/llvm-darwin-arm64 build:native` and
|
||||
`pnpm --filter @scriptc/runtime-darwin-arm64 build:native`. The macOS full test
|
||||
suite also uses those generated artifacts.
|
||||
The normal workspace build needs no local LLVM installation. To rebuild a
|
||||
native helper/runtime pack, install CMake, Ninja, and the pinned LLVM 22
|
||||
development package on that target host, then run the matching
|
||||
`@scriptc/llvm-<platform>` and `@scriptc/runtime-<platform>` `build:native`
|
||||
scripts. The macOS full test suite also uses those generated artifacts.
|
||||
|
||||
`pnpm test:sandbox` loads `.env.local`, preflights Vercel authentication and
|
||||
project access, and uses the managed `vercel/sandbox/universal` image by
|
||||
|
||||
+6
-6
@@ -1,21 +1,21 @@
|
||||
# Releasing
|
||||
|
||||
Releases are manual, single-commit affairs. The maintainer controls the changelog voice and format. The five npm packages — `@scriptc/runtime`, `@scriptc/runtime-darwin-arm64`, `@scriptc/llvm-darwin-arm64`, `@scriptc/compiler`, and `scriptc` — always publish together at the same version.
|
||||
Releases are manual, single-commit affairs. The maintainer controls the changelog voice and format. `@scriptc/runtime`, every platform helper/runtime pack, `@scriptc/compiler`, and `scriptc` always publish together at the same version.
|
||||
|
||||
To prepare a release:
|
||||
|
||||
1. Bump the version in `packages/cli/package.json`
|
||||
2. Run `node scripts/sync-versions.mjs` to stamp the same version into `packages/runtime`, `packages/runtime-darwin-arm64`, `packages/llvm-darwin-arm64`, and `packages/compiler`, then `pnpm manifest` to restamp `packages/compiler/surface-manifest.json` with the new version, and commit both (the test suite's staleness guard fails on a version drift)
|
||||
2. Run `node scripts/sync-versions.mjs` to stamp the same version into the runtime, helper, and compiler packages, then `pnpm manifest` to restamp `packages/compiler/surface-manifest.json` with the new version, and commit both (the test suite's staleness guard fails on a version drift)
|
||||
3. Fold the `## Unreleased` section of `CHANGELOG.md` into a new `## <version>` entry (newest first, below `## Unreleased`), and leave `## Unreleased` empty for the next cycle
|
||||
4. Wrap the new entry in `<!-- release:start -->` and `<!-- release:end -->` markers; this marked block is also the GitHub release body
|
||||
5. Remove the `<!-- release:start -->` and `<!-- release:end -->` markers from the previous release entry; only the latest release should have markers
|
||||
6. With Zig on `PATH`, run `SCRIPTC_CROSS=1 pnpm exec vitest run tests/harness/library-cross.test.ts` and require the cross-target library conformance lane to pass
|
||||
7. Commit to `main`
|
||||
|
||||
CI (`.github/workflows/release.yml`) compares the version in `packages/cli/package.json` to what `scriptc` has on npm. If it differs, it builds the workspace, verifies all five package versions match (a mismatch fails with a hint to run `scripts/sync-versions.mjs`), and publishes to npm in dependency order — `@scriptc/runtime`, `@scriptc/runtime-darwin-arm64`, `@scriptc/llvm-darwin-arm64`, `@scriptc/compiler`, then `scriptc` — so each package's dependencies are resolvable the moment it lands. After the publish succeeds, a separate job creates the git tag `v<version>` and the GitHub release with the marked changelog entry as its body, and attaches `surface-manifest.json` — the machine-readable listing of the surface the static tier compiles at that version (stable per-entry ids, so two releases diff mechanically; see `packages/compiler/src/coverage/surface-manifest.ts` for the schema). The job regenerates the manifest from the tree and fails on any byte difference from the committed file before attaching, so the asset is always the manifest of the code being released. The same file ships inside the `@scriptc/compiler` package as `@scriptc/compiler/surface-manifest.json`.
|
||||
CI (`.github/workflows/release.yml`) compares the version in `packages/cli/package.json` to what `scriptc` has on npm. If it differs, it builds platform packages on matching macOS, Linux, and Windows runners, verifies the version spine, and publishes the runtime, helper, compiler, and CLI packages in dependency order. After the publish succeeds, a separate job creates the git tag `v<version>` and the GitHub release with the marked changelog entry as its body, and attaches `surface-manifest.json` — the machine-readable listing of the surface the static tier compiles at that version (stable per-entry ids, so two releases diff mechanically; see `packages/compiler/src/coverage/surface-manifest.ts` for the schema). The job regenerates the manifest from the tree and fails on any byte difference from the committed file before attaching, so the asset is always the manifest of the code being released. The same file ships inside the `@scriptc/compiler` package as `@scriptc/compiler/surface-manifest.json`.
|
||||
|
||||
The release job runs on macOS arm64, builds and strips the pinned LLVM helper,
|
||||
then builds the matching precompiled runtime pack before publishing both
|
||||
The release job builds and strips each pinned LLVM helper on its matching host,
|
||||
then builds the matching precompiled runtime pack before publishing the
|
||||
constrained platform packages ahead of `@scriptc/compiler`. Ordinary LLVM-tier
|
||||
executables use the helper for the program object and the platform pack for
|
||||
runtime objects; the user's toolchain performs only the final platform link.
|
||||
@@ -25,7 +25,7 @@ platform pack is available. The GitHub release remains a tag, release notes, and
|
||||
manifest asset; the npm publish never waits on the GitHub release.
|
||||
|
||||
Publishing uses npm trusted publishing (OIDC) — there is no npm token secret.
|
||||
Each of the five packages must have a GitHub Actions trusted publisher for
|
||||
Each published package must have a GitHub Actions trusted publisher for
|
||||
`release.yml` and the `Release` environment. A missing configuration fails
|
||||
before upload. Re-runs skip package versions already present on npm, so a
|
||||
partially published release can be resumed safely.
|
||||
|
||||
@@ -90,7 +90,7 @@ Prebuilds release runtime objects and native TLS/dynamic-engine archives for tar
|
||||
<dd>Primary artifact path. An explicit path is exact. Defaults are <code>.scriptc/<name>.ir.json</code>, <code>.c</code>, <code>.ll</code>, <code>.s</code>, <code>.o</code>, or the platform executable name.</dd>
|
||||
|
||||
<dt><code>--emit <ir|c|llvm|asm|obj|exe></code></dt>
|
||||
<dd>Select the invocation's one primary artifact. <code>ir</code>, <code>c</code>, and <code>llvm</code> need only Node. <code>asm</code> and <code>obj</code> use the bundled LLVM helper on macOS 15+ arm64 and emit artifacts targeting macOS 14.0. <code>exe</code> is the default.</dd>
|
||||
<dd>Select the invocation's one primary artifact. <code>ir</code>, <code>c</code>, and <code>llvm</code> need only Node. <code>asm</code> and <code>obj</code> use a matching bundled LLVM helper on supported macOS, Linux, and Windows hosts and for WASI; they need no installed C compiler. <code>exe</code> is the default.</dd>
|
||||
|
||||
<dt><code>--print <native-link-info></code></dt>
|
||||
<dd>Build an object (equivalent to <code>--emit=obj</code>) and print its machine-readable external link recipe as JSON instead of printing the artifact path. The document names the exact installed source runtime pack and all link inputs, but does not invoke a linker.</dd>
|
||||
@@ -102,7 +102,7 @@ Prebuilds release runtime objects and native TLS/dynamic-engine archives for tar
|
||||
<dd>Bind signature-only TypeScript declarations to native C ABI symbols and link the manifest's archive, object, and system-library inputs. See <a href="/ffi">Native FFI</a>.</dd>
|
||||
|
||||
<dt><code>--backend <c|llvm></code></dt>
|
||||
<dd>Code generator: <code>llvm</code> (default) or <code>c</code> (the readable debugging backend). On macOS arm64, LLVM-tier executable code generation uses the bundled helper and precompiled runtime pack before the platform link. Unset, a native build can fall back to C when the program is outside the LLVM tier. The production <code>wasm32-wasi</code> target never falls back: a missing LLVM lowering is <code>SC3001</code>.</dd>
|
||||
<dd>Code generator: <code>llvm</code> (default) or <code>c</code> (the readable debugging backend). On supported targets, LLVM-tier executable code generation uses the bundled helper and precompiled runtime pack before the platform link. Unset, a native build can fall back to C when the program is outside the LLVM tier. The production <code>wasm32-wasi</code> target never falls back: a missing LLVM lowering is <code>SC3001</code>.</dd>
|
||||
|
||||
<dt><code>--npm-static <pkg[,pkg…]|auto></code></dt>
|
||||
<dd>EXPERIMENTAL. Compile the named npm packages' shipped JS statically as program modules instead of embedding them for the engine (repeatable; <code>auto</code> opts in every eligible direct import). A package the preflight refuses falls back to the island with a coverage-report note. See <a href="/dependencies">npm Dependencies</a> for maturity notes.</dd>
|
||||
@@ -159,7 +159,7 @@ fib-linux: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically
|
||||
|
||||
## Backends
|
||||
|
||||
The default backend emits textual LLVM IR. On macOS arm64 it is lowered to an object by the bundled helper and linked with the precompiled runtime pack; <code>SCRIPTC_LINKER</code> controls the platform linker driver, separately from C compilation. Other executable targets retain their existing toolchain path. A program outside the LLVM tier is never miscompiled—the native build falls back to the C backend transparently and says so in one stderr line. The production <code>wasm32-wasi</code> target uses LLVM's 32-bit ABI path and never falls back; an LLVM coverage gap is a build diagnostic. Dynamic npm embedding is LLVM surface on every target.
|
||||
The default backend emits textual LLVM IR. On supported targets it is lowered to an object by the bundled helper and linked with the matching precompiled runtime pack; <code>SCRIPTC_LINKER</code> controls the platform linker driver, separately from C compilation. A program outside the LLVM tier is never miscompiled—the native build falls back to the C backend transparently and says so in one stderr line. The production <code>wasm32-wasi</code> target uses LLVM's 32-bit ABI path and never falls back; an LLVM coverage gap is a build diagnostic. Dynamic npm embedding is LLVM surface on every target.
|
||||
|
||||
The C backend is a debugging aid: deliberately readable, source-line-annotated output with differential tests against LLVM wherever the two overlap. Pin it when you want to inspect what your program became:
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ TypeScript ──tsc: parse + typecheck──▶ lowering ──▶ typed IR ─
|
||||
|
||||
1. **Frontend** — the real TypeScript compiler parses and type-checks your program against `es2025` (plus `@types/node` when your project has it), honoring your `tsconfig.json` for checker strictness. The frontend then lowers the checked AST into a typed intermediate representation, using tsc's own type and narrowing answers to drive every decision. A construct with no lowering is a precise diagnostic at this stage — never a miscompile later.
|
||||
2. **Typed IR** — the only interface between the ends: a validated, serializable representation (`--emit=ir` writes it as JSON and stops). Types are concrete here; generics have been monomorphized, unions are tagged values, closures have explicit captures.
|
||||
3. **Backends** — `--emit=c` writes readable C and stops; `--emit=llvm` writes textual LLVM IR and stops. Neither source-output command discovers or invokes a native toolchain. On macOS 15+ arm64, `--emit=asm|obj` sends LLVM IR to a version-matched out-of-process helper linked to LLVM 22; it needs no clang or linker and emits macOS 14-targeted artifacts. Executable builds default to LLVM and can fall back to C on a native program outside the LLVM tier (one stderr note; `--backend llvm` pins it and fails with a diagnostic instead). The production <code>wasm32-wasi</code> target never falls back.
|
||||
4. **Link** — on macOS arm64 the release packages contain one precompiled object per runtime feature unit plus QuickJS, libregexp, zlib, and mbedTLS archives. A hashed manifest maps IR feature gates to an ordered typed link plan, so binaries still pay only for what they use. The user needs a platform linker and SDK, but ordinary LLVM-tier builds compile no C. AddressSanitizer, explicit C builds, and LLVM refusals keep the external C-toolchain path.
|
||||
3. **Backends** — `--emit=c` writes readable C and stops; `--emit=llvm` writes textual LLVM IR and stops. Neither source-output command discovers or invokes a native toolchain. On supported macOS, Linux, and Windows hosts (and for WASI), `--emit=asm|obj` sends LLVM IR to a version-matched out-of-process LLVM 22 helper; it needs no clang or linker. Executable builds default to LLVM and can fall back to C on a native program outside the LLVM tier (one stderr note; `--backend llvm` pins it and fails with a diagnostic instead). The production <code>wasm32-wasi</code> target never falls back.
|
||||
4. **Link** — release packages contain one precompiled object per runtime feature unit plus QuickJS, libregexp, zlib, and mbedTLS archives for every supported target. A hashed manifest maps IR feature gates to an ordered typed link plan, so binaries still pay only for what they use. The user needs the target platform linker and SDK/sysroot, but ordinary LLVM-tier builds compile no C. AddressSanitizer, explicit C builds, and LLVM refusals keep the external C-toolchain path.
|
||||
|
||||
Program objects define <code>main</code> and leave their selected
|
||||
<code>scr_*</code> runtime functions undefined. The
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Native Program Objects
|
||||
|
||||
`scriptc build --emit=obj` produces one relocatable macOS arm64 program
|
||||
object without invoking clang, a linker, or an SDK. The object defines
|
||||
`scriptc build --emit=obj` produces one relocatable program object without
|
||||
invoking clang, a linker, or an SDK on a supported target. The object defines
|
||||
`main`; it is intended to become the program in an external native link. It
|
||||
is not a host-callable library—use `scriptc build --lib --profile ...` for
|
||||
that interface.
|
||||
@@ -59,9 +59,12 @@ $ ./app-cc
|
||||
42
|
||||
```
|
||||
|
||||
The script compiles each reported source set and gives clang only the link
|
||||
inputs and system libraries from the document. `--emit=obj` itself remains
|
||||
clang-free; this compiler invocation belongs to the external runtime build.
|
||||
The script is the macOS external-link example: it compiles each reported
|
||||
source set and gives clang only the link inputs and system libraries from the
|
||||
document. `--emit=obj` itself remains clang-free; this compiler invocation
|
||||
belongs to the external runtime build. Linux objects need the target glibc or
|
||||
musl linker/sysroot; Windows MSVC objects need the Windows SDK/MSVC CRT; WASI
|
||||
objects need a Preview 1 linker/sysroot.
|
||||
|
||||
## Native Apple linker
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Platform Support
|
||||
|
||||
## macOS (arm64)
|
||||
## Owned LLVM targets
|
||||
|
||||
The primary platform. Source artifacts selected with <code>--emit=ir|c|llvm</code> need only Node. On macOS 15+ arm64, <code>--emit=asm|obj</code> uses the version-matched <code>@scriptc/llvm-darwin-arm64</code> helper installed with scriptc, emits <code>arm64-apple-macosx14.0.0</code> artifacts, and does not invoke a compiler, archiver, linker, or SDK. Ordinary LLVM-tier executables additionally need the Xcode platform linker/SDK; the helper emits the program object and the packaged runtime supplies objects/archives, so <code>clang</code> is only a linker driver (selectable with <code>SCRIPTC_LINKER</code>) and compiles neither program nor runtime C. Explicit C builds, LLVM fallbacks, and <code>--sanitize</code> still require a C compiler. Object output retains undefined runtime references and is not a library archive. The full executable surface is supported: the language, the stdlib, the Node API surface including the server stack, `--dynamic`, and the sanitizer lane.
|
||||
Source artifacts selected with <code>--emit=ir|c|llvm</code> need only Node. On supported hosts, <code>--emit=asm|obj</code> uses the version-matched platform helper installed with scriptc and does not invoke a compiler, archiver, linker, or SDK. Supported assembly/object targets are macOS arm64/x64 (macOS 14.0 artifacts; helper needs macOS 15+), Linux x64/arm64 glibc, Windows x64 MSVC, Linux x64/arm64 musl, and WASI Preview 1. Ordinary LLVM-tier executables additionally need the platform linker and SDK/sysroot; the helper emits the program object and the packaged runtime supplies objects/archives, so that driver compiles neither program nor runtime C. Explicit C builds, LLVM fallbacks, and <code>--sanitize</code> still require a C compiler. Object output retains undefined runtime references and is not a library archive.
|
||||
|
||||
## Cross-compilation via zig
|
||||
|
||||
@@ -83,19 +83,19 @@ The remaining executable boundary is host capability, not language coverage. WAS
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>macOS arm64</td>
|
||||
<td>native</td>
|
||||
<td>Primary: full surface, <code>--dynamic</code>, sanitizer lane</td>
|
||||
<td>macOS arm64 / x64</td>
|
||||
<td>native host helper + runtime pack</td>
|
||||
<td>Full surface, <code>--dynamic</code>, sanitizer lane (external C route)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Linux arm64 / x86_64</td>
|
||||
<td><code>SCRIPTC_CC=zigcc SCRIPTC_TARGET=<arch>-linux-gnu.2.36</code> or <code><arch>-linux-musl</code></td>
|
||||
<td>Static and dynamic surfaces incl. servers, TLS, fetch, fs.watch, and child_process; verified against Linux Node on Bookworm and Alpine</td>
|
||||
<td>native host helper + runtime pack; <code>SCRIPTC_TARGET=<arch>-linux-musl</code> selects musl</td>
|
||||
<td>Static and dynamic surfaces incl. servers, TLS, fetch, fs.watch, and child_process; executable linking needs the matching libc/sysroot</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Windows x86_64</td>
|
||||
<td><code>SCRIPTC_CC=zigcc SCRIPTC_TARGET=x86_64-windows-gnu</code></td>
|
||||
<td>Static and dynamic surfaces incl. servers, TLS, fetch, and child_process; verified against Windows Node</td>
|
||||
<td>native x64 MSVC helper + runtime pack</td>
|
||||
<td>Static and dynamic surfaces incl. servers, TLS, fetch, and child_process; executable linking needs the Windows SDK/MSVC CRT</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>iOS arm64 (device and simulator)</td>
|
||||
@@ -109,7 +109,7 @@ The remaining executable boundary is host capability, not language coverage. WAS
|
||||
</tr>
|
||||
<tr>
|
||||
<td>WebAssembly / WASI Preview 1</td>
|
||||
<td><code>SCRIPTC_CC=zigcc SCRIPTC_TARGET=wasm32-wasi</code></td>
|
||||
<td>matching host helper + WASI runtime pack</td>
|
||||
<td>Production LLVM target; full language and dynamic tiers, bounded by WASI P1 host capabilities</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
@@ -1,10 +1,24 @@
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
|
||||
set(SCRIPTC_PACKAGE_VERSION "0.0.0-dev" CACHE STRING
|
||||
"scriptc npm package version reported by the helper protocol")
|
||||
set(SCRIPTC_DEFAULT_TARGET "arm64-apple-macosx14.0.0" CACHE STRING
|
||||
"Default target reported by the helper protocol")
|
||||
set(SCRIPTC_DEFAULT_DATA_LAYOUT
|
||||
"e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32"
|
||||
CACHE STRING "Data layout for SCRIPTC_DEFAULT_TARGET")
|
||||
set(SCRIPTC_TARGET_BACKENDS "AArch64" CACHE STRING
|
||||
"Semicolon-separated LLVM target backends compiled into the helper")
|
||||
set(SCRIPTC_ALLOWED_TARGETS "arm64-apple-macosx14.0.0" CACHE STRING
|
||||
"Comma-separated target triples accepted by this helper")
|
||||
set(SCRIPTC_HELPER_ARCH "arm64" CACHE STRING
|
||||
"macOS architecture of the helper executable")
|
||||
|
||||
# These must be cache variables before project() enables the Apple toolchain.
|
||||
# A target property named OSX_DEPLOYMENT_TARGET is not recognized by CMake and
|
||||
# silently leaves the executable at the build host/SDK's deployment version.
|
||||
if(CMAKE_HOST_APPLE)
|
||||
set(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING
|
||||
if(APPLE)
|
||||
set(CMAKE_OSX_ARCHITECTURES "${SCRIPTC_HELPER_ARCH}" CACHE STRING
|
||||
"Architectures for the macOS helper" FORCE)
|
||||
# Homebrew's pinned LLVM 22 bottle is built for macOS 15. The helper must
|
||||
# tell the truth about that host requirement; the objects it emits retain
|
||||
@@ -15,10 +29,12 @@ endif()
|
||||
|
||||
project(scriptc_llvm_codegen LANGUAGES C CXX)
|
||||
|
||||
find_package(LLVM 22.1.8 EXACT REQUIRED CONFIG)
|
||||
# Official LLVM binary distributions retain zstd as an imported dependency in
|
||||
# LLVMSupport. Resolve it before loading LLVM's exported targets so CMake never
|
||||
# leaves an unresolved `zstd::libzstd_static` edge on Linux or Windows.
|
||||
find_package(zstd CONFIG QUIET)
|
||||
|
||||
set(SCRIPTC_PACKAGE_VERSION "0.0.0-dev" CACHE STRING
|
||||
"scriptc npm package version reported by the helper protocol")
|
||||
find_package(LLVM 22.1.8 EXACT REQUIRED CONFIG)
|
||||
|
||||
# LLVM's exported Support target names zstd's shared target even when the
|
||||
# selected LLVM components are static. The npm sidecar must not retain a
|
||||
@@ -49,9 +65,47 @@ target_compile_definitions(scriptc-llvm-codegen PRIVATE
|
||||
${LLVM_DEFINITIONS}
|
||||
SCRIPTC_PACKAGE_VERSION="${SCRIPTC_PACKAGE_VERSION}"
|
||||
)
|
||||
# The official Linux and Windows LLVM archives are commonly built with RTTI
|
||||
# disabled. Mixing RTTI modes turns otherwise ordinary virtual typeinfo into
|
||||
# an unresolved link symbol when the helper links those static components.
|
||||
if(NOT LLVM_ENABLE_RTTI)
|
||||
if(MSVC)
|
||||
target_compile_options(scriptc-llvm-codegen PRIVATE /GR-)
|
||||
else()
|
||||
target_compile_options(scriptc-llvm-codegen PRIVATE -fno-rtti)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
foreach(SCRIPTC_TARGET_BACKEND IN LISTS SCRIPTC_TARGET_BACKENDS)
|
||||
if(SCRIPTC_TARGET_BACKEND STREQUAL "AArch64")
|
||||
list(APPEND SCRIPTC_LLVM_TARGET_LIBS AArch64CodeGen)
|
||||
target_compile_definitions(scriptc-llvm-codegen PRIVATE SCRIPTC_ENABLE_AARCH64=1)
|
||||
elseif(SCRIPTC_TARGET_BACKEND STREQUAL "X86")
|
||||
list(APPEND SCRIPTC_LLVM_TARGET_LIBS X86CodeGen)
|
||||
target_compile_definitions(scriptc-llvm-codegen PRIVATE SCRIPTC_ENABLE_X86=1)
|
||||
elseif(SCRIPTC_TARGET_BACKEND STREQUAL "WebAssembly")
|
||||
list(APPEND SCRIPTC_LLVM_TARGET_LIBS WebAssemblyCodeGen)
|
||||
target_compile_definitions(scriptc-llvm-codegen PRIVATE SCRIPTC_ENABLE_WEBASSEMBLY=1)
|
||||
else()
|
||||
message(FATAL_ERROR "unsupported SCRIPTC_TARGET_BACKENDS entry: ${SCRIPTC_TARGET_BACKEND}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# The WebAssembly target machine emits either an object or final wasm module,
|
||||
# but LLVM's normal `CodeGen` component remains the shared driver interface.
|
||||
# Keep the backend list canonical in the protocol rather than relying on the
|
||||
# host's installed LLVM target registry.
|
||||
|
||||
string(REPLACE ";" "," SCRIPTC_TARGET_BACKENDS_JSON "${SCRIPTC_TARGET_BACKENDS}")
|
||||
target_compile_definitions(scriptc-llvm-codegen PRIVATE
|
||||
SCRIPTC_DEFAULT_TARGET="${SCRIPTC_DEFAULT_TARGET}"
|
||||
SCRIPTC_DEFAULT_DATA_LAYOUT="${SCRIPTC_DEFAULT_DATA_LAYOUT}"
|
||||
SCRIPTC_TARGET_BACKENDS="${SCRIPTC_TARGET_BACKENDS_JSON}"
|
||||
SCRIPTC_ALLOWED_TARGETS="${SCRIPTC_ALLOWED_TARGETS}"
|
||||
)
|
||||
|
||||
llvm_map_components_to_libnames(SCRIPTC_LLVM_LIBS
|
||||
AArch64CodeGen
|
||||
${SCRIPTC_LLVM_TARGET_LIBS}
|
||||
CodeGen
|
||||
Core
|
||||
Coroutines
|
||||
|
||||
@@ -71,10 +71,10 @@ static OptimizationLevel optimizationLevel(StringRef Level) {
|
||||
}
|
||||
|
||||
int emit(const EmitOptions &Options) {
|
||||
if (Options.Target != DefaultTarget)
|
||||
if (!supportsTarget(Options.Target))
|
||||
return reportError("unsupported_target",
|
||||
Twine("unsupported target '") + Options.Target +
|
||||
"' (supported: " + DefaultTarget + ")",
|
||||
"' (supported: " + AllowedTargets + ")",
|
||||
Options.DiagnosticFormat);
|
||||
if (Options.FileType != "obj" && Options.FileType != "asm")
|
||||
return reportError("invalid_filetype", "filetype must be obj or asm",
|
||||
@@ -113,12 +113,6 @@ int emit(const EmitOptions &Options) {
|
||||
Triple TargetTriple(Options.Target);
|
||||
Mod->setTargetTriple(TargetTriple);
|
||||
Mod->setDataLayout(Machine->createDataLayout());
|
||||
if (Mod->getDataLayoutStr() != DefaultDataLayout)
|
||||
return reportError("data_layout_mismatch",
|
||||
Twine("LLVM produced unexpected data layout '") +
|
||||
Mod->getDataLayoutStr() + "'",
|
||||
Options.DiagnosticFormat);
|
||||
|
||||
std::string VerificationError;
|
||||
raw_string_ostream VerificationStream(VerificationError);
|
||||
if (verifyModule(*Mod, &VerificationStream))
|
||||
|
||||
@@ -32,13 +32,28 @@ int version(int Argc, char **Argv) {
|
||||
if (!Machine)
|
||||
return scriptc::reportError("target_machine_failed", Error);
|
||||
|
||||
json::Array Targets;
|
||||
StringRef Backends = scriptc::TargetBackends;
|
||||
while (!Backends.empty()) {
|
||||
auto Split = Backends.split(',');
|
||||
Targets.push_back(Split.first);
|
||||
Backends = Split.second;
|
||||
}
|
||||
json::Array SupportedTargets;
|
||||
StringRef TargetsText = scriptc::AllowedTargets;
|
||||
while (!TargetsText.empty()) {
|
||||
auto Split = TargetsText.split(',');
|
||||
SupportedTargets.push_back(Split.first);
|
||||
TargetsText = Split.second;
|
||||
}
|
||||
json::Object Response{
|
||||
{"ok", true},
|
||||
{"protocol_version", scriptc::ProtocolVersion},
|
||||
{"scriptc_package_version", SCRIPTC_PACKAGE_VERSION},
|
||||
{"llvm_version", LLVM_VERSION_STRING},
|
||||
{"host_triple", sys::getDefaultTargetTriple()},
|
||||
{"targets", json::Array{"AArch64"}},
|
||||
{"targets", std::move(Targets)},
|
||||
{"supported_targets", std::move(SupportedTargets)},
|
||||
{"default_target", scriptc::DefaultTarget},
|
||||
{"data_layout", Machine->createDataLayout().getStringRepresentation()},
|
||||
};
|
||||
|
||||
@@ -8,12 +8,30 @@
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
#if defined(SCRIPTC_ENABLE_AARCH64)
|
||||
extern "C" {
|
||||
void LLVMInitializeAArch64TargetInfo();
|
||||
void LLVMInitializeAArch64Target();
|
||||
void LLVMInitializeAArch64TargetMC();
|
||||
void LLVMInitializeAArch64AsmPrinter();
|
||||
}
|
||||
#endif
|
||||
#if defined(SCRIPTC_ENABLE_X86)
|
||||
extern "C" {
|
||||
void LLVMInitializeX86TargetInfo();
|
||||
void LLVMInitializeX86Target();
|
||||
void LLVMInitializeX86TargetMC();
|
||||
void LLVMInitializeX86AsmPrinter();
|
||||
}
|
||||
#endif
|
||||
#if defined(SCRIPTC_ENABLE_WEBASSEMBLY)
|
||||
extern "C" {
|
||||
void LLVMInitializeWebAssemblyTargetInfo();
|
||||
void LLVMInitializeWebAssemblyTarget();
|
||||
void LLVMInitializeWebAssemblyTargetMC();
|
||||
void LLVMInitializeWebAssemblyAsmPrinter();
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace scriptc {
|
||||
|
||||
@@ -21,13 +39,62 @@ void initializeTargets() {
|
||||
static bool Initialized = false;
|
||||
if (Initialized)
|
||||
return;
|
||||
#if defined(SCRIPTC_ENABLE_AARCH64)
|
||||
LLVMInitializeAArch64TargetInfo();
|
||||
LLVMInitializeAArch64Target();
|
||||
LLVMInitializeAArch64TargetMC();
|
||||
LLVMInitializeAArch64AsmPrinter();
|
||||
#endif
|
||||
#if defined(SCRIPTC_ENABLE_X86)
|
||||
LLVMInitializeX86TargetInfo();
|
||||
LLVMInitializeX86Target();
|
||||
LLVMInitializeX86TargetMC();
|
||||
LLVMInitializeX86AsmPrinter();
|
||||
#endif
|
||||
#if defined(SCRIPTC_ENABLE_WEBASSEMBLY)
|
||||
LLVMInitializeWebAssemblyTargetInfo();
|
||||
LLVMInitializeWebAssemblyTarget();
|
||||
LLVMInitializeWebAssemblyTargetMC();
|
||||
LLVMInitializeWebAssemblyAsmPrinter();
|
||||
#endif
|
||||
Initialized = true;
|
||||
}
|
||||
|
||||
bool supportsTarget(StringRef TripleName) {
|
||||
bool Allowed = false;
|
||||
StringRef Remaining = AllowedTargets;
|
||||
while (!Remaining.empty()) {
|
||||
auto Split = Remaining.split(',');
|
||||
if (Split.first == TripleName) {
|
||||
Allowed = true;
|
||||
break;
|
||||
}
|
||||
Remaining = Split.second;
|
||||
}
|
||||
if (!Allowed)
|
||||
return false;
|
||||
Triple Triple(TripleName);
|
||||
switch (Triple.getArch()) {
|
||||
#if defined(SCRIPTC_ENABLE_AARCH64)
|
||||
case Triple::aarch64:
|
||||
case Triple::aarch64_be:
|
||||
return Triple.isOSBinFormatMachO() || Triple.isOSBinFormatELF();
|
||||
#endif
|
||||
#if defined(SCRIPTC_ENABLE_X86)
|
||||
case Triple::x86_64:
|
||||
case Triple::x86:
|
||||
return Triple.isOSBinFormatMachO() || Triple.isOSBinFormatELF() ||
|
||||
Triple.isOSBinFormatCOFF();
|
||||
#endif
|
||||
#if defined(SCRIPTC_ENABLE_WEBASSEMBLY)
|
||||
case Triple::wasm32:
|
||||
return Triple.isOSBinFormatWasm();
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static CodeGenOptLevel codeGenLevel(StringRef Level) {
|
||||
if (Level == "0")
|
||||
return CodeGenOptLevel::None;
|
||||
@@ -42,6 +109,10 @@ std::unique_ptr<TargetMachine> createTargetMachine(StringRef TripleName,
|
||||
StringRef OptLevel,
|
||||
std::string &Error) {
|
||||
initializeTargets();
|
||||
if (!supportsTarget(TripleName)) {
|
||||
Error = (Twine("target '") + TripleName + "' was not compiled into this helper").str();
|
||||
return nullptr;
|
||||
}
|
||||
Triple TargetTriple(TripleName);
|
||||
const Target *Definition = TargetRegistry::lookupTarget(TargetTriple, Error);
|
||||
if (Definition == nullptr)
|
||||
|
||||
@@ -13,12 +13,27 @@ namespace scriptc {
|
||||
|
||||
inline constexpr llvm::StringLiteral ProtocolVersion = "1";
|
||||
inline constexpr llvm::StringLiteral LlvmVersion = "22.1.8";
|
||||
#ifndef SCRIPTC_DEFAULT_TARGET
|
||||
#define SCRIPTC_DEFAULT_TARGET "arm64-apple-macosx14.0.0"
|
||||
#endif
|
||||
#ifndef SCRIPTC_DEFAULT_DATA_LAYOUT
|
||||
#define SCRIPTC_DEFAULT_DATA_LAYOUT "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32"
|
||||
#endif
|
||||
#ifndef SCRIPTC_TARGET_BACKENDS
|
||||
#define SCRIPTC_TARGET_BACKENDS "AArch64"
|
||||
#endif
|
||||
#ifndef SCRIPTC_ALLOWED_TARGETS
|
||||
#define SCRIPTC_ALLOWED_TARGETS "arm64-apple-macosx14.0.0"
|
||||
#endif
|
||||
inline constexpr llvm::StringLiteral DefaultTarget =
|
||||
"arm64-apple-macosx14.0.0";
|
||||
SCRIPTC_DEFAULT_TARGET;
|
||||
inline constexpr llvm::StringLiteral DefaultDataLayout =
|
||||
"e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32";
|
||||
SCRIPTC_DEFAULT_DATA_LAYOUT;
|
||||
inline constexpr llvm::StringLiteral TargetBackends = SCRIPTC_TARGET_BACKENDS;
|
||||
inline constexpr llvm::StringLiteral AllowedTargets = SCRIPTC_ALLOWED_TARGETS;
|
||||
|
||||
void initializeTargets();
|
||||
bool supportsTarget(llvm::StringRef Triple);
|
||||
std::unique_ptr<llvm::TargetMachine>
|
||||
createTargetMachine(llvm::StringRef Triple, llvm::StringRef OptLevel,
|
||||
std::string &Error);
|
||||
|
||||
@@ -22,7 +22,7 @@ $ scriptc build fib.ts -o fib && ./fib
|
||||
$ npm install -g scriptc
|
||||
```
|
||||
|
||||
Requires Node.js 24. Executable builds require a platform linker driver and SDK. On macOS 15+ arm64, LLVM-tier executables use the matching optional helper and precompiled runtime pack, so the driver only links; select that driver with `SCRIPTC_LINKER`. Explicit C builds, LLVM fallbacks, `--sanitize`, and the deprecated `SCRIPTC_CC=clang|zigcc` compatibility route still compile C. `--emit=ir|c|llvm` requires only Node, while `--emit=asm|obj` requires neither an external compiler nor a linker.
|
||||
Requires Node.js 24. Executable builds require a platform linker driver and SDK/sysroot. On supported macOS, Linux, and Windows hosts, LLVM-tier executables use the matching optional helper and precompiled runtime pack, so the driver only links; select that driver with `SCRIPTC_LINKER`. Explicit C builds, LLVM fallbacks, `--sanitize`, and the deprecated `SCRIPTC_CC=clang|zigcc` compatibility route still compile C. `--emit=ir|c|llvm` requires only Node, while `--emit=asm|obj` requires neither an external compiler nor a linker.
|
||||
|
||||
Builds use a bounded persistent cache by default. Exact unchanged library builds validate their recorded TypeScript/module-resolution inputs and restore the generated C/LLVM unit before starting the frontend. TypeScript comment-only edits can restore validated lowered IR instead, rebasing source locations and regenerating exact-source build identity before emission; directives, JSDoc-bearing JavaScript, token edits, configuration, package resolution, and newly appearing candidates still invalidate it. Library identity getters live in a tiny C translation unit, so build-id-only changes reuse the large compiled program object and compile only that small member before rearchiving. The native cache then applies its independent toolchain checks. Unchanged executables and library archives skip native code generation and linking after fresh compiler metadata probes, while edited builds reuse stable runtime objects. Experimental provenance-source builds bypass the early frontend tier because their fetched-source registry is process state. FFI builds with archive/object inputs or ambient `system_libraries` relink every time but still reuse runtime objects. Mutable compiler input paths such as `CPATH` and `SDKROOT`, and compiler wrappers, bypass persistent native artifacts and objects so same-path dependency edits cannot go stale. Opaque archiver wrappers rebuild library program members and archives while retaining runtime-object reuse. Direct Clang, Apple's system Clang shim, `zig cc`, trusted platform archivers, and `zig ar` retain their applicable persistent tiers. Set `SCRIPTC_NO_CACHE=1` to bypass every cache or `SCRIPTC_CACHE_DIR` to choose its location; an existing POSIX override must already be private, otherwise caching is bypassed without changing its permissions.
|
||||
|
||||
@@ -35,8 +35,8 @@ Builds use a bounded persistent cache by default. Exact unchanged library builds
|
||||
`scriptc build app.ts --emit=ir|c|llvm|asm|obj` selects serialized typed IR,
|
||||
readable C, textual LLVM IR, target assembly, or a relocatable program object
|
||||
as the one primary artifact. `--emit=exe` is the default. Assembly/object
|
||||
emission currently requires a macOS 15+ arm64 host and emits objects targeting
|
||||
macOS 14.0 (`arm64-apple-macosx14.0.0`).
|
||||
emission uses the matching helper on supported macOS, Linux, and Windows hosts
|
||||
(and produces WASI artifacts when that target is selected).
|
||||
Objects retain undefined `scr_*` runtime references plus the
|
||||
`scr_runtime_abi_v1` compatibility marker; they are not library archives.
|
||||
External consumption is experimental and requires the exact matching runtime.
|
||||
|
||||
@@ -6,5 +6,7 @@ export function hostSupportsRuntimePack(
|
||||
hostRelease = release(),
|
||||
) {
|
||||
const darwinMajor = Number.parseInt(hostRelease.split(".", 1)[0] ?? "", 10);
|
||||
return platform === "darwin" && architecture === "arm64" && darwinMajor >= 24;
|
||||
return (platform === "darwin" && (architecture === "arm64" || architecture === "x64") && darwinMajor >= 24) ||
|
||||
(platform === "linux" && (architecture === "arm64" || architecture === "x64")) ||
|
||||
(platform === "win32" && architecture === "x64");
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
||||
if (
|
||||
!existsSync(join(packageRoot, "src")) &&
|
||||
process.env["SCRIPTC_NO_CACHE"] !== "1" &&
|
||||
// A supported macOS arm64 install already carries immutable release/dev
|
||||
// runtime artifacts. Older macOS hosts retain the source-toolchain path.
|
||||
// A supported platform install already carries immutable release/dev
|
||||
// runtime artifacts. Unsupported hosts retain the source-toolchain path.
|
||||
!hostSupportsRuntimePack()
|
||||
) {
|
||||
try {
|
||||
|
||||
@@ -3,11 +3,9 @@
|
||||
import { spawn } from "node:child_process";
|
||||
import { readFile, rm } from "node:fs/promises";
|
||||
import { enableCompileCache } from "node:module";
|
||||
import { arch } from "node:process";
|
||||
import { basename, dirname, join, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { parseArgs } from "node:util";
|
||||
import { hostSupportsRuntimePack } from "../scripts/runtime-pack-host.mjs";
|
||||
import { LEGACY_C_EXECUTABLE_WARNING, shouldWarnLegacyCExecutable } from "./legacy-c-warning.js";
|
||||
import { CLI_OPTIONS, USAGE } from "./usage.js";
|
||||
|
||||
@@ -83,7 +81,7 @@ async function tryFastPath(): Promise<number | null> {
|
||||
let buildPlatform: string;
|
||||
try {
|
||||
startup = await import("@scriptc/compiler/startup-cache");
|
||||
buildPlatform = startup.targetPlatform(startup.resolveCc());
|
||||
buildPlatform = startup.configuredTargetPlatform();
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
@@ -101,16 +99,21 @@ async function tryFastPath(): Promise<number | null> {
|
||||
const ffiBytes = ffiPath === null ? null : await readFile(ffiPath).catch(() => null);
|
||||
if (ffiPath !== null && ffiBytes === null) return null;
|
||||
const root = await startup.prepareBuildCacheRoot(startup.resolveBuildCacheRoot());
|
||||
const helperObjectRoute = hostSupportsRuntimePack(process.platform, arch) &&
|
||||
(process.env["SCRIPTC_TARGET"] ?? "") === "" &&
|
||||
backend !== "c" && !values.sanitize &&
|
||||
process.env["SCRIPTC_RUNTIME_PACK"] !== "0" &&
|
||||
process.env["SCRIPTC_FETCH_CURL"] !== "1" &&
|
||||
!startup.legacyCExecutablePathRequested();
|
||||
// This must exactly mirror the ordinary LLVM executable's route in the
|
||||
// full compiler. Otherwise a valid helper/runtime-pack cache entry has a
|
||||
// different target/compiler identity and bootstrap must unnecessarily load
|
||||
// the whole compiler graph to rediscover it.
|
||||
const helperRuntimePackTarget = backend !== "c" && !values.sanitize
|
||||
? startup.precompiledRuntimePackTarget()
|
||||
: null;
|
||||
const helperObjectRoute = helperRuntimePackTarget !== null;
|
||||
let nativeEnvironment: string | null;
|
||||
try {
|
||||
nativeEnvironment = helperObjectRoute
|
||||
? await startup.executableLinkerEnvironmentFingerprint()
|
||||
? await startup.executableLinkerEnvironmentFingerprint(
|
||||
process.env,
|
||||
helperRuntimePackTarget.defaultLinker,
|
||||
)
|
||||
: await startup.executableNativeEnvironmentFingerprint();
|
||||
} catch {
|
||||
nativeEnvironment = null;
|
||||
@@ -127,10 +130,12 @@ async function tryFastPath(): Promise<number | null> {
|
||||
...(optimization === "dev" ? { optimization: "dev" as const } : {}),
|
||||
npmStatic,
|
||||
ffiProfile: ffiPath === null ? null : { path: ffiPath, bytes: ffiBytes! },
|
||||
target: `${process.env["SCRIPTC_TARGET"] ?? "native"}:${buildPlatform}:${arch}:${
|
||||
target: `${process.env["SCRIPTC_TARGET"] ?? "native"}:${buildPlatform}:${process.arch}:${
|
||||
helperObjectRoute ? "runtime-pack" : "driver-tu"
|
||||
}`,
|
||||
compiler: [helperObjectRoute ? startup.resolvePlatformLinker() : (process.env["SCRIPTC_CC"] ?? "clang")],
|
||||
compiler: [helperObjectRoute
|
||||
? startup.resolvePlatformLinker(process.env, helperRuntimePackTarget.defaultLinker)
|
||||
: (process.env["SCRIPTC_CC"] ?? "clang")],
|
||||
nativeEnvironment,
|
||||
nodeVersion: process.version,
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@ import { existsSync, readFileSync, rmSync, statSync } from "node:fs";
|
||||
import { dirname, join, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { parseArgs } from "node:util";
|
||||
import { analyze, buildTargetPlatform, compile, compileExternalC, compileLibrary, isExactExternalTypeSpecifier, renderDiagnostics, renderCoverage, resolveProvenanceSources, setProvenanceSources, warmNativeCaches, type NativeCacheWarmProfile } from "@scriptc/compiler";
|
||||
import { analyze, buildTargetPlatform, compile, compileExternalC, compileLibrary, isExactExternalTypeSpecifier, renderDiagnostics, renderCoverage, resolveProvenanceSources, setProvenanceSources, sourceTargetPlatform, warmNativeCaches, type NativeCacheWarmProfile } from "@scriptc/compiler";
|
||||
import { LEGACY_C_EXECUTABLE_WARNING, shouldWarnLegacyCExecutable } from "./legacy-c-warning.js";
|
||||
import { resolveOutputOptions } from "./output-options.js";
|
||||
import { selectOutputPaths } from "./paths.js";
|
||||
@@ -329,7 +329,7 @@ async function main(): Promise<number> {
|
||||
if (command === "run") {
|
||||
return new Promise<number>((resolveExit) => {
|
||||
let child;
|
||||
if (buildTargetPlatform() === "wasi") {
|
||||
if (sourceTargetPlatform() === "wasi") {
|
||||
const builtRunner = fileURLToPath(new URL("./wasi-runner.js", import.meta.url));
|
||||
const runner = existsSync(builtRunner)
|
||||
? builtRunner
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { tmpdir } from "node:os";
|
||||
import { basename, dirname, join, resolve } from "node:path";
|
||||
import { buildTargetPlatform, wasiGuestPath } from "@scriptc/compiler";
|
||||
import { buildTargetPlatform, sourceTargetPlatform, wasiGuestPath } from "@scriptc/compiler";
|
||||
|
||||
export type CliOutputKind = "ir" | "c" | "llvm" | "asm" | "obj" | "exe";
|
||||
|
||||
@@ -25,7 +25,7 @@ export function defaultOutputName(
|
||||
kind: CliOutputKind,
|
||||
platform?: string,
|
||||
): string {
|
||||
const selectedPlatform = platform ?? (kind === "exe" ? buildTargetPlatform() : process.platform);
|
||||
const selectedPlatform = platform ?? (kind === "exe" ? sourceTargetPlatform() : process.platform);
|
||||
if (kind === "exe" && selectedPlatform === "wasi") return `${stem}.wasm`;
|
||||
return `${stem}${(selectedPlatform === "win32" ? WINDOWS_SUFFIXES : POSIX_SUFFIXES)[kind]}`;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ Usage:
|
||||
Options:
|
||||
-o, --out <path> primary output path (default: .scriptc/<name><suffix>)
|
||||
--emit <kind> primary output: ir, c, llvm, asm, obj, or exe
|
||||
(default: exe). asm/obj currently support macOS 15+ arm64
|
||||
(default: exe). asm/obj use the matching platform helper
|
||||
--print <kind> print machine-readable metadata instead of the output path
|
||||
(native-link-info implies --emit=obj and never links)
|
||||
--backend <b> code generator. llvm is the default and the output that
|
||||
|
||||
@@ -2,10 +2,13 @@ import { describe, expect, test } from "vitest";
|
||||
import { hostSupportsRuntimePack } from "../scripts/runtime-pack-host.mjs";
|
||||
|
||||
describe("runtime-pack host support", () => {
|
||||
test("requires macOS 15 or newer on arm64", () => {
|
||||
test("recognizes each platform with a release-built runtime pack", () => {
|
||||
expect(hostSupportsRuntimePack("darwin", "arm64", "24.0.0")).toBe(true);
|
||||
expect(hostSupportsRuntimePack("darwin", "x64", "24.0.0")).toBe(true);
|
||||
expect(hostSupportsRuntimePack("darwin", "arm64", "23.6.0")).toBe(false);
|
||||
expect(hostSupportsRuntimePack("darwin", "x64", "24.0.0")).toBe(false);
|
||||
expect(hostSupportsRuntimePack("linux", "arm64", "24.0.0")).toBe(false);
|
||||
expect(hostSupportsRuntimePack("linux", "x64", "6.8.0")).toBe(true);
|
||||
expect(hostSupportsRuntimePack("linux", "arm64", "6.8.0")).toBe(true);
|
||||
expect(hostSupportsRuntimePack("win32", "x64", "10.0.0")).toBe(true);
|
||||
expect(hostSupportsRuntimePack("linux", "ia32", "6.8.0")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import { execFile } from "node:child_process";
|
||||
import { existsSync } from "node:fs";
|
||||
import { createRequire } from "node:module";
|
||||
import { mkdtemp, rm } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { dirname, join } from "node:path";
|
||||
import { promisify } from "node:util";
|
||||
import { afterEach, expect, test } from "vitest";
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
const require = createRequire(import.meta.url);
|
||||
const repoRoot = join(import.meta.dirname, "../../..");
|
||||
const cliEntry = join(repoRoot, "packages/cli/src/main.ts");
|
||||
const tsxLoader = join(dirname(require.resolve("tsx/package.json")), "dist/loader.mjs");
|
||||
const helperPackage = require.resolve("@scriptc/llvm-darwin-arm64/package.json");
|
||||
const helper = join(dirname(helperPackage), "bin", "scriptc-llvm-codegen");
|
||||
const runtimePackage = require.resolve("@scriptc/runtime-wasm32-wasi/package.json");
|
||||
const runtimeManifest = join(dirname(runtimePackage), "runtime-pack.json");
|
||||
const supported = existsSync(helper) && existsSync(runtimeManifest);
|
||||
const dirs: string[] = [];
|
||||
|
||||
afterEach(async () => {
|
||||
await Promise.all(dirs.splice(0).map((path) => rm(path, { recursive: true, force: true })));
|
||||
});
|
||||
|
||||
test.runIf(supported)("WASI helper object plus runtime pack builds and runs without SCRIPTC_CC", async () => {
|
||||
const dir = await mkdtemp(join(tmpdir(), "scriptc-wasi-runtime-pack-"));
|
||||
dirs.push(dir);
|
||||
const output = join(dir, "hello.wasm");
|
||||
const zigCache = join(dir, "zig-cache");
|
||||
await expect(execFileAsync(process.execPath, [
|
||||
"--import", tsxLoader, cliEntry, "run", join(repoRoot, "tests/corpus/001-hello.ts"), "-o", output,
|
||||
], {
|
||||
env: {
|
||||
...process.env,
|
||||
SCRIPTC_TARGET: "wasm32-wasi",
|
||||
SCRIPTC_NO_CACHE: "1",
|
||||
SCRIPTC_LEGACY_C_PIPELINE: "0",
|
||||
ZIG_GLOBAL_CACHE_DIR: join(zigCache, "global"),
|
||||
ZIG_LOCAL_CACHE_DIR: join(zigCache, "local"),
|
||||
},
|
||||
encoding: "utf8",
|
||||
})).resolves.toMatchObject({ stdout: "hello world\n" });
|
||||
});
|
||||
@@ -38,6 +38,19 @@
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@scriptc/llvm-darwin-arm64": "workspace:*",
|
||||
"@scriptc/runtime-darwin-arm64": "workspace:*"
|
||||
"@scriptc/llvm-darwin-x64": "workspace:*",
|
||||
"@scriptc/llvm-linux-x64-gnu": "workspace:*",
|
||||
"@scriptc/llvm-linux-arm64-gnu": "workspace:*",
|
||||
"@scriptc/llvm-linux-x64-musl": "workspace:*",
|
||||
"@scriptc/llvm-linux-arm64-musl": "workspace:*",
|
||||
"@scriptc/llvm-win32-x64-msvc": "workspace:*",
|
||||
"@scriptc/runtime-darwin-arm64": "workspace:*",
|
||||
"@scriptc/runtime-darwin-x64": "workspace:*",
|
||||
"@scriptc/runtime-linux-x64-gnu": "workspace:*",
|
||||
"@scriptc/runtime-linux-arm64-gnu": "workspace:*",
|
||||
"@scriptc/runtime-linux-x64-musl": "workspace:*",
|
||||
"@scriptc/runtime-linux-arm64-musl": "workspace:*",
|
||||
"@scriptc/runtime-win32-x64-msvc": "workspace:*",
|
||||
"@scriptc/runtime-wasm32-wasi": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
import {
|
||||
compileC,
|
||||
compileLibArchive,
|
||||
configuredTargetPlatform,
|
||||
type CcOptions,
|
||||
type LibArchiveOptions,
|
||||
} from "./native-toolchain.js";
|
||||
@@ -20,6 +21,7 @@ export {
|
||||
compileC,
|
||||
compileLibArchive,
|
||||
compilerDriverSupportsPersistentCache,
|
||||
configuredTargetPlatform,
|
||||
executableNativeEnvironmentFingerprint,
|
||||
isAndroidTarget,
|
||||
isIosTarget,
|
||||
@@ -72,8 +74,8 @@ export function legacyCExecutablePipelineEnabled(
|
||||
}
|
||||
|
||||
/** `SCRIPTC_CC` selects the external C compiler route during the migration.
|
||||
* An unset value lets an LLVM-tier macOS build use the helper plus runtime
|
||||
* pack and reserve `SCRIPTC_LINKER` for the platform-linker driver. */
|
||||
* An unset value lets every supported LLVM-tier target use its helper plus
|
||||
* runtime pack and reserve `SCRIPTC_LINKER` for the platform-linker driver. */
|
||||
export function legacyCExecutablePathRequested(
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
): boolean {
|
||||
|
||||
@@ -51,7 +51,9 @@ export async function createNativeLinkPlan(options: {
|
||||
...(options.ffi?.systemLibraries ?? []),
|
||||
...runtimePack.systemLibraries,
|
||||
])],
|
||||
driverFlags: [...options.target.executableLinkerArgs],
|
||||
driverFlags: options.target.executableLinkerArgs.map((arg, index, args) =>
|
||||
index > 0 && args[index - 1] === "-target" ? options.target.linkerTargetTriple : arg
|
||||
),
|
||||
dependencyPaths: [
|
||||
...runtimePack.dependencyPaths,
|
||||
...(options.ffi?.libraries ?? []),
|
||||
|
||||
@@ -28,8 +28,11 @@ const execFileAsync = promisify(execFile);
|
||||
/** The linker (or linker driver) is independent from SCRIPTC_CC. A plain
|
||||
* `clang` is the initial macOS driver because it locates the selected SDK and
|
||||
* CRT inputs; it receives only objects and archives on this route. */
|
||||
export function resolvePlatformLinker(env: NodeJS.ProcessEnv = process.env): string {
|
||||
return env["SCRIPTC_LINKER"] || "clang";
|
||||
export function resolvePlatformLinker(
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
defaultLinker: string = "clang",
|
||||
): string {
|
||||
return env["SCRIPTC_LINKER"] || defaultLinker;
|
||||
}
|
||||
|
||||
/** Exact executable selected for a linker spelling. The object-only route
|
||||
@@ -74,8 +77,9 @@ function platformLinkerIdentity(
|
||||
* only the helper-produced program object and runtime-pack artifacts. */
|
||||
export async function executableLinkerEnvironmentFingerprint(
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
defaultLinker: string = "clang",
|
||||
): Promise<string> {
|
||||
const linker = resolvePlatformLinker(env);
|
||||
const linker = resolvePlatformLinker(env, defaultLinker);
|
||||
const linkerIdentity = platformLinkerIdentity(env);
|
||||
let effectiveDriverIdentity: string;
|
||||
try {
|
||||
@@ -112,7 +116,9 @@ export async function executableLinkerEnvironmentFingerprint(
|
||||
* a caller-selected SCRIPTC_LINKER may be a wrapper with hidden inputs. */
|
||||
export function platformLinkerSupportsPersistentCache(
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
target?: Pick<NativeLinkPlan["target"], "platform" | "defaultLinker">,
|
||||
): boolean {
|
||||
if (target !== undefined && target.platform !== "darwin") return false;
|
||||
// The Apple system shim is a stable front door to the active SDK/linker;
|
||||
// linkNativeExecutable snapshots the selected transitive inputs before it
|
||||
// publishes the final cache entry. A PATH wrapper is intentionally opaque.
|
||||
@@ -198,7 +204,8 @@ export async function linkNativeExecutable(
|
||||
onArtifactReady?: (artifact: { dependencies: NativeArtifactDependency[] }) => Promise<void>;
|
||||
} = {},
|
||||
): Promise<void> {
|
||||
const linker = options.linker ?? resolvePlatformLinker();
|
||||
const explicitLinker = options.linker ?? process.env["SCRIPTC_LINKER"];
|
||||
const linker = explicitLinker ?? plan.target.defaultLinker;
|
||||
// ld64 derives an ad-hoc signature identifier from the output basename.
|
||||
// Keep that basename caller-visible while a private sibling directory gives
|
||||
// the link its own inode and preserves an atomic same-filesystem install.
|
||||
@@ -211,6 +218,7 @@ export async function linkNativeExecutable(
|
||||
const staged = await stageRuntimePackArtifacts(plan.runtimePack);
|
||||
stagedRoot = staged.root;
|
||||
const args = [
|
||||
...(explicitLinker === undefined ? plan.target.defaultLinkerArgs : []),
|
||||
...plan.driverFlags,
|
||||
...plan.inputs.map((input) => staged.replacements.get(input) ?? input),
|
||||
...plan.systemLibraries.map((name) => `-l${name}`),
|
||||
|
||||
@@ -2,9 +2,9 @@ import { chmod, mkdir, mkdtemp, readFile, rm, stat, writeFile } from "node:fs/pr
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { afterEach, expect, test } from "vitest";
|
||||
import { emitNativeArtifact, NativeCodegenError } from "./native-codegen.js";
|
||||
import { emitNativeArtifact, NativeCodegenError, validateNativeCodegenVersion } from "./native-codegen.js";
|
||||
import { nativeArtifactDependenciesStillMatch } from "./native-toolchain.js";
|
||||
import { MACOS_ARM64_TARGET } from "./targets.js";
|
||||
import { LINUX_X64_GNU_TARGET, MACOS_ARM64_TARGET, WASM32_WASI_TARGET } from "./targets.js";
|
||||
import { compilerReleaseVersion } from "../library/sidecar.js";
|
||||
|
||||
const dirs: string[] = [];
|
||||
@@ -34,6 +34,7 @@ async function fakePackage(options: {
|
||||
llvm_version: "22.1.8",
|
||||
host_triple: "arm64-apple-darwin24.0.0",
|
||||
targets: ["AArch64"],
|
||||
supported_targets: [MACOS_ARM64_TARGET.llvmTriple],
|
||||
default_target: MACOS_ARM64_TARGET.llvmTriple,
|
||||
data_layout: MACOS_ARM64_TARGET.dataLayout,
|
||||
});
|
||||
@@ -63,18 +64,57 @@ ${options.emitFailure === true
|
||||
return { packageJson, bin, log, root };
|
||||
}
|
||||
|
||||
function request(root: string, packageJson: string, output = join(root, "program.o")) {
|
||||
function request(root: string, packageJson: string, output = join(root, "program.o"), target = MACOS_ARM64_TARGET) {
|
||||
return {
|
||||
outputPath: output,
|
||||
llvm: "define i32 @answer() { ret i32 42 }\n",
|
||||
outputKind: "obj" as const,
|
||||
sourcePath: "/source/app.ts",
|
||||
target: MACOS_ARM64_TARGET,
|
||||
target,
|
||||
resolvePackageJson: () => packageJson,
|
||||
cacheRoot: join(root, "cache"),
|
||||
};
|
||||
}
|
||||
|
||||
test("resolves the target's matching platform helper rather than a fixed macOS package", async () => {
|
||||
const pkg = await fakePackage();
|
||||
const output = join(pkg.root, "linux.o");
|
||||
await writeFile(pkg.packageJson, JSON.stringify({ name: LINUX_X64_GNU_TARGET.helperPackage }));
|
||||
await writeFile(pkg.bin, (await readFile(pkg.bin, "utf8"))
|
||||
.replaceAll(MACOS_ARM64_TARGET.llvmTriple, LINUX_X64_GNU_TARGET.helper.defaultTarget)
|
||||
.replaceAll(MACOS_ARM64_TARGET.dataLayout, LINUX_X64_GNU_TARGET.helper.defaultDataLayout)
|
||||
.replaceAll('"targets":["AArch64"]', '"targets":["X86"]')
|
||||
.replaceAll(`"supported_targets":["${MACOS_ARM64_TARGET.llvmTriple}"]`, `"supported_targets":["${LINUX_X64_GNU_TARGET.llvmTriple}"]`));
|
||||
await emitNativeArtifact({
|
||||
...request(pkg.root, pkg.packageJson, output, LINUX_X64_GNU_TARGET),
|
||||
helperHost: { platform: "linux", arch: "x64" },
|
||||
});
|
||||
expect(await readFile(output, "utf8")).toContain("define i32 @answer");
|
||||
});
|
||||
|
||||
test("requires a portable target backend in addition to the host helper backend", async () => {
|
||||
const pkg = await fakePackage();
|
||||
await expect(emitNativeArtifact({
|
||||
...request(pkg.root, pkg.packageJson, join(pkg.root, "program.wasm"), WASM32_WASI_TARGET),
|
||||
helperHost: { platform: "darwin", arch: "arm64" },
|
||||
})).rejects.toMatchObject({ diagnosticCode: "SC3003", detailCode: "version_mismatch" });
|
||||
});
|
||||
|
||||
test("accepts a WASI-capable helper whose default host target differs", () => {
|
||||
const helper = WASM32_WASI_TARGET.hostHelpers?.["darwin-arm64"]!;
|
||||
expect(validateNativeCodegenVersion({
|
||||
ok: true,
|
||||
protocol_version: "1",
|
||||
scriptc_package_version: compilerReleaseVersion(),
|
||||
llvm_version: "22.1.8",
|
||||
host_triple: "arm64-apple-darwin25.0.0",
|
||||
targets: ["AArch64", "WebAssembly"],
|
||||
supported_targets: [helper.defaultTarget, WASM32_WASI_TARGET.llvmTriple],
|
||||
default_target: helper.defaultTarget,
|
||||
data_layout: helper.defaultDataLayout,
|
||||
}, WASM32_WASI_TARGET, helper).targets).toContain("WebAssembly");
|
||||
});
|
||||
|
||||
test("resolves a package helper, emits atomically, and caches by all native inputs", async () => {
|
||||
const pkg = await fakePackage();
|
||||
const first = join(pkg.root, "first.o");
|
||||
|
||||
@@ -19,7 +19,13 @@ import {
|
||||
snapshotNativeArtifactDependencies,
|
||||
type NativeArtifactDependency,
|
||||
} from "./native-toolchain.js";
|
||||
import { nativeCodegenTarget, nativeCodegenTargetRefusal, type NativeTargetSpec } from "./targets.js";
|
||||
import {
|
||||
nativeCodegenTarget,
|
||||
nativeCodegenTargetRefusal,
|
||||
nativeHelperForTarget,
|
||||
type NativeHelperSpec,
|
||||
type NativeTargetSpec,
|
||||
} from "./targets.js";
|
||||
import { compilerReleaseVersion } from "../library/sidecar.js";
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
@@ -46,6 +52,7 @@ export interface NativeCodegenVersion {
|
||||
llvm_version: string;
|
||||
host_triple: string;
|
||||
targets: string[];
|
||||
supported_targets: string[];
|
||||
default_target: string;
|
||||
data_layout: string;
|
||||
}
|
||||
@@ -78,6 +85,8 @@ export interface NativeCodegenOptions {
|
||||
optimization?: "0" | "1" | "2" | "3" | "s" | "z";
|
||||
sanitize?: boolean;
|
||||
target?: NativeTargetSpec;
|
||||
/** Test seam for package selection on a simulated host. */
|
||||
helperHost?: { platform: NodeJS.Platform; arch: string };
|
||||
/** Test seam: still resolves a package path, never searches PATH. */
|
||||
resolvePackageJson?: (specifier: string) => string;
|
||||
/** Internal/test override; omitted production calls use the shared cache. */
|
||||
@@ -122,12 +131,16 @@ async function invoke(binaryPath: string, args: string[]): Promise<{ stdout: str
|
||||
}
|
||||
}
|
||||
|
||||
function validateVersion(value: Record<string, unknown>, target: NativeTargetSpec): NativeCodegenVersion {
|
||||
export function validateNativeCodegenVersion(
|
||||
value: Record<string, unknown>,
|
||||
target: NativeTargetSpec,
|
||||
helper: NativeHelperSpec,
|
||||
): NativeCodegenVersion {
|
||||
const expectedPackageVersion = compilerReleaseVersion();
|
||||
const mismatch = (field: string, expected: string): never => {
|
||||
throw new NativeCodegenError(
|
||||
"SC3003",
|
||||
`LLVM native helper is incompatible: ${field} is ${JSON.stringify(value[field])}, expected ${JSON.stringify(expected)}; reinstall scriptc so its compiler and ${target.helperPackage} packages have matching versions`,
|
||||
`LLVM native helper is incompatible: ${field} is ${JSON.stringify(value[field])}, expected ${JSON.stringify(expected)}; reinstall scriptc so its compiler and ${helper.packageName} packages have matching versions`,
|
||||
"version_mismatch",
|
||||
);
|
||||
};
|
||||
@@ -141,14 +154,17 @@ function validateVersion(value: Record<string, unknown>, target: NativeTargetSpe
|
||||
if (value["llvm_version"] !== NATIVE_CODEGEN_LLVM_VERSION) {
|
||||
mismatch("llvm_version", NATIVE_CODEGEN_LLVM_VERSION);
|
||||
}
|
||||
if (value["default_target"] !== target.llvmTriple) {
|
||||
mismatch("default_target", target.llvmTriple);
|
||||
if (value["default_target"] !== helper.defaultTarget) {
|
||||
mismatch("default_target", helper.defaultTarget);
|
||||
}
|
||||
if (value["data_layout"] !== target.dataLayout) {
|
||||
mismatch("data_layout", target.dataLayout);
|
||||
if (value["data_layout"] !== helper.defaultDataLayout) {
|
||||
mismatch("data_layout", helper.defaultDataLayout);
|
||||
}
|
||||
if (!Array.isArray(value["targets"]) || !value["targets"].includes("AArch64")) {
|
||||
mismatch("targets", "an array containing AArch64");
|
||||
if (!Array.isArray(value["targets"]) || !value["targets"].includes(target.llvmBackend)) {
|
||||
mismatch("targets", `an array containing ${target.llvmBackend}`);
|
||||
}
|
||||
if (!Array.isArray(value["supported_targets"]) || !value["supported_targets"].includes(target.llvmTriple)) {
|
||||
mismatch("supported_targets", `an array containing ${target.llvmTriple}`);
|
||||
}
|
||||
if (typeof value["host_triple"] !== "string") mismatch("host_triple", "a string");
|
||||
return value as unknown as NativeCodegenVersion;
|
||||
@@ -157,20 +173,37 @@ function validateVersion(value: Record<string, unknown>, target: NativeTargetSpe
|
||||
async function resolveHelper(
|
||||
target: NativeTargetSpec,
|
||||
resolver?: (specifier: string) => string,
|
||||
host?: { platform: NodeJS.Platform; arch: string },
|
||||
): Promise<ResolvedHelper> {
|
||||
const helper = nativeHelperForTarget(
|
||||
target,
|
||||
host?.platform,
|
||||
host?.arch,
|
||||
);
|
||||
if (helper === null) {
|
||||
throw new NativeCodegenError(
|
||||
"SC3002",
|
||||
`no scriptc LLVM helper supports ${target.name} on this host`,
|
||||
"unsupported_helper_host",
|
||||
);
|
||||
}
|
||||
const resolvePackageJson = resolver ?? ((specifier: string) =>
|
||||
createRequire(import.meta.url).resolve(specifier));
|
||||
let packageJsonPath: string;
|
||||
try {
|
||||
packageJsonPath = resolvePackageJson(`${target.helperPackage}/package.json`);
|
||||
packageJsonPath = resolvePackageJson(`${helper.packageName}/package.json`);
|
||||
} catch {
|
||||
throw new NativeCodegenError(
|
||||
"SC3003",
|
||||
`LLVM native helper package ${target.helperPackage} is not installed; reinstall scriptc with optional dependencies enabled for macOS arm64`,
|
||||
`LLVM native helper package ${helper.packageName} is not installed; reinstall scriptc with optional dependencies enabled for this host`,
|
||||
"missing_package",
|
||||
);
|
||||
}
|
||||
const binaryPath = join(dirname(packageJsonPath), "bin", "scriptc-llvm-codegen");
|
||||
const binaryPath = join(
|
||||
dirname(packageJsonPath),
|
||||
"bin",
|
||||
process.platform === "win32" ? "scriptc-llvm-codegen.exe" : "scriptc-llvm-codegen",
|
||||
);
|
||||
let binaryStat;
|
||||
try {
|
||||
binaryStat = await stat(binaryPath);
|
||||
@@ -178,7 +211,7 @@ async function resolveHelper(
|
||||
} catch {
|
||||
throw new NativeCodegenError(
|
||||
"SC3003",
|
||||
`LLVM native helper package ${target.helperPackage} is incomplete: ${binaryPath} is missing; reinstall scriptc`,
|
||||
`LLVM native helper package ${helper.packageName} is incomplete: ${binaryPath} is missing; reinstall scriptc`,
|
||||
"missing_binary",
|
||||
);
|
||||
}
|
||||
@@ -191,7 +224,7 @@ async function resolveHelper(
|
||||
} catch {
|
||||
throw new NativeCodegenError(
|
||||
"SC3003",
|
||||
`LLVM native helper package ${target.helperPackage} is incomplete: ${binaryPath} is not readable and executable; reinstall scriptc`,
|
||||
`LLVM native helper package ${helper.packageName} is incomplete: ${binaryPath} is not readable and executable; reinstall scriptc`,
|
||||
"unusable_binary",
|
||||
);
|
||||
}
|
||||
@@ -201,11 +234,15 @@ async function resolveHelper(
|
||||
} catch {
|
||||
throw new NativeCodegenError(
|
||||
"SC3003",
|
||||
`LLVM native helper package ${target.helperPackage} changed while its inputs were being inspected; retry the build or reinstall scriptc`,
|
||||
`LLVM native helper package ${helper.packageName} changed while its inputs were being inspected; retry the build or reinstall scriptc`,
|
||||
"helper_changed",
|
||||
);
|
||||
}
|
||||
const cacheKey = JSON.stringify(dependencies);
|
||||
// A single host helper can own more than one backend (for example its
|
||||
// host-native ISA plus WebAssembly). Cache only after the target backend
|
||||
// has also been checked; otherwise a prior X86 lookup could accidentally
|
||||
// bless a later WASI request against an older X86-only package.
|
||||
const cacheKey = JSON.stringify({ dependencies, targetBackend: target.llvmBackend });
|
||||
const load = async (): Promise<ResolvedHelper> => {
|
||||
let stdout: string;
|
||||
let binary: Buffer;
|
||||
@@ -217,7 +254,7 @@ async function resolveHelper(
|
||||
} catch (error) {
|
||||
throw new NativeCodegenError(
|
||||
"SC3003",
|
||||
`LLVM native helper package ${target.helperPackage} could not be read and executed for its identity check: ${error instanceof Error ? error.message : String(error)}; reinstall scriptc`,
|
||||
`LLVM native helper package ${helper.packageName} could not be read and executed for its identity check: ${error instanceof Error ? error.message : String(error)}; reinstall scriptc`,
|
||||
"identity_probe_failed",
|
||||
);
|
||||
}
|
||||
@@ -225,14 +262,14 @@ async function resolveHelper(
|
||||
if (rawVersion === null) {
|
||||
throw new NativeCodegenError(
|
||||
"SC3003",
|
||||
`LLVM native helper returned an invalid version response; reinstall scriptc and ${target.helperPackage}`,
|
||||
`LLVM native helper returned an invalid version response; reinstall scriptc and ${helper.packageName}`,
|
||||
"invalid_version_response",
|
||||
);
|
||||
}
|
||||
if (!(await nativeArtifactDependenciesStillMatch(dependencies).catch(() => false))) {
|
||||
throw new NativeCodegenError(
|
||||
"SC3003",
|
||||
`LLVM native helper package ${target.helperPackage} changed during its identity check; retry the build or reinstall scriptc`,
|
||||
`LLVM native helper package ${helper.packageName} changed during its identity check; retry the build or reinstall scriptc`,
|
||||
"helper_changed",
|
||||
);
|
||||
}
|
||||
@@ -241,9 +278,9 @@ async function resolveHelper(
|
||||
binaryPath,
|
||||
dependencies,
|
||||
identity: {
|
||||
packageName: target.helperPackage,
|
||||
packageName: helper.packageName,
|
||||
binaryDigest: createHash("sha256").update(binary).digest("hex"),
|
||||
version: validateVersion(rawVersion, target),
|
||||
version: validateNativeCodegenVersion(rawVersion, target, helper),
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -304,6 +341,13 @@ export async function emitNativeArtifact(options: NativeCodegenOptions): Promise
|
||||
"unsupported_target",
|
||||
);
|
||||
}
|
||||
if (!target.supports[options.outputKind]) {
|
||||
throw new NativeCodegenError(
|
||||
"SC3002",
|
||||
`--emit=${options.outputKind} is not supported for ${target.name}`,
|
||||
"unsupported_output_kind",
|
||||
);
|
||||
}
|
||||
if (options.sanitize === true) {
|
||||
throw new NativeCodegenError(
|
||||
"SC3002",
|
||||
@@ -311,7 +355,7 @@ export async function emitNativeArtifact(options: NativeCodegenOptions): Promise
|
||||
"sanitize_unsupported",
|
||||
);
|
||||
}
|
||||
const helper = await resolveHelper(target, options.resolvePackageJson);
|
||||
const helper = await resolveHelper(target, options.resolvePackageJson, options.helperHost);
|
||||
const root = await prepareBuildCacheRoot(
|
||||
options.cacheRoot === undefined ? buildCacheRoot() : options.cacheRoot,
|
||||
);
|
||||
|
||||
@@ -68,7 +68,7 @@ export interface NativeLinkInfo {
|
||||
target: {
|
||||
name: NativeTargetSpec["name"];
|
||||
llvm_triple: NativeTargetSpec["llvmTriple"];
|
||||
architecture: "arm64";
|
||||
architecture: NativeTargetSpec["architecture"];
|
||||
object_format: NativeTargetSpec["objectFormat"];
|
||||
minimum_os: NativeTargetSpec["minimumOs"];
|
||||
relocation_model: NativeTargetSpec["relocationModel"];
|
||||
@@ -117,11 +117,8 @@ function runtimeSourceRecipe(
|
||||
env: NodeJS.ProcessEnv,
|
||||
optimization: "release" | "dev",
|
||||
): { sets: NativeSourceSet[]; systemLibraries: string[]; driverFlags: string[] } {
|
||||
// Native link info currently describes the supported Mach-O external-object
|
||||
// recipe. Keep this in the same target-aware helper as compileC so a
|
||||
// consumer's link has the identical executable reachability semantics.
|
||||
const executableSectionFlags = executableSectionEliminationFlags("darwin");
|
||||
const dynamic = features.dynamic;
|
||||
const executableSectionFlags = executableSectionEliminationFlags(target.platform);
|
||||
const curlFetch = dynamic && features.fetch && env["SCRIPTC_FETCH_CURL"] === "1";
|
||||
const nativeFetch = features.fetch && !curlFetch;
|
||||
const netIsland = dynamic && (features.netIsland || nativeFetch);
|
||||
@@ -129,8 +126,19 @@ function runtimeSourceRecipe(
|
||||
const http = features.http || nativeFetch || netIsland;
|
||||
const tls = features.tls || nativeFetch || netIsland;
|
||||
const tlsCa = features.tlsCa || tls;
|
||||
const wasiUnavailableSources = new Set([
|
||||
"scr_child.c", "scr_dyn_handle.c", "scr_loop_kqueue.c", "scr_loop_epoll.c",
|
||||
"scr_loop_wsapoll.c", "scr_net.c", "scr_http.c", "scr_http2.c", "scr_dgram.c",
|
||||
"scr_watch.c", "scr_tls_ca.c", "scr_tls.c", "scr_fetch.c", "scr_net_island.c",
|
||||
]);
|
||||
const runtimeSources = [
|
||||
...EXECUTABLE_RUNTIME_SOURCES,
|
||||
...EXECUTABLE_RUNTIME_SOURCES.filter((source) =>
|
||||
target.platform !== "wasi" || !wasiUnavailableSources.has(source)
|
||||
),
|
||||
...(target.platform === "win32" ? ["scr_win.c"] : []),
|
||||
...(target.name === "linux-x64-musl" || target.name === "linux-arm64-musl"
|
||||
? ["scr_musl.c"]
|
||||
: []),
|
||||
...(features.copying ? ["scr_copying.c"] : []),
|
||||
...(features.fileHandle ? ["scr_file_handle.c"] : []),
|
||||
...(features.regex ? ["scr_regex.c"] : []),
|
||||
@@ -174,12 +182,14 @@ function runtimeSourceRecipe(
|
||||
]
|
||||
: []),
|
||||
];
|
||||
const commonTargetFlags = ["-target", target.llvmTriple];
|
||||
const filteredSources = target.platform === "wasi"
|
||||
? runtimeSources.filter((source) => !wasiUnavailableSources.has(source))
|
||||
: runtimeSources;
|
||||
const sets: NativeSourceSet[] = [{
|
||||
name: "runtime",
|
||||
output: "objects",
|
||||
suggested_output: "runtime/*.o",
|
||||
sources: unique(runtimeSources).map((source) => packagePath("src", source)),
|
||||
sources: unique(filteredSources).map((source) => packagePath("src", source)),
|
||||
include_directories: unique([
|
||||
"src",
|
||||
...(features.regex || dynamic ? ["vendor/quickjs-ng"] : []),
|
||||
@@ -187,11 +197,13 @@ function runtimeSourceRecipe(
|
||||
...(curlFetch ? ["vendor/curl/include"] : []),
|
||||
]),
|
||||
defines: unique([
|
||||
...target.runtimeCompileDefines,
|
||||
...(features.textDecoderLegacy ? ["SCR_TEXT_DECODER_LEGACY"] : []),
|
||||
...(dynamic ? ["SCR_DYNAMIC"] : []),
|
||||
]),
|
||||
c_flags: [
|
||||
"-std=c11", ...commonTargetFlags, "-pthread",
|
||||
"-std=c11", "-target", target.llvmTriple,
|
||||
...(target.platform === "win32" || target.platform === "wasi" ? [] : ["-pthread"]),
|
||||
optimization === "dev" ? "-O0" : "-O2",
|
||||
...executableSectionFlags.compile,
|
||||
"-fno-math-errno", "-fno-strict-aliasing", "-Wno-deprecated-declarations",
|
||||
@@ -205,7 +217,11 @@ function runtimeSourceRecipe(
|
||||
sources: LRE_SOURCES.map((source) => packagePath("vendor", "quickjs-ng", source)),
|
||||
include_directories: ["vendor/quickjs-ng"],
|
||||
defines: [],
|
||||
c_flags: ["-std=c11", ...commonTargetFlags, "-Os"],
|
||||
c_flags: [
|
||||
"-std=c11", "-target", target.llvmTriple,
|
||||
...target.runtimeCompileDefines.map((define) => `-D${define}`),
|
||||
"-Os",
|
||||
],
|
||||
});
|
||||
}
|
||||
if (dynamic) {
|
||||
@@ -217,7 +233,9 @@ function runtimeSourceRecipe(
|
||||
include_directories: ["vendor/quickjs-ng"],
|
||||
defines: ["QUICKJS_NG_BUILD", "_GNU_SOURCE", "NDEBUG"],
|
||||
c_flags: [
|
||||
"-std=gnu11", ...commonTargetFlags, "-fvisibility=hidden",
|
||||
"-std=gnu11", "-target", target.llvmTriple,
|
||||
...target.runtimeCompileDefines.map((define) => `-D${define}`),
|
||||
"-fvisibility=hidden",
|
||||
"-funsigned-char", "-Os",
|
||||
],
|
||||
});
|
||||
@@ -233,22 +251,29 @@ function runtimeSourceRecipe(
|
||||
sources: [],
|
||||
include_directories: ["vendor/mbedtls/include", "vendor/mbedtls/library"],
|
||||
defines: [],
|
||||
c_flags: ["-std=c11", ...commonTargetFlags, "-Os"],
|
||||
c_flags: [
|
||||
"-std=c11", "-target", target.llvmTriple,
|
||||
...target.runtimeCompileDefines.map((define) => `-D${define}`),
|
||||
"-Os",
|
||||
],
|
||||
});
|
||||
}
|
||||
if (target.platform === "wasi") {
|
||||
const blocked = features.net || features.http || features.http2 || features.dgram ||
|
||||
features.watch || features.tls || features.tlsCa || features.fetch || features.netIsland;
|
||||
if (blocked) throw new Error("WASI native link info requested an unavailable network/TLS runtime surface");
|
||||
}
|
||||
const systemLibraries = unique([
|
||||
"System",
|
||||
...((features.zlib || nativeFetch) ? ["z"] : []),
|
||||
...(dynamic ? ["m"] : []),
|
||||
...target.runtimeSystemLibraries,
|
||||
...((features.zlib || nativeFetch) && target.platform !== "win32" ? ["z"] : []),
|
||||
...(dynamic && target.platform !== "win32" ? ["m"] : []),
|
||||
...(curlFetch ? ["curl"] : []),
|
||||
]);
|
||||
return {
|
||||
sets,
|
||||
systemLibraries,
|
||||
driverFlags: [
|
||||
...commonTargetFlags,
|
||||
"-pthread",
|
||||
...executableSectionFlags.link,
|
||||
...target.executableLinkerArgs,
|
||||
],
|
||||
};
|
||||
}
|
||||
@@ -293,7 +318,7 @@ export async function createNativeLinkInfo(options: {
|
||||
target: {
|
||||
name: options.target.name,
|
||||
llvm_triple: options.target.llvmTriple,
|
||||
architecture: "arm64",
|
||||
architecture: options.target.architecture,
|
||||
object_format: options.target.objectFormat,
|
||||
minimum_os: options.target.minimumOs,
|
||||
relocation_model: options.target.relocationModel,
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import { createHash } from "node:crypto";
|
||||
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { dirname, join } from "node:path";
|
||||
import { afterEach, expect, test } from "vitest";
|
||||
import { loadRuntimePack, type RuntimePackManifest } from "./runtime-pack.js";
|
||||
import {
|
||||
LINUX_ARM64_GNU_TARGET,
|
||||
LINUX_ARM64_MUSL_TARGET,
|
||||
LINUX_X64_GNU_TARGET,
|
||||
LINUX_X64_MUSL_TARGET,
|
||||
MACOS_X64_TARGET,
|
||||
WASM32_WASI_TARGET,
|
||||
WINDOWS_X64_MSVC_TARGET,
|
||||
type NativeTargetSpec,
|
||||
} from "./targets.js";
|
||||
import { compilerReleaseVersion } from "../library/sidecar.js";
|
||||
|
||||
const dirs: string[] = [];
|
||||
afterEach(async () => Promise.all(dirs.splice(0).map((dir) => rm(dir, { recursive: true, force: true }))));
|
||||
|
||||
async function fixture(target: NativeTargetSpec) {
|
||||
const root = await mkdtemp(join(tmpdir(), "scriptc-runtime-pack-target-"));
|
||||
dirs.push(root);
|
||||
const packagePath = join(root, "package.json");
|
||||
const bytes = Buffer.from("runtime object");
|
||||
const artifact = { path: "artifacts/runtime.o", sha256: createHash("sha256").update(bytes).digest("hex"), size: bytes.length };
|
||||
await mkdir(dirname(join(root, artifact.path)), { recursive: true });
|
||||
await Promise.all([
|
||||
writeFile(join(root, artifact.path), bytes),
|
||||
writeFile(join(root, "LICENSE"), "license"),
|
||||
writeFile(packagePath, JSON.stringify({ name: target.runtimePackPackage, version: compilerReleaseVersion() })),
|
||||
]);
|
||||
const manifest: RuntimePackManifest = {
|
||||
schema: "scriptc.runtime-pack.v1", format: 1, package: target.runtimePackPackage, version: compilerReleaseVersion(),
|
||||
target: { name: target.name, llvm_triple: target.llvmTriple, architecture: target.architecture, object_format: target.objectFormat, minimum_os: target.minimumOs },
|
||||
runtime_abi: { version: 1, marker: "scr_runtime_abi_v1" },
|
||||
compiler: { command: "fixture", identity: "fixture", target: target.llvmTriple },
|
||||
macros: { executable: [], excluded: ["SCR_LIB"], sanitizer: "external-toolchain-required" },
|
||||
flavors: {
|
||||
release: { optimization: "-O2", runtime_units: [{ source: "scr_runtime.c", predicate: true, variants: [{ id: "default", when: {}, defines: [], ...artifact }] }] },
|
||||
dev: { optimization: "-O0", runtime_units: [{ source: "scr_runtime.c", predicate: true, variants: [{ id: "default", when: {}, defines: [], ...artifact }] }] },
|
||||
},
|
||||
archives: [], system_libraries: [], licenses: [{ path: "LICENSE", license: "fixture" }],
|
||||
};
|
||||
await writeFile(join(root, "runtime-pack.json"), JSON.stringify(manifest));
|
||||
return { packagePath };
|
||||
}
|
||||
|
||||
const features = {
|
||||
dynamic: false, regex: false, copying: false, textDecoderLegacy: false, fileHandle: false,
|
||||
fetch: false, netIsland: false, zlib: false, assert: false, inspect: false, dynInvoke: false,
|
||||
dc: false, dynAsync: false, events: false, emitter: false, symbol: false, searchParams: false,
|
||||
qs: false, parseArgs: false, stream: false, net: false, http: false, http2: false,
|
||||
dgram: false, watch: false, foreignFfi: false, nodeTest: false, tls: false, tlsCa: false,
|
||||
};
|
||||
|
||||
test.each([
|
||||
MACOS_X64_TARGET, LINUX_X64_GNU_TARGET, LINUX_ARM64_GNU_TARGET,
|
||||
WINDOWS_X64_MSVC_TARGET, LINUX_X64_MUSL_TARGET, LINUX_ARM64_MUSL_TARGET, WASM32_WASI_TARGET,
|
||||
])("runtime-pack validation selects the exact $name package", async (target) => {
|
||||
const pack = await fixture(target);
|
||||
const result = await loadRuntimePack({ target, features, optimization: "release", resolver: () => pack.packagePath });
|
||||
expect(result.manifest.package).toBe(target.runtimePackPackage);
|
||||
expect(result.manifest.target).toMatchObject({ name: target.name, architecture: target.architecture, object_format: target.objectFormat });
|
||||
});
|
||||
@@ -51,7 +51,7 @@ export interface RuntimePackManifest {
|
||||
target: {
|
||||
name: NativeTargetSpec["name"];
|
||||
llvm_triple: NativeTargetSpec["llvmTriple"];
|
||||
architecture: "arm64";
|
||||
architecture: NativeTargetSpec["architecture"];
|
||||
object_format: NativeTargetSpec["objectFormat"];
|
||||
minimum_os: NativeTargetSpec["minimumOs"];
|
||||
};
|
||||
@@ -157,11 +157,10 @@ export function parseRuntimePackManifest(value: unknown): RuntimePackManifest {
|
||||
if (
|
||||
manifest?.schema !== RUNTIME_PACK_SCHEMA || manifest.format !== RUNTIME_PACK_FORMAT ||
|
||||
typeof manifest.package !== "string" || typeof manifest.version !== "string" ||
|
||||
target?.name !== "macos-arm64" || target.llvm_triple !== "arm64-apple-macosx14.0.0" ||
|
||||
target.architecture !== "arm64" || target.object_format !== "macho" || target.minimum_os !== "14.0" ||
|
||||
!isRuntimePackTarget(target) ||
|
||||
abi?.version !== RUNTIME_ABI_VERSION || abi.marker !== RUNTIME_ABI_MARKER ||
|
||||
typeof compiler?.command !== "string" || typeof compiler.identity !== "string" ||
|
||||
compiler.target !== target.llvm_triple ||
|
||||
compiler.target !== (target?.llvm_triple) ||
|
||||
!Array.isArray(macros?.executable) || !macros.executable.every((entry) => typeof entry === "string") ||
|
||||
!Array.isArray(macros.excluded) || !macros.excluded.every((entry) => typeof entry === "string") ||
|
||||
macros.sanitizer !== "external-toolchain-required" ||
|
||||
@@ -182,6 +181,15 @@ export function parseRuntimePackManifest(value: unknown): RuntimePackManifest {
|
||||
return manifest as unknown as RuntimePackManifest;
|
||||
}
|
||||
|
||||
function isRuntimePackTarget(target: Record<string, unknown> | null): boolean {
|
||||
return target !== null &&
|
||||
typeof target.name === "string" &&
|
||||
typeof target.llvm_triple === "string" &&
|
||||
(target.architecture === "arm64" || target.architecture === "x64" || target.architecture === "wasm32") &&
|
||||
(target.object_format === "macho" || target.object_format === "elf" || target.object_format === "coff" || target.object_format === "wasm") &&
|
||||
typeof target.minimum_os === "string";
|
||||
}
|
||||
|
||||
export function effectiveRuntimeFeatures(
|
||||
features: NativeLinkFeatures,
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
@@ -324,16 +332,14 @@ export async function loadRuntimePack(options: {
|
||||
env?: NodeJS.ProcessEnv;
|
||||
resolver?: (specifier: string) => string;
|
||||
}): Promise<RuntimePackSelection> {
|
||||
const packageName = options.target.name === "macos-arm64"
|
||||
? "@scriptc/runtime-darwin-arm64"
|
||||
: (() => { throw new RuntimePackError(`no runtime pack supports ${options.target.name}`, "unsupported"); })();
|
||||
const packageName = options.target.runtimePackPackage;
|
||||
const resolvePackageJson = options.resolver ?? ((specifier: string) => createRequire(import.meta.url).resolve(specifier));
|
||||
let packagePath: string;
|
||||
try {
|
||||
packagePath = resolvePackageJson(`${packageName}/package.json`);
|
||||
} catch {
|
||||
throw new RuntimePackError(
|
||||
`precompiled runtime package ${packageName} is not installed; reinstall scriptc with optional dependencies enabled for macOS arm64`,
|
||||
`precompiled runtime package ${packageName} is not installed; reinstall scriptc with optional dependencies enabled for ${options.target.name}`,
|
||||
"missing",
|
||||
);
|
||||
}
|
||||
@@ -368,6 +374,7 @@ export async function loadRuntimePack(options: {
|
||||
if (
|
||||
manifest.target.name !== options.target.name ||
|
||||
manifest.target.llvm_triple !== options.target.llvmTriple ||
|
||||
manifest.target.architecture !== options.target.architecture ||
|
||||
manifest.target.object_format !== options.target.objectFormat ||
|
||||
manifest.target.minimum_os !== options.target.minimumOs
|
||||
) throw new RuntimePackError(`runtime pack does not support target ${options.target.name}`, "invalid");
|
||||
|
||||
@@ -1,12 +1,34 @@
|
||||
import { describe, expect, test } from "vitest";
|
||||
import { MACOS_ARM64_TARGET, nativeCodegenTarget, nativeCodegenTargetRefusal } from "./targets.js";
|
||||
import {
|
||||
LINUX_ARM64_GNU_TARGET,
|
||||
LINUX_ARM64_MUSL_TARGET,
|
||||
LINUX_X64_GNU_TARGET,
|
||||
LINUX_X64_MUSL_TARGET,
|
||||
MACOS_ARM64_TARGET,
|
||||
MACOS_X64_TARGET,
|
||||
WASM32_WASI_TARGET,
|
||||
WINDOWS_X64_MSVC_TARGET,
|
||||
nativeCodegenTarget,
|
||||
nativeCodegenTargetRefusal,
|
||||
} from "./targets.js";
|
||||
|
||||
describe("native code-generation targets", () => {
|
||||
test("admits only host-native macOS arm64", () => {
|
||||
test("selects only fully specified host-native targets", () => {
|
||||
expect(nativeCodegenTarget({}, "darwin", "arm64", "24.0.0")).toEqual(MACOS_ARM64_TARGET);
|
||||
expect(nativeCodegenTarget({}, "darwin", "x64", "24.0.0")).toEqual(MACOS_X64_TARGET);
|
||||
expect(nativeCodegenTarget({}, "linux", "x64", "6.8.0", "gnu")).toEqual(LINUX_X64_GNU_TARGET);
|
||||
expect(nativeCodegenTarget({}, "linux", "arm64", "6.8.0", "gnu")).toEqual(LINUX_ARM64_GNU_TARGET);
|
||||
expect(nativeCodegenTarget({}, "linux", "x64", "6.8.0", "musl")).toEqual(LINUX_X64_MUSL_TARGET);
|
||||
expect(nativeCodegenTarget({}, "linux", "arm64", "6.8.0", "musl")).toEqual(LINUX_ARM64_MUSL_TARGET);
|
||||
expect(nativeCodegenTarget({}, "win32", "x64", "10.0.0")).toEqual(WINDOWS_X64_MSVC_TARGET);
|
||||
expect(nativeCodegenTarget({}, "darwin", "arm64", "23.6.0")).toBeNull();
|
||||
expect(nativeCodegenTarget({}, "darwin", "x64", "24.0.0")).toBeNull();
|
||||
expect(nativeCodegenTarget({}, "linux", "arm64", "6.8.0")).toBeNull();
|
||||
expect(nativeCodegenTarget({}, "linux", "ia32", "6.8.0")).toBeNull();
|
||||
expect(nativeCodegenTarget({ SCRIPTC_TARGET: "x86_64-linux-musl" }, "linux", "x64", "6.8.0", "musl"))
|
||||
.toEqual(LINUX_X64_MUSL_TARGET);
|
||||
expect(nativeCodegenTarget({ SCRIPTC_TARGET: "aarch64-linux-musl" }, "linux", "arm64", "6.8.0", "musl"))
|
||||
.toEqual(LINUX_ARM64_MUSL_TARGET);
|
||||
expect(nativeCodegenTarget({ SCRIPTC_TARGET: "wasm32-wasi" }, "darwin", "x64", "24.0.0"))
|
||||
.toEqual(WASM32_WASI_TARGET);
|
||||
expect(nativeCodegenTarget(
|
||||
{ SCRIPTC_TARGET: "aarch64-apple-ios" }, "darwin", "arm64", "24.0.0",
|
||||
))
|
||||
@@ -14,7 +36,7 @@ describe("native code-generation targets", () => {
|
||||
});
|
||||
|
||||
test("refusals name the unsupported host or cross target", () => {
|
||||
expect(nativeCodegenTargetRefusal({}, "linux", "x64", "6.8.0")).toContain("linux x64");
|
||||
expect(nativeCodegenTargetRefusal({}, "linux", "ia32", "6.8.0")).toContain("linux ia32");
|
||||
expect(nativeCodegenTargetRefusal({}, "darwin", "arm64", "23.6.0"))
|
||||
.toContain("requires macOS 15.0 or newer");
|
||||
expect(nativeCodegenTargetRefusal(
|
||||
@@ -33,4 +55,8 @@ describe("native code-generation targets", () => {
|
||||
"-Wl,-dead_strip",
|
||||
]);
|
||||
});
|
||||
|
||||
test("describes the WASI relocatable-object ABI", () => {
|
||||
expect(WASM32_WASI_TARGET.supports).toMatchObject({ asm: true, obj: true, exe: true });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,60 +1,360 @@
|
||||
import { release } from "node:os";
|
||||
|
||||
/** A helper package is host-specific, even when it emits a portable target
|
||||
* (the WASI helpers are the first intentionally cross-host case). */
|
||||
export interface NativeHelperSpec {
|
||||
packageName: string;
|
||||
/** The helper protocol reports this primary target and its layout. */
|
||||
defaultTarget: string;
|
||||
defaultDataLayout: string;
|
||||
backend: "AArch64" | "X86" | "WebAssembly";
|
||||
}
|
||||
|
||||
export type NativeTargetName =
|
||||
| "macos-arm64"
|
||||
| "macos-x64"
|
||||
| "linux-x64-gnu"
|
||||
| "linux-arm64-gnu"
|
||||
| "windows-x64-msvc"
|
||||
| "linux-x64-musl"
|
||||
| "linux-arm64-musl"
|
||||
| "wasm32-wasi";
|
||||
|
||||
export type NativeObjectFormat = "macho" | "elf" | "coff" | "wasm";
|
||||
export type NativeTargetPlatform = "darwin" | "linux" | "win32" | "wasi";
|
||||
|
||||
export interface NativeTargetSpec {
|
||||
/** Stable scriptc-facing identity used in cache keys and diagnostics. */
|
||||
name: "macos-arm64";
|
||||
llvmTriple: "arm64-apple-macosx14.0.0";
|
||||
dataLayout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32";
|
||||
name: NativeTargetName;
|
||||
llvmTriple: string;
|
||||
dataLayout: string;
|
||||
cpu: "generic";
|
||||
features: "";
|
||||
pointerBits: 64;
|
||||
pointerBits: 32 | 64;
|
||||
endianness: "little";
|
||||
objectFormat: "macho";
|
||||
objectFormat: NativeObjectFormat;
|
||||
relocationModel: "pic";
|
||||
codeModel: "small";
|
||||
minimumOs: "14.0";
|
||||
helperMinimumOs: "15.0";
|
||||
outputSuffixes: { asm: ".s"; obj: ".o"; exe: "" };
|
||||
/** OS deployment level, libc floor, or WASI ABI contract. */
|
||||
minimumOs: string;
|
||||
/** Minimum host contract for the helper package itself. */
|
||||
helperMinimumOs: string;
|
||||
architecture: "arm64" | "x64" | "wasm32";
|
||||
platform: NativeTargetPlatform;
|
||||
outputSuffixes: { asm: ".s" | ".asm"; obj: ".o" | ".obj"; exe: "" | ".exe" | ".wasm" };
|
||||
/** Arguments for the platform linker driver once scriptc has produced an
|
||||
* object. These are target ABI policy, rather than C compiler settings. */
|
||||
executableLinkerArgs: readonly ["-target", "arm64-apple-macosx14.0.0", "-pthread", "-Wl,-dead_strip"];
|
||||
supports: { asm: true; obj: true; exe: true; library: false };
|
||||
helperPackage: "@scriptc/llvm-darwin-arm64";
|
||||
executableLinkerArgs: readonly string[];
|
||||
defaultLinker: string;
|
||||
defaultLinkerArgs: readonly string[];
|
||||
/** Driver spelling for the native-codegen triple. Linker drivers such as
|
||||
* zig use a different user-facing triple from LLVM's canonical spelling. */
|
||||
linkerTargetTriple: string;
|
||||
runtimeSystemLibraries: readonly string[];
|
||||
/** A source-level flag needed by the matching precompiled runtime units.
|
||||
* The helper's program object never needs this (it is already LLVM IR). */
|
||||
runtimeCompileDefines: readonly string[];
|
||||
supports: { asm: boolean; obj: boolean; exe: boolean; library: boolean };
|
||||
/** Primary host-native helper. The resolved helper can differ for WASI. */
|
||||
helperPackage: string;
|
||||
helper: NativeHelperSpec;
|
||||
llvmBackend: NativeHelperSpec["backend"];
|
||||
hostHelpers?: Partial<Record<NativeHelperHost, NativeHelperSpec>>;
|
||||
runtimePackPackage: string;
|
||||
}
|
||||
|
||||
export const MACOS_ARM64_TARGET: NativeTargetSpec = {
|
||||
name: "macos-arm64",
|
||||
llvmTriple: "arm64-apple-macosx14.0.0",
|
||||
dataLayout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32",
|
||||
cpu: "generic",
|
||||
features: "",
|
||||
pointerBits: 64,
|
||||
endianness: "little",
|
||||
objectFormat: "macho",
|
||||
relocationModel: "pic",
|
||||
codeModel: "small",
|
||||
minimumOs: "14.0",
|
||||
helperMinimumOs: "15.0",
|
||||
outputSuffixes: { asm: ".s", obj: ".o", exe: "" },
|
||||
executableLinkerArgs: ["-target", "arm64-apple-macosx14.0.0", "-pthread", "-Wl,-dead_strip"],
|
||||
supports: { asm: true, obj: true, exe: true, library: false },
|
||||
helperPackage: "@scriptc/llvm-darwin-arm64",
|
||||
export type NativeHelperHost =
|
||||
| "darwin-arm64"
|
||||
| "darwin-x64"
|
||||
| "linux-x64-gnu"
|
||||
| "linux-x64-musl"
|
||||
| "linux-arm64-gnu"
|
||||
| "linux-arm64-musl"
|
||||
| "win32-x64";
|
||||
|
||||
export type LinuxLibc = "gnu" | "musl";
|
||||
|
||||
const ARM64_DARWIN_LAYOUT = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32";
|
||||
const X64_DARWIN_LAYOUT = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128";
|
||||
const X64_ELF_LAYOUT = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128";
|
||||
const ARM64_ELF_LAYOUT = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32";
|
||||
const X64_COFF_LAYOUT = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128";
|
||||
const WASI_LAYOUT = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20";
|
||||
|
||||
const DARWIN_ARM64_HELPER: NativeHelperSpec = {
|
||||
packageName: "@scriptc/llvm-darwin-arm64",
|
||||
defaultTarget: "arm64-apple-macosx14.0.0",
|
||||
defaultDataLayout: ARM64_DARWIN_LAYOUT,
|
||||
backend: "AArch64",
|
||||
};
|
||||
const DARWIN_X64_HELPER: NativeHelperSpec = {
|
||||
packageName: "@scriptc/llvm-darwin-x64",
|
||||
defaultTarget: "x86_64-apple-macosx14.0.0",
|
||||
defaultDataLayout: X64_DARWIN_LAYOUT,
|
||||
backend: "X86",
|
||||
};
|
||||
const LINUX_X64_HELPER: NativeHelperSpec = {
|
||||
packageName: "@scriptc/llvm-linux-x64-gnu",
|
||||
defaultTarget: "x86_64-unknown-linux-gnu",
|
||||
defaultDataLayout: X64_ELF_LAYOUT,
|
||||
backend: "X86",
|
||||
};
|
||||
const LINUX_ARM64_HELPER: NativeHelperSpec = {
|
||||
packageName: "@scriptc/llvm-linux-arm64-gnu",
|
||||
defaultTarget: "aarch64-unknown-linux-gnu",
|
||||
defaultDataLayout: ARM64_ELF_LAYOUT,
|
||||
backend: "AArch64",
|
||||
};
|
||||
const LINUX_X64_MUSL_HELPER: NativeHelperSpec = {
|
||||
packageName: "@scriptc/llvm-linux-x64-musl",
|
||||
defaultTarget: "x86_64-unknown-linux-musl",
|
||||
defaultDataLayout: X64_ELF_LAYOUT,
|
||||
backend: "X86",
|
||||
};
|
||||
const LINUX_ARM64_MUSL_HELPER: NativeHelperSpec = {
|
||||
packageName: "@scriptc/llvm-linux-arm64-musl",
|
||||
defaultTarget: "aarch64-unknown-linux-musl",
|
||||
defaultDataLayout: ARM64_ELF_LAYOUT,
|
||||
backend: "AArch64",
|
||||
};
|
||||
const WINDOWS_X64_HELPER: NativeHelperSpec = {
|
||||
packageName: "@scriptc/llvm-win32-x64-msvc",
|
||||
defaultTarget: "x86_64-pc-windows-msvc",
|
||||
defaultDataLayout: X64_COFF_LAYOUT,
|
||||
backend: "X86",
|
||||
};
|
||||
|
||||
export const MACOS_ARM64_TARGET: NativeTargetSpec = {
|
||||
name: "macos-arm64", llvmTriple: "arm64-apple-macosx14.0.0", dataLayout: ARM64_DARWIN_LAYOUT,
|
||||
cpu: "generic", features: "", pointerBits: 64, endianness: "little", objectFormat: "macho",
|
||||
relocationModel: "pic", codeModel: "small", minimumOs: "14.0", helperMinimumOs: "15.0",
|
||||
architecture: "arm64", platform: "darwin", outputSuffixes: { asm: ".s", obj: ".o", exe: "" },
|
||||
executableLinkerArgs: ["-target", "arm64-apple-macosx14.0.0", "-pthread", "-Wl,-dead_strip"],
|
||||
defaultLinker: "clang", defaultLinkerArgs: [], runtimeSystemLibraries: ["System"],
|
||||
linkerTargetTriple: "arm64-apple-macosx14.0.0",
|
||||
runtimeCompileDefines: [],
|
||||
supports: { asm: true, obj: true, exe: true, library: false },
|
||||
helperPackage: DARWIN_ARM64_HELPER.packageName, helper: DARWIN_ARM64_HELPER,
|
||||
llvmBackend: "AArch64",
|
||||
runtimePackPackage: "@scriptc/runtime-darwin-arm64",
|
||||
};
|
||||
|
||||
export const MACOS_X64_TARGET: NativeTargetSpec = {
|
||||
name: "macos-x64", llvmTriple: "x86_64-apple-macosx14.0.0", dataLayout: X64_DARWIN_LAYOUT,
|
||||
cpu: "generic", features: "", pointerBits: 64, endianness: "little", objectFormat: "macho",
|
||||
relocationModel: "pic", codeModel: "small", minimumOs: "14.0", helperMinimumOs: "15.0",
|
||||
architecture: "x64", platform: "darwin", outputSuffixes: { asm: ".s", obj: ".o", exe: "" },
|
||||
executableLinkerArgs: ["-target", "x86_64-apple-macosx14.0.0", "-pthread", "-Wl,-dead_strip"],
|
||||
defaultLinker: "clang", defaultLinkerArgs: [], runtimeSystemLibraries: ["System"],
|
||||
linkerTargetTriple: "x86_64-apple-macosx14.0.0",
|
||||
runtimeCompileDefines: [],
|
||||
supports: { asm: true, obj: true, exe: true, library: false },
|
||||
helperPackage: DARWIN_X64_HELPER.packageName, helper: DARWIN_X64_HELPER,
|
||||
llvmBackend: "X86",
|
||||
runtimePackPackage: "@scriptc/runtime-darwin-x64",
|
||||
};
|
||||
|
||||
export const LINUX_X64_GNU_TARGET: NativeTargetSpec = {
|
||||
name: "linux-x64-gnu", llvmTriple: "x86_64-unknown-linux-gnu", dataLayout: X64_ELF_LAYOUT,
|
||||
cpu: "generic", features: "", pointerBits: 64, endianness: "little", objectFormat: "elf",
|
||||
relocationModel: "pic", codeModel: "small", minimumOs: "glibc 2.36", helperMinimumOs: "glibc 2.35",
|
||||
architecture: "x64", platform: "linux", outputSuffixes: { asm: ".s", obj: ".o", exe: "" },
|
||||
executableLinkerArgs: ["-target", "x86_64-unknown-linux-gnu", "-pthread", "-Wl,--gc-sections"],
|
||||
defaultLinker: "clang", defaultLinkerArgs: [], runtimeSystemLibraries: ["m"],
|
||||
linkerTargetTriple: "x86_64-unknown-linux-gnu",
|
||||
runtimeCompileDefines: ["_GNU_SOURCE"],
|
||||
supports: { asm: true, obj: true, exe: true, library: true },
|
||||
helperPackage: LINUX_X64_HELPER.packageName, helper: LINUX_X64_HELPER,
|
||||
llvmBackend: "X86",
|
||||
runtimePackPackage: "@scriptc/runtime-linux-x64-gnu",
|
||||
};
|
||||
|
||||
export const LINUX_ARM64_GNU_TARGET: NativeTargetSpec = {
|
||||
name: "linux-arm64-gnu", llvmTriple: "aarch64-unknown-linux-gnu", dataLayout: ARM64_ELF_LAYOUT,
|
||||
cpu: "generic", features: "", pointerBits: 64, endianness: "little", objectFormat: "elf",
|
||||
relocationModel: "pic", codeModel: "small", minimumOs: "glibc 2.36", helperMinimumOs: "glibc 2.35",
|
||||
architecture: "arm64", platform: "linux", outputSuffixes: { asm: ".s", obj: ".o", exe: "" },
|
||||
executableLinkerArgs: ["-target", "aarch64-unknown-linux-gnu", "-pthread", "-Wl,--gc-sections"],
|
||||
defaultLinker: "clang", defaultLinkerArgs: [], runtimeSystemLibraries: ["m"],
|
||||
linkerTargetTriple: "aarch64-unknown-linux-gnu",
|
||||
runtimeCompileDefines: ["_GNU_SOURCE"],
|
||||
supports: { asm: true, obj: true, exe: true, library: true },
|
||||
helperPackage: LINUX_ARM64_HELPER.packageName, helper: LINUX_ARM64_HELPER,
|
||||
llvmBackend: "AArch64",
|
||||
runtimePackPackage: "@scriptc/runtime-linux-arm64-gnu",
|
||||
};
|
||||
|
||||
export const WINDOWS_X64_MSVC_TARGET: NativeTargetSpec = {
|
||||
name: "windows-x64-msvc", llvmTriple: "x86_64-pc-windows-msvc", dataLayout: X64_COFF_LAYOUT,
|
||||
cpu: "generic", features: "", pointerBits: 64, endianness: "little", objectFormat: "coff",
|
||||
relocationModel: "pic", codeModel: "small", minimumOs: "Windows 10", helperMinimumOs: "Windows 10",
|
||||
architecture: "x64", platform: "win32", outputSuffixes: { asm: ".asm", obj: ".obj", exe: ".exe" },
|
||||
// The runtime pack is built against Zig's MinGW-compatible Windows sysroot;
|
||||
// its x64 COFF ABI is compatible with the helper's MSVC-flavored object.
|
||||
executableLinkerArgs: ["-target", "x86_64-windows-gnu", "-Wl,--gc-sections"],
|
||||
defaultLinker: "zig", defaultLinkerArgs: ["cc"], runtimeSystemLibraries: ["advapi32", "iphlpapi", "ws2_32"],
|
||||
linkerTargetTriple: "x86_64-windows-gnu",
|
||||
runtimeCompileDefines: [],
|
||||
supports: { asm: true, obj: true, exe: true, library: true },
|
||||
helperPackage: WINDOWS_X64_HELPER.packageName, helper: WINDOWS_X64_HELPER,
|
||||
llvmBackend: "X86",
|
||||
runtimePackPackage: "@scriptc/runtime-win32-x64-msvc",
|
||||
};
|
||||
|
||||
export const LINUX_X64_MUSL_TARGET: NativeTargetSpec = {
|
||||
...LINUX_X64_GNU_TARGET,
|
||||
name: "linux-x64-musl", llvmTriple: "x86_64-unknown-linux-musl",
|
||||
minimumOs: "musl 1.2", helperMinimumOs: "glibc 2.35",
|
||||
executableLinkerArgs: ["-target", "x86_64-unknown-linux-musl", "-pthread", "-Wl,--gc-sections"],
|
||||
defaultLinker: "zig", defaultLinkerArgs: ["cc"], linkerTargetTriple: "x86_64-linux-musl",
|
||||
runtimePackPackage: "@scriptc/runtime-linux-x64-musl",
|
||||
runtimeCompileDefines: ["_GNU_SOURCE", "SCR_MUSL"],
|
||||
helperPackage: LINUX_X64_MUSL_HELPER.packageName,
|
||||
helper: LINUX_X64_MUSL_HELPER,
|
||||
};
|
||||
|
||||
export const LINUX_ARM64_MUSL_TARGET: NativeTargetSpec = {
|
||||
...LINUX_ARM64_GNU_TARGET,
|
||||
name: "linux-arm64-musl", llvmTriple: "aarch64-unknown-linux-musl",
|
||||
minimumOs: "musl 1.2", helperMinimumOs: "glibc 2.35",
|
||||
executableLinkerArgs: ["-target", "aarch64-unknown-linux-musl", "-pthread", "-Wl,--gc-sections"],
|
||||
defaultLinker: "zig", defaultLinkerArgs: ["cc"], linkerTargetTriple: "aarch64-linux-musl",
|
||||
runtimePackPackage: "@scriptc/runtime-linux-arm64-musl",
|
||||
runtimeCompileDefines: ["_GNU_SOURCE", "SCR_MUSL"],
|
||||
helperPackage: LINUX_ARM64_MUSL_HELPER.packageName,
|
||||
helper: LINUX_ARM64_MUSL_HELPER,
|
||||
};
|
||||
|
||||
export const WASM32_WASI_TARGET: NativeTargetSpec = {
|
||||
name: "wasm32-wasi", llvmTriple: "wasm32-unknown-wasi", dataLayout: WASI_LAYOUT,
|
||||
cpu: "generic", features: "", pointerBits: 32, endianness: "little", objectFormat: "wasm",
|
||||
relocationModel: "pic", codeModel: "small", minimumOs: "WASI Preview 1", helperMinimumOs: "host helper contract",
|
||||
architecture: "wasm32", platform: "wasi", outputSuffixes: { asm: ".s", obj: ".o", exe: ".wasm" },
|
||||
executableLinkerArgs: ["-target", "wasm32-wasi"], defaultLinker: "zig", defaultLinkerArgs: ["cc"],
|
||||
linkerTargetTriple: "wasm32-wasi",
|
||||
runtimeSystemLibraries: ["wasi-emulated-signal", "wasi-emulated-process-clocks"],
|
||||
runtimeCompileDefines: ["_GNU_SOURCE", "_WASI_EMULATED_SIGNAL", "_WASI_EMULATED_PROCESS_CLOCKS"],
|
||||
supports: { asm: true, obj: true, exe: true, library: false },
|
||||
helperPackage: DARWIN_ARM64_HELPER.packageName, helper: DARWIN_ARM64_HELPER,
|
||||
llvmBackend: "WebAssembly",
|
||||
hostHelpers: {
|
||||
"darwin-arm64": DARWIN_ARM64_HELPER,
|
||||
"darwin-x64": DARWIN_X64_HELPER,
|
||||
"linux-x64-gnu": LINUX_X64_HELPER,
|
||||
"linux-x64-musl": LINUX_X64_MUSL_HELPER,
|
||||
"linux-arm64-gnu": LINUX_ARM64_HELPER,
|
||||
"linux-arm64-musl": LINUX_ARM64_MUSL_HELPER,
|
||||
"win32-x64": WINDOWS_X64_HELPER,
|
||||
},
|
||||
runtimePackPackage: "@scriptc/runtime-wasm32-wasi",
|
||||
};
|
||||
|
||||
export const NATIVE_TARGETS = [
|
||||
MACOS_ARM64_TARGET, MACOS_X64_TARGET, LINUX_X64_GNU_TARGET,
|
||||
LINUX_ARM64_GNU_TARGET, WINDOWS_X64_MSVC_TARGET, LINUX_X64_MUSL_TARGET,
|
||||
LINUX_ARM64_MUSL_TARGET, WASM32_WASI_TARGET,
|
||||
] as const;
|
||||
|
||||
function detectedLinuxLibc(): LinuxLibc {
|
||||
// Node exposes glibc's runtime version without any external command or
|
||||
// filesystem probe. Its absence on Linux is the portable musl signal used
|
||||
// by npm's own optional-dependency selection conventions.
|
||||
const report = process.report?.getReport() as { header?: { glibcVersionRuntime?: unknown } } | undefined;
|
||||
const header = report?.header;
|
||||
return typeof header?.glibcVersionRuntime === "string" ? "gnu" : "musl";
|
||||
}
|
||||
|
||||
function helperHost(
|
||||
platform: NodeJS.Platform,
|
||||
arch: string,
|
||||
linuxLibc: LinuxLibc = detectedLinuxLibc(),
|
||||
): NativeHelperHost | null {
|
||||
if (platform === "darwin" && arch === "arm64") return "darwin-arm64";
|
||||
if (platform === "darwin" && arch === "x64") return "darwin-x64";
|
||||
if (platform === "linux" && arch === "x64") return `linux-x64-${linuxLibc}`;
|
||||
if (platform === "linux" && arch === "arm64") return `linux-arm64-${linuxLibc}`;
|
||||
if (platform === "win32" && arch === "x64") return "win32-x64";
|
||||
return null;
|
||||
}
|
||||
|
||||
export function nativeHelperForTarget(
|
||||
target: NativeTargetSpec,
|
||||
hostPlatform: NodeJS.Platform = process.platform,
|
||||
hostArch: string = process.arch,
|
||||
linuxLibc?: LinuxLibc,
|
||||
): NativeHelperSpec | null {
|
||||
const host = helperHost(hostPlatform, hostArch, linuxLibc);
|
||||
if (host === null) return null;
|
||||
return target.hostHelpers?.[host] ?? (
|
||||
target.platform === hostPlatform && target.architecture === hostArch ? target.helper : null
|
||||
);
|
||||
}
|
||||
|
||||
function nativeHostTarget(
|
||||
hostPlatform: NodeJS.Platform,
|
||||
hostArch: string,
|
||||
hostRelease: string,
|
||||
linuxLibc: LinuxLibc,
|
||||
): NativeTargetSpec | null {
|
||||
if (hostPlatform === "darwin") {
|
||||
const major = Number.parseInt(hostRelease.split(".", 1)[0] ?? "", 10);
|
||||
if (!Number.isFinite(major) || major < 24) return null;
|
||||
return hostArch === "arm64" ? MACOS_ARM64_TARGET : hostArch === "x64" ? MACOS_X64_TARGET : null;
|
||||
}
|
||||
if (hostPlatform === "linux") {
|
||||
return hostArch === "x64"
|
||||
? linuxLibc === "musl" ? LINUX_X64_MUSL_TARGET : LINUX_X64_GNU_TARGET
|
||||
: hostArch === "arm64"
|
||||
? linuxLibc === "musl" ? LINUX_ARM64_MUSL_TARGET : LINUX_ARM64_GNU_TARGET
|
||||
: null;
|
||||
}
|
||||
return hostPlatform === "win32" && hostArch === "x64" ? WINDOWS_X64_MSVC_TARGET : null;
|
||||
}
|
||||
|
||||
function requestedTarget(
|
||||
raw: string,
|
||||
host: NativeTargetSpec | null,
|
||||
hostPlatform: NodeJS.Platform,
|
||||
hostArch: string,
|
||||
linuxLibc: LinuxLibc,
|
||||
): NativeTargetSpec | null {
|
||||
if (raw === "") return host;
|
||||
switch (raw) {
|
||||
case "arm64-apple-macosx14.0.0": return host?.name === "macos-arm64" ? MACOS_ARM64_TARGET : null;
|
||||
case "x86_64-apple-macosx14.0.0":
|
||||
case "x86_64-apple-macos": return host?.name === "macos-x64" ? MACOS_X64_TARGET : null;
|
||||
case "x86_64-unknown-linux-gnu":
|
||||
case "x86_64-linux-gnu":
|
||||
case "x86_64-linux-gnu.2.36": return host?.name === "linux-x64-gnu" ? LINUX_X64_GNU_TARGET : null;
|
||||
case "aarch64-unknown-linux-gnu":
|
||||
case "aarch64-linux-gnu":
|
||||
case "aarch64-linux-gnu.2.36": return host?.name === "linux-arm64-gnu" ? LINUX_ARM64_GNU_TARGET : null;
|
||||
case "x86_64-unknown-linux-musl":
|
||||
case "x86_64-linux-musl":
|
||||
return host?.platform === "linux" && host.architecture === "x64" ? LINUX_X64_MUSL_TARGET : null;
|
||||
case "aarch64-unknown-linux-musl":
|
||||
case "aarch64-linux-musl":
|
||||
return host?.platform === "linux" && host.architecture === "arm64" ? LINUX_ARM64_MUSL_TARGET : null;
|
||||
case "wasm32-wasi":
|
||||
case "wasm32-unknown-wasi":
|
||||
return helperHost(hostPlatform, hostArch, linuxLibc) === null ? null : WASM32_WASI_TARGET;
|
||||
case "x86_64-pc-windows-msvc": return host?.name === "windows-x64-msvc" ? WINDOWS_X64_MSVC_TARGET : null;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Select only a fully described scriptc target. LLVM accepting an arbitrary
|
||||
* triple is never evidence of its object ABI, runtime pack, link, or run. */
|
||||
export function nativeCodegenTarget(
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
hostPlatform: NodeJS.Platform = process.platform,
|
||||
hostArch: string = process.arch,
|
||||
hostRelease: string = release(),
|
||||
linuxLibc: LinuxLibc = detectedLinuxLibc(),
|
||||
): NativeTargetSpec | null {
|
||||
// The first helper is host-native only. In particular, do not reinterpret
|
||||
// an existing SCRIPTC_TARGET cross-build as macOS merely because its OS
|
||||
// family is Darwin.
|
||||
if ((env["SCRIPTC_TARGET"] ?? "") !== "") return null;
|
||||
const darwinMajor = Number.parseInt(hostRelease.split(".", 1)[0] ?? "", 10);
|
||||
return hostPlatform === "darwin" && hostArch === "arm64" && darwinMajor >= 24
|
||||
? MACOS_ARM64_TARGET
|
||||
: null;
|
||||
const host = nativeHostTarget(hostPlatform, hostArch, hostRelease, linuxLibc);
|
||||
const target = requestedTarget(env["SCRIPTC_TARGET"] ?? "", host, hostPlatform, hostArch, linuxLibc);
|
||||
return target !== null && nativeHelperForTarget(target, hostPlatform, hostArch, linuxLibc) !== null ? target : null;
|
||||
}
|
||||
|
||||
export function nativeCodegenTargetRefusal(
|
||||
@@ -62,18 +362,17 @@ export function nativeCodegenTargetRefusal(
|
||||
hostPlatform: NodeJS.Platform = process.platform,
|
||||
hostArch: string = process.arch,
|
||||
hostRelease: string = release(),
|
||||
linuxLibc: LinuxLibc = detectedLinuxLibc(),
|
||||
): string | null {
|
||||
if (nativeCodegenTarget(env, hostPlatform, hostArch, hostRelease) !== null) return null;
|
||||
const crossTarget = env["SCRIPTC_TARGET"] ?? "";
|
||||
if (crossTarget !== "") {
|
||||
return `native assembly/object emission does not support SCRIPTC_TARGET=${crossTarget}; the first supported target is host-native macOS arm64`;
|
||||
if (nativeCodegenTarget(env, hostPlatform, hostArch, hostRelease, linuxLibc) !== null) return null;
|
||||
const requested = env["SCRIPTC_TARGET"] ?? "";
|
||||
if (requested !== "") {
|
||||
return `native assembly/object emission does not support SCRIPTC_TARGET=${requested} on this ${hostPlatform} ${hostArch} host; supported hosts are macOS arm64/x64, Linux x64/arm64, and Windows x64 (with wasm32-wasi on each)`;
|
||||
}
|
||||
if (hostPlatform === "darwin" && hostArch === "arm64") {
|
||||
const darwinMajor = Number.parseInt(hostRelease.split(".", 1)[0] ?? "", 10);
|
||||
const macosMajor = Number.isFinite(darwinMajor) && darwinMajor >= 20
|
||||
? String(darwinMajor - 9)
|
||||
: "unknown";
|
||||
return `native assembly/object emission requires macOS ${MACOS_ARM64_TARGET.helperMinimumOs} or newer; this host is macOS ${macosMajor} (Darwin ${hostRelease})`;
|
||||
if (hostPlatform === "darwin" && (hostArch === "arm64" || hostArch === "x64")) {
|
||||
const major = Number.parseInt(hostRelease.split(".", 1)[0] ?? "", 10);
|
||||
const macos = Number.isFinite(major) && major >= 20 ? String(major - 9) : "unknown";
|
||||
return `native assembly/object emission requires macOS 15.0 or newer; this host is macOS ${macos} (Darwin ${hostRelease})`;
|
||||
}
|
||||
return `native assembly/object emission is supported on macOS arm64 hosts; this host is ${hostPlatform} ${hostArch}`;
|
||||
return `native assembly/object emission is supported on macOS arm64/x64, Linux x64/arm64, and Windows x64 hosts; this host is ${hostPlatform} ${hostArch}`;
|
||||
}
|
||||
|
||||
@@ -1089,7 +1089,10 @@ async function compileExecutableNative(
|
||||
programObjectDependencies,
|
||||
});
|
||||
const cacheableLinker =
|
||||
onArtifactReady !== undefined && ffi === null && platformLinkerSupportsPersistentCache();
|
||||
onArtifactReady !== undefined && ffi === null && platformLinkerSupportsPersistentCache(
|
||||
process.env,
|
||||
runtimePackTarget,
|
||||
);
|
||||
await linkNativeExecutable(plan, {
|
||||
// A caller-selected linker can be a mutable wrapper with hidden inputs,
|
||||
// and a PATH-selected `clang` can be one too. FFI profiles and mutable
|
||||
@@ -1259,7 +1262,22 @@ async function compileTracked(
|
||||
}
|
||||
let buildPlatform: string;
|
||||
if (outputKind === "exe") {
|
||||
buildPlatform = buildTargetPlatform();
|
||||
// Target semantics are needed before choosing the helper/runtime-pack
|
||||
// path. Do not make them contingent on the legacy C-driver resolver:
|
||||
// an LLVM-owned WASI build deliberately needs no SCRIPTC_CC.
|
||||
try {
|
||||
buildPlatform = sourceTargetPlatform();
|
||||
} catch (err) {
|
||||
return {
|
||||
ok: false,
|
||||
diagnostics: [{
|
||||
code: "SC3002",
|
||||
message: err instanceof Error ? err.message : String(err),
|
||||
loc: { file: entryPath, start: 0, end: 0 },
|
||||
}],
|
||||
sourceTexts: new Map(),
|
||||
};
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
buildPlatform = sourceTargetPlatform();
|
||||
@@ -1355,11 +1373,14 @@ async function compileTracked(
|
||||
}`,
|
||||
compiler: [
|
||||
helperObjectRoute
|
||||
? resolvePlatformLinker()
|
||||
? resolvePlatformLinker(process.env, nativeCodegenTarget()?.defaultLinker)
|
||||
: (process.env["SCRIPTC_CC"] ?? "clang"),
|
||||
],
|
||||
nativeEnvironment: helperObjectRoute
|
||||
? await executableLinkerEnvironmentFingerprint()
|
||||
? await executableLinkerEnvironmentFingerprint(
|
||||
process.env,
|
||||
nativeCodegenTarget()?.defaultLinker,
|
||||
)
|
||||
: await executableNativeEnvironmentFingerprint(),
|
||||
nodeVersion: process.version,
|
||||
implementation: implementation.digest,
|
||||
|
||||
@@ -5,6 +5,7 @@ export { readRoutedExecutableCache } from "./executable/executable-cache.js";
|
||||
export type { EarlyExecutableRouteOptions } from "./executable/executable-cache.js";
|
||||
export {
|
||||
executableNativeEnvironmentFingerprint,
|
||||
configuredTargetPlatform,
|
||||
legacyCExecutablePathRequested,
|
||||
resolveCc,
|
||||
targetPlatform,
|
||||
@@ -14,3 +15,18 @@ export {
|
||||
executableLinkerEnvironmentFingerprint,
|
||||
resolvePlatformLinker,
|
||||
} from "./backend/linker.js";
|
||||
import { legacyCExecutablePathRequested } from "./backend/external-c.js";
|
||||
import { nativeCodegenTarget, type NativeTargetSpec } from "./backend/targets.js";
|
||||
|
||||
/** Whether an ordinary LLVM executable can take the helper/object plus
|
||||
* precompiled-runtime-pack route. Keep this startup-sized: the CLI bootstrap
|
||||
* needs the exact cache identity before deciding whether it must import the
|
||||
* full compiler graph. */
|
||||
export function precompiledRuntimePackTarget(
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
): NativeTargetSpec | null {
|
||||
if (env["SCRIPTC_RUNTIME_PACK"] === "0" ||
|
||||
env["SCRIPTC_FETCH_CURL"] === "1" ||
|
||||
legacyCExecutablePathRequested(env)) return null;
|
||||
return nativeCodegenTarget(env);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ execFileSync("cmake", [
|
||||
"-G", "Ninja",
|
||||
`-DLLVM_DIR=${llvmDir}`,
|
||||
`-DSCRIPTC_PACKAGE_VERSION=${manifest.version}`,
|
||||
"-DSCRIPTC_TARGET_BACKENDS=AArch64;WebAssembly",
|
||||
"-DSCRIPTC_ALLOWED_TARGETS=arm64-apple-macosx14.0.0,wasm32-unknown-wasi",
|
||||
"-DCMAKE_BUILD_TYPE=Release",
|
||||
], { stdio: "inherit" });
|
||||
execFileSync("cmake", ["--build", buildDir, "--target", "scriptc-llvm-codegen"], {
|
||||
@@ -38,7 +40,9 @@ const version = JSON.parse(execFileSync(output, ["version", "--format=json"], {
|
||||
if (
|
||||
version.protocol_version !== "1" ||
|
||||
version.scriptc_package_version !== manifest.version ||
|
||||
version.llvm_version !== "22.1.8"
|
||||
version.llvm_version !== "22.1.8" ||
|
||||
!Array.isArray(version.supported_targets) ||
|
||||
!version.supported_targets.includes("arm64-apple-macosx14.0.0")
|
||||
) {
|
||||
throw new Error(`built helper reported an incompatible identity: ${JSON.stringify(version)}`);
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Apache License 2.0. See https://www.apache.org/licenses/LICENSE-2.0
|
||||
@@ -0,0 +1 @@
|
||||
Copyright scriptc contributors. Licensed under Apache-2.0.
|
||||
@@ -0,0 +1 @@
|
||||
This package contains LLVM components licensed under Apache-2.0 with LLVM Exceptions.
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "@scriptc/llvm-darwin-x64",
|
||||
"version": "0.0.36",
|
||||
"description": "Pinned LLVM code-generation helper for scriptc on macOS x64",
|
||||
"license": "Apache-2.0 WITH LLVM-exception",
|
||||
"homepage": "https://scriptc.dev",
|
||||
"repository": { "type": "git", "url": "git+https://github.com/vercel-labs/scriptc.git", "directory": "packages/llvm-darwin-x64" },
|
||||
"os": ["darwin"],
|
||||
"cpu": ["x64"],
|
||||
"files": ["bin", "LICENSE", "SCRIPTC_LICENSE", "THIRD_PARTY_NOTICES"],
|
||||
"scripts": { "build": "true", "build:native": "node scripts/build.mjs", "prepack": "test -x bin/scriptc-llvm-codegen" },
|
||||
"publishConfig": { "access": "public" }
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env node
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { chmodSync, copyFileSync, mkdirSync, readFileSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const root = dirname(dirname(fileURLToPath(import.meta.url)));
|
||||
const repo = fileURLToPath(new URL("../../..", import.meta.url));
|
||||
if (process.platform !== "darwin" || process.arch !== "x64") {
|
||||
process.stdout.write("@scriptc/llvm-darwin-x64: skipped on this host\n");
|
||||
process.exit(0);
|
||||
}
|
||||
const manifest = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
|
||||
const build = join(repo, "node_modules/.cache/scriptc-llvm-darwin-x64");
|
||||
execFileSync("cmake", ["-S", join(repo, "native/llvm-codegen"), "-B", build, "-G", "Ninja", `-DLLVM_DIR=${process.env.LLVM_DIR ?? "/usr/local/opt/llvm@22/lib/cmake/llvm"}`, `-DSCRIPTC_PACKAGE_VERSION=${manifest.version}`, "-DSCRIPTC_HELPER_ARCH=x86_64", "-DSCRIPTC_DEFAULT_TARGET=x86_64-apple-macosx14.0.0", "-DSCRIPTC_DEFAULT_DATA_LAYOUT=e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", "-DSCRIPTC_TARGET_BACKENDS=X86;WebAssembly", "-DSCRIPTC_ALLOWED_TARGETS=x86_64-apple-macosx14.0.0,wasm32-unknown-wasi", "-DCMAKE_BUILD_TYPE=Release"], { stdio: "inherit" });
|
||||
execFileSync("cmake", ["--build", build, "--target", "scriptc-llvm-codegen"], { stdio: "inherit" });
|
||||
mkdirSync(join(root, "bin"), { recursive: true });
|
||||
const output = join(root, "bin", "scriptc-llvm-codegen");
|
||||
copyFileSync(join(build, "scriptc-llvm-codegen"), output);
|
||||
execFileSync("strip", ["-x", output], { stdio: "inherit" });
|
||||
chmodSync(output, 0o755);
|
||||
@@ -0,0 +1 @@
|
||||
Apache License 2.0. See https://www.apache.org/licenses/LICENSE-2.0
|
||||
@@ -0,0 +1 @@
|
||||
Copyright scriptc contributors. Licensed under Apache-2.0.
|
||||
@@ -0,0 +1 @@
|
||||
This package contains LLVM components licensed under Apache-2.0 with LLVM Exceptions.
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "@scriptc/llvm-linux-arm64-gnu", "version": "0.0.36", "description": "Pinned LLVM code-generation helper for scriptc on Linux arm64", "license": "Apache-2.0 WITH LLVM-exception", "homepage": "https://scriptc.dev",
|
||||
"repository": { "type": "git", "url": "git+https://github.com/vercel-labs/scriptc.git", "directory": "packages/llvm-linux-arm64-gnu" }, "os": ["linux"], "cpu": ["arm64"], "files": ["bin", "LICENSE", "SCRIPTC_LICENSE", "THIRD_PARTY_NOTICES"], "scripts": { "build": "true", "build:native": "node scripts/build.mjs", "prepack": "test -x bin/scriptc-llvm-codegen" }, "publishConfig": { "access": "public" }
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env node
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { chmodSync, copyFileSync, mkdirSync, readFileSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
const root = dirname(dirname(fileURLToPath(import.meta.url))); const repo = fileURLToPath(new URL("../../..", import.meta.url));
|
||||
if (process.platform !== "linux" || process.arch !== "arm64") { process.stdout.write("@scriptc/llvm-linux-arm64-gnu: skipped on this host\n"); process.exit(0); }
|
||||
const manifest = JSON.parse(readFileSync(join(root, "package.json"), "utf8")); const build = join(repo, "node_modules/.cache/scriptc-llvm-linux-arm64-gnu");
|
||||
execFileSync("cmake", ["-S", join(repo, "native/llvm-codegen"), "-B", build, "-G", "Ninja", `-DLLVM_DIR=${process.env.LLVM_DIR ?? "/usr/lib/llvm-22/lib/cmake/llvm"}`, `-DSCRIPTC_PACKAGE_VERSION=${manifest.version}`, "-DSCRIPTC_DEFAULT_TARGET=aarch64-unknown-linux-gnu", "-DSCRIPTC_DEFAULT_DATA_LAYOUT=e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32", "-DSCRIPTC_TARGET_BACKENDS=AArch64;WebAssembly", "-DSCRIPTC_ALLOWED_TARGETS=aarch64-unknown-linux-gnu,aarch64-unknown-linux-musl,wasm32-unknown-wasi", "-DCMAKE_BUILD_TYPE=Release"], { stdio: "inherit" });
|
||||
execFileSync("cmake", ["--build", build, "--target", "scriptc-llvm-codegen"], { stdio: "inherit" }); mkdirSync(join(root, "bin"), { recursive: true }); const output = join(root, "bin", "scriptc-llvm-codegen"); copyFileSync(join(build, "scriptc-llvm-codegen"), output); execFileSync("strip", [output], { stdio: "inherit" }); chmodSync(output, 0o755);
|
||||
@@ -0,0 +1 @@
|
||||
Apache License 2.0. See https://www.apache.org/licenses/LICENSE-2.0
|
||||
@@ -0,0 +1 @@
|
||||
Copyright scriptc contributors. Licensed under Apache-2.0.
|
||||
@@ -0,0 +1 @@
|
||||
This package contains LLVM components licensed under Apache-2.0 with LLVM Exceptions.
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "@scriptc/llvm-linux-arm64-musl",
|
||||
"version": "0.0.36",
|
||||
"description": "Statically linked LLVM code-generation helper for scriptc on Linux arm64 musl",
|
||||
"license": "Apache-2.0 WITH LLVM-exception",
|
||||
"homepage": "https://scriptc.dev",
|
||||
"repository": { "type": "git", "url": "git+https://github.com/vercel-labs/scriptc.git", "directory": "packages/llvm-linux-arm64-musl" },
|
||||
"os": ["linux"], "cpu": ["arm64"],
|
||||
"files": ["bin", "LICENSE", "SCRIPTC_LICENSE", "THIRD_PARTY_NOTICES"],
|
||||
"scripts": { "build": "true", "build:native": "node scripts/build.mjs", "prepack": "test -x bin/scriptc-llvm-codegen" },
|
||||
"publishConfig": { "access": "public" }
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env node
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { chmodSync, copyFileSync, mkdirSync, readFileSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
const root = dirname(dirname(fileURLToPath(import.meta.url))); const repo = fileURLToPath(new URL("../../..", import.meta.url));
|
||||
if (process.platform !== "linux" || process.arch !== "arm64") { process.stdout.write("@scriptc/llvm-linux-arm64-musl: skipped on this host\n"); process.exit(0); }
|
||||
const manifest = JSON.parse(readFileSync(join(root, "package.json"), "utf8")); const build = join(repo, "node_modules/.cache/scriptc-llvm-linux-arm64-musl");
|
||||
execFileSync("cmake", ["-S", join(repo, "native/llvm-codegen"), "-B", build, "-G", "Ninja", "-DCMAKE_C_COMPILER=zig", "-DCMAKE_C_COMPILER_ARG1=cc", "-DCMAKE_CXX_COMPILER=zig", "-DCMAKE_CXX_COMPILER_ARG1=c++", "-DCMAKE_C_COMPILER_TARGET=aarch64-linux-musl", "-DCMAKE_CXX_COMPILER_TARGET=aarch64-linux-musl", "-DCMAKE_EXE_LINKER_FLAGS=-static", `-DLLVM_DIR=${process.env.LLVM_DIR ?? "/usr/lib/llvm-22/lib/cmake/llvm"}`, `-DSCRIPTC_PACKAGE_VERSION=${manifest.version}`, "-DSCRIPTC_DEFAULT_TARGET=aarch64-unknown-linux-musl", "-DSCRIPTC_DEFAULT_DATA_LAYOUT=e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32", "-DSCRIPTC_TARGET_BACKENDS=AArch64;WebAssembly", "-DSCRIPTC_ALLOWED_TARGETS=aarch64-unknown-linux-musl,wasm32-unknown-wasi", "-DCMAKE_BUILD_TYPE=Release"], { stdio: "inherit" });
|
||||
execFileSync("cmake", ["--build", build, "--target", "scriptc-llvm-codegen"], { stdio: "inherit" }); mkdirSync(join(root, "bin"), { recursive: true }); const output = join(root, "bin", "scriptc-llvm-codegen"); copyFileSync(join(build, "scriptc-llvm-codegen"), output); execFileSync("strip", [output], { stdio: "inherit" }); chmodSync(output, 0o755);
|
||||
@@ -0,0 +1 @@
|
||||
Apache License 2.0. See https://www.apache.org/licenses/LICENSE-2.0
|
||||
@@ -0,0 +1 @@
|
||||
Copyright scriptc contributors. Licensed under Apache-2.0.
|
||||
@@ -0,0 +1 @@
|
||||
This package contains LLVM components licensed under Apache-2.0 with LLVM Exceptions.
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "@scriptc/llvm-linux-x64-gnu",
|
||||
"version": "0.0.36",
|
||||
"description": "Pinned LLVM code-generation helper for scriptc on Linux x64",
|
||||
"license": "Apache-2.0 WITH LLVM-exception",
|
||||
"homepage": "https://scriptc.dev",
|
||||
"repository": { "type": "git", "url": "git+https://github.com/vercel-labs/scriptc.git", "directory": "packages/llvm-linux-x64-gnu" },
|
||||
"os": ["linux"], "cpu": ["x64"],
|
||||
"files": ["bin", "LICENSE", "SCRIPTC_LICENSE", "THIRD_PARTY_NOTICES"],
|
||||
"scripts": { "build": "true", "build:native": "node scripts/build.mjs", "prepack": "test -x bin/scriptc-llvm-codegen" },
|
||||
"publishConfig": { "access": "public" }
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env node
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { chmodSync, copyFileSync, mkdirSync, readFileSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const root = dirname(dirname(fileURLToPath(import.meta.url)));
|
||||
const repo = fileURLToPath(new URL("../../..", import.meta.url));
|
||||
if (process.platform !== "linux" || process.arch !== "x64") { process.stdout.write("@scriptc/llvm-linux-x64-gnu: skipped on this host\n"); process.exit(0); }
|
||||
const manifest = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
|
||||
const build = join(repo, "node_modules/.cache/scriptc-llvm-linux-x64-gnu");
|
||||
execFileSync("cmake", ["-S", join(repo, "native/llvm-codegen"), "-B", build, "-G", "Ninja", `-DLLVM_DIR=${process.env.LLVM_DIR ?? "/usr/lib/llvm-22/lib/cmake/llvm"}`, `-DSCRIPTC_PACKAGE_VERSION=${manifest.version}`, "-DSCRIPTC_DEFAULT_TARGET=x86_64-unknown-linux-gnu", "-DSCRIPTC_DEFAULT_DATA_LAYOUT=e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", "-DSCRIPTC_TARGET_BACKENDS=X86;WebAssembly", "-DSCRIPTC_ALLOWED_TARGETS=x86_64-unknown-linux-gnu,x86_64-unknown-linux-musl,wasm32-unknown-wasi", "-DCMAKE_BUILD_TYPE=Release"], { stdio: "inherit" });
|
||||
execFileSync("cmake", ["--build", build, "--target", "scriptc-llvm-codegen"], { stdio: "inherit" });
|
||||
mkdirSync(join(root, "bin"), { recursive: true });
|
||||
const output = join(root, "bin", "scriptc-llvm-codegen"); copyFileSync(join(build, "scriptc-llvm-codegen"), output); execFileSync("strip", [output], { stdio: "inherit" }); chmodSync(output, 0o755);
|
||||
@@ -0,0 +1 @@
|
||||
Apache License 2.0. See https://www.apache.org/licenses/LICENSE-2.0
|
||||
@@ -0,0 +1 @@
|
||||
Copyright scriptc contributors. Licensed under Apache-2.0.
|
||||
@@ -0,0 +1 @@
|
||||
This package contains LLVM components licensed under Apache-2.0 with LLVM Exceptions.
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "@scriptc/llvm-linux-x64-musl",
|
||||
"version": "0.0.36",
|
||||
"description": "Statically linked LLVM code-generation helper for scriptc on Linux x64 musl",
|
||||
"license": "Apache-2.0 WITH LLVM-exception",
|
||||
"homepage": "https://scriptc.dev",
|
||||
"repository": { "type": "git", "url": "git+https://github.com/vercel-labs/scriptc.git", "directory": "packages/llvm-linux-x64-musl" },
|
||||
"os": ["linux"], "cpu": ["x64"],
|
||||
"files": ["bin", "LICENSE", "SCRIPTC_LICENSE", "THIRD_PARTY_NOTICES"],
|
||||
"scripts": { "build": "true", "build:native": "node scripts/build.mjs", "prepack": "test -x bin/scriptc-llvm-codegen" },
|
||||
"publishConfig": { "access": "public" }
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env node
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { chmodSync, copyFileSync, mkdirSync, readFileSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const root = dirname(dirname(fileURLToPath(import.meta.url)));
|
||||
const repo = fileURLToPath(new URL("../../..", import.meta.url));
|
||||
if (process.platform !== "linux" || process.arch !== "x64") { process.stdout.write("@scriptc/llvm-linux-x64-musl: skipped on this host\n"); process.exit(0); }
|
||||
const manifest = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
|
||||
const build = join(repo, "node_modules/.cache/scriptc-llvm-linux-x64-musl");
|
||||
execFileSync("cmake", ["-S", join(repo, "native/llvm-codegen"), "-B", build, "-G", "Ninja", "-DCMAKE_C_COMPILER=zig", "-DCMAKE_C_COMPILER_ARG1=cc", "-DCMAKE_CXX_COMPILER=zig", "-DCMAKE_CXX_COMPILER_ARG1=c++", "-DCMAKE_C_COMPILER_TARGET=x86_64-linux-musl", "-DCMAKE_CXX_COMPILER_TARGET=x86_64-linux-musl", "-DCMAKE_EXE_LINKER_FLAGS=-static", `-DLLVM_DIR=${process.env.LLVM_DIR ?? "/usr/lib/llvm-22/lib/cmake/llvm"}`, `-DSCRIPTC_PACKAGE_VERSION=${manifest.version}`, "-DSCRIPTC_DEFAULT_TARGET=x86_64-unknown-linux-musl", "-DSCRIPTC_DEFAULT_DATA_LAYOUT=e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", "-DSCRIPTC_TARGET_BACKENDS=X86;WebAssembly", "-DSCRIPTC_ALLOWED_TARGETS=x86_64-unknown-linux-musl,wasm32-unknown-wasi", "-DCMAKE_BUILD_TYPE=Release"], { stdio: "inherit" });
|
||||
execFileSync("cmake", ["--build", build, "--target", "scriptc-llvm-codegen"], { stdio: "inherit" }); mkdirSync(join(root, "bin"), { recursive: true }); const output = join(root, "bin", "scriptc-llvm-codegen"); copyFileSync(join(build, "scriptc-llvm-codegen"), output); execFileSync("strip", [output], { stdio: "inherit" }); chmodSync(output, 0o755);
|
||||
@@ -0,0 +1 @@
|
||||
Apache License 2.0. See https://www.apache.org/licenses/LICENSE-2.0
|
||||
@@ -0,0 +1 @@
|
||||
Copyright scriptc contributors. Licensed under Apache-2.0.
|
||||
@@ -0,0 +1 @@
|
||||
This package contains LLVM components licensed under Apache-2.0 with LLVM Exceptions.
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "@scriptc/llvm-win32-x64-msvc", "version": "0.0.36", "description": "Pinned LLVM code-generation helper for scriptc on Windows x64", "license": "Apache-2.0 WITH LLVM-exception", "homepage": "https://scriptc.dev",
|
||||
"repository": { "type": "git", "url": "git+https://github.com/vercel-labs/scriptc.git", "directory": "packages/llvm-win32-x64-msvc" }, "os": ["win32"], "cpu": ["x64"], "files": ["bin", "LICENSE", "SCRIPTC_LICENSE", "THIRD_PARTY_NOTICES"], "scripts": { "build": "true", "build:native": "node scripts/build.mjs", "prepack": "test -f bin/scriptc-llvm-codegen.exe" }, "publishConfig": { "access": "public" }
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env node
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { copyFileSync, mkdirSync, readFileSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
const root = dirname(dirname(fileURLToPath(import.meta.url))); const repo = fileURLToPath(new URL("../../..", import.meta.url));
|
||||
if (process.platform !== "win32" || process.arch !== "x64") { process.stdout.write("@scriptc/llvm-win32-x64-msvc: skipped on this host\n"); process.exit(0); }
|
||||
const manifest = JSON.parse(readFileSync(join(root, "package.json"), "utf8")); const build = join(repo, "node_modules/.cache/scriptc-llvm-win32-x64-msvc");
|
||||
// LLVM's official Windows development archive contains MSVC-built static
|
||||
// libraries. Use Visual Studio's generator, rather than inheriting a caller's
|
||||
// clang/ninja defaults, so it selects the matching CRT, SDK, manifest tools,
|
||||
// and current MSVC standard-library implementation.
|
||||
execFileSync("cmake", ["-S", join(repo, "native/llvm-codegen"), "-B", build, "-G", "Visual Studio 17 2022", "-A", "x64", `-DLLVM_DIR=${process.env.LLVM_DIR ?? "C:/Program Files/LLVM/lib/cmake/llvm"}`, `-DSCRIPTC_PACKAGE_VERSION=${manifest.version}`, "-DSCRIPTC_DEFAULT_TARGET=x86_64-pc-windows-msvc", "-DSCRIPTC_DEFAULT_DATA_LAYOUT=e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", "-DSCRIPTC_TARGET_BACKENDS=X86;WebAssembly", "-DSCRIPTC_ALLOWED_TARGETS=x86_64-pc-windows-msvc,wasm32-unknown-wasi"], { stdio: "inherit" });
|
||||
execFileSync("cmake", ["--build", build, "--config", "Release", "--target", "scriptc-llvm-codegen"], { stdio: "inherit" }); mkdirSync(join(root, "bin"), { recursive: true }); copyFileSync(join(build, "Release", "scriptc-llvm-codegen.exe"), join(root, "bin", "scriptc-llvm-codegen.exe"));
|
||||
@@ -99,10 +99,7 @@ export const RUNTIME_PACK_MATRIX = {
|
||||
object_format: "macho",
|
||||
minimum_os: "14.0",
|
||||
},
|
||||
flavors: {
|
||||
release: { optimization: "-O2" },
|
||||
dev: { optimization: "-O0" },
|
||||
},
|
||||
flavors: { release: { optimization: "-O2" }, dev: { optimization: "-O0" } },
|
||||
executable_section_elimination: EXECUTABLE_SECTION_ELIMINATION,
|
||||
runtime_units: [
|
||||
...BASE_RUNTIME_SOURCES.map((source) => ({ source, predicate: true })),
|
||||
@@ -114,8 +111,5 @@ export const RUNTIME_PACK_MATRIX = {
|
||||
{ id: "zlib", predicate: "zlibEffective" },
|
||||
{ id: "mbedtls", predicate: "tlsEffective" },
|
||||
],
|
||||
system_libraries: [
|
||||
{ name: "System", predicate: true },
|
||||
{ name: "m", predicate: "dynamic" },
|
||||
],
|
||||
system_libraries: [{ name: "System", predicate: true }, { name: "m", predicate: "dynamic" }],
|
||||
};
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "@scriptc/runtime-darwin-x64", "version": "0.0.36", "description": "Precompiled scriptc runtime pack for macOS x64", "license": "Apache-2.0", "homepage": "https://scriptc.dev",
|
||||
"repository": { "type": "git", "url": "git+https://github.com/vercel-labs/scriptc.git", "directory": "packages/runtime-darwin-x64" }, "os": ["darwin"], "cpu": ["x64"],
|
||||
"files": ["artifacts", "runtime-pack.json"], "scripts": { "build": "true", "build:native": "node scripts/build.mjs", "prepack": "node scripts/verify.mjs" }, "publishConfig": { "access": "public" }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url";
|
||||
if (process.platform !== "darwin" || process.arch !== "x64") { process.stdout.write("@scriptc/runtime-darwin-x64: 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: "darwin", runtimeDefines: [], threadArgs: ["-pthread"], target: { name: "macos-x64", llvm_triple: "x86_64-apple-macosx14.0.0", architecture: "x64", object_format: "macho", minimum_os: "14.0" }, targetArgs: ["-target", "x86_64-apple-macosx14.0.0"], compileFlags: [], systemLibraries: [{ name: "System", predicate: true }, { name: "m", predicate: "dynamic" }] });
|
||||
await import("../../runtime-pack-common/scripts/build.mjs");
|
||||
@@ -0,0 +1,2 @@
|
||||
import { dirname } from "node:path"; import { fileURLToPath } from "node:url";
|
||||
process.env.SCRIPTC_RUNTIME_PACK_ROOT = dirname(dirname(fileURLToPath(import.meta.url))); await import("../../runtime-pack-common/scripts/verify.mjs");
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "@scriptc/runtime-linux-arm64-gnu", "version": "0.0.36", "description": "Precompiled scriptc runtime pack for Linux arm64 glibc", "license": "Apache-2.0", "homepage": "https://scriptc.dev",
|
||||
"repository": { "type": "git", "url": "git+https://github.com/vercel-labs/scriptc.git", "directory": "packages/runtime-linux-arm64-gnu" }, "os": ["linux"], "cpu": ["arm64"],
|
||||
"files": ["artifacts", "runtime-pack.json"], "scripts": { "build": "true", "build:native": "node scripts/build.mjs", "prepack": "node scripts/verify.mjs" }, "publishConfig": { "access": "public" }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
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); }
|
||||
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 }] });
|
||||
await import("../../runtime-pack-common/scripts/build.mjs");
|
||||
@@ -0,0 +1,2 @@
|
||||
import { dirname } from "node:path"; import { fileURLToPath } from "node:url";
|
||||
process.env.SCRIPTC_RUNTIME_PACK_ROOT = dirname(dirname(fileURLToPath(import.meta.url))); await import("../../runtime-pack-common/scripts/verify.mjs");
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "@scriptc/runtime-linux-arm64-musl", "version": "0.0.36", "description": "Precompiled scriptc runtime pack for Linux arm64 musl", "license": "Apache-2.0", "homepage": "https://scriptc.dev",
|
||||
"repository": { "type": "git", "url": "git+https://github.com/vercel-labs/scriptc.git", "directory": "packages/runtime-linux-arm64-musl" }, "os": ["linux"], "cpu": ["arm64"],
|
||||
"files": ["artifacts", "runtime-pack.json"], "scripts": { "build": "true", "build:native": "node scripts/build.mjs", "prepack": "node scripts/verify.mjs" }, "publishConfig": { "access": "public" }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { dirname } from "node:path"; import { fileURLToPath } from "node:url";
|
||||
if (process.platform !== "linux" || process.arch !== "arm64") { process.stdout.write("@scriptc/runtime-linux-arm64-musl: 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", "SCR_MUSL"], threadArgs: ["-pthread"], extraRuntimeSources: ["scr_musl.c"], compiler: "zig", compilerArgs: ["cc"], archiver: "zig", archiverArgs: ["ar"], target: { name: "linux-arm64-musl", llvm_triple: "aarch64-unknown-linux-musl", architecture: "arm64", object_format: "elf", minimum_os: "musl 1.2" }, targetArgs: ["-target", "aarch64-linux-musl"], compileFlags: ["-ffunction-sections", "-fdata-sections"], systemLibraries: [{ name: "m", predicate: true }] });
|
||||
await import("../../runtime-pack-common/scripts/build.mjs");
|
||||
@@ -0,0 +1,2 @@
|
||||
import { dirname } from "node:path"; import { fileURLToPath } from "node:url";
|
||||
process.env.SCRIPTC_RUNTIME_PACK_ROOT = dirname(dirname(fileURLToPath(import.meta.url))); await import("../../runtime-pack-common/scripts/verify.mjs");
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "@scriptc/runtime-linux-x64-gnu", "version": "0.0.36", "description": "Precompiled scriptc runtime pack for Linux x64 glibc", "license": "Apache-2.0", "homepage": "https://scriptc.dev",
|
||||
"repository": { "type": "git", "url": "git+https://github.com/vercel-labs/scriptc.git", "directory": "packages/runtime-linux-x64-gnu" }, "os": ["linux"], "cpu": ["x64"],
|
||||
"files": ["artifacts", "runtime-pack.json"], "scripts": { "build": "true", "build:native": "node scripts/build.mjs", "prepack": "node scripts/verify.mjs" }, "publishConfig": { "access": "public" }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
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); }
|
||||
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 }] });
|
||||
await import("../../runtime-pack-common/scripts/build.mjs");
|
||||
@@ -0,0 +1,2 @@
|
||||
import { dirname } from "node:path"; import { fileURLToPath } from "node:url";
|
||||
process.env.SCRIPTC_RUNTIME_PACK_ROOT = dirname(dirname(fileURLToPath(import.meta.url))); await import("../../runtime-pack-common/scripts/verify.mjs");
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "@scriptc/runtime-linux-x64-musl", "version": "0.0.36", "description": "Precompiled scriptc runtime pack for Linux x64 musl", "license": "Apache-2.0", "homepage": "https://scriptc.dev",
|
||||
"repository": { "type": "git", "url": "git+https://github.com/vercel-labs/scriptc.git", "directory": "packages/runtime-linux-x64-musl" }, "os": ["linux"], "cpu": ["x64"],
|
||||
"files": ["artifacts", "runtime-pack.json"], "scripts": { "build": "true", "build:native": "node scripts/build.mjs", "prepack": "node scripts/verify.mjs" }, "publishConfig": { "access": "public" }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { dirname } from "node:path"; import { fileURLToPath } from "node:url";
|
||||
if (process.platform !== "linux" || process.arch !== "x64") { process.stdout.write("@scriptc/runtime-linux-x64-musl: 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", "SCR_MUSL"], threadArgs: ["-pthread"], extraRuntimeSources: ["scr_musl.c"], compiler: "zig", compilerArgs: ["cc"], archiver: "zig", archiverArgs: ["ar"], target: { name: "linux-x64-musl", llvm_triple: "x86_64-unknown-linux-musl", architecture: "x64", object_format: "elf", minimum_os: "musl 1.2" }, targetArgs: ["-target", "x86_64-linux-musl"], compileFlags: ["-ffunction-sections", "-fdata-sections"], systemLibraries: [{ name: "m", predicate: true }] });
|
||||
await import("../../runtime-pack-common/scripts/build.mjs");
|
||||
@@ -0,0 +1,2 @@
|
||||
import { dirname } from "node:path"; import { fileURLToPath } from "node:url";
|
||||
process.env.SCRIPTC_RUNTIME_PACK_ROOT = dirname(dirname(fileURLToPath(import.meta.url))); await import("../../runtime-pack-common/scripts/verify.mjs");
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "@scriptc/runtime-pack-common",
|
||||
"version": "0.0.36",
|
||||
"private": true,
|
||||
"type": "module"
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* Shared release-runtime pack matrix. Platform package scripts provide the
|
||||
* target descriptor, then this module fixes feature reachability and the
|
||||
* compile/link flags required by every generated runtime object.
|
||||
*/
|
||||
const any = (...features) => ({ any: features });
|
||||
const all = (...features) => ({ all: features });
|
||||
|
||||
const BASE_RUNTIME_SOURCES = [
|
||||
"scr_number.c", "scr_string.c", "scr_array.c", "scr_bytes.c",
|
||||
"scr_bytes_io.c", "scr_map.c", "scr_closure.c", "scr_ffi.c",
|
||||
"scr_object.c", "scr_union.c", "scr_exception.c", "scr_error.c",
|
||||
"scr_console.c", "scr_lib.c", "scr_path.c", "scr_url.c", "scr_json.c",
|
||||
"scr_async.c", "scr_child.c", "scr_cycle.c",
|
||||
];
|
||||
|
||||
const OPTIONAL = [
|
||||
["scr_copying.c", "copying"], ["scr_file_handle.c", "fileHandle"],
|
||||
["scr_regex.c", "regex"], ["scr_assert.c", any("assert", "regex", "symbol")],
|
||||
["scr_inspect.c", "inspect"], ["scr_dyn_invoke.c", any("dynInvoke", "nativeFetch")],
|
||||
["scr_dc.c", "dc"], ["scr_async_dyn.c", any("dynAsync", "dynInvoke", "dc", "nativeFetch")],
|
||||
["scr_zlib.c", "zlib"], ["scr_zlib_island.c", all("zlib", "dynamic")],
|
||||
["scr_events.c", "events"], ["scr_readline.c", "events"],
|
||||
["scr_events_emitter.c", "emitter"], ["scr_dyn_handle.c", any("emitter", "netEffective")],
|
||||
["scr_symbol.c", "symbol"], ["scr_url_params.c", "searchParams"],
|
||||
["scr_qs.c", "qs"], ["scr_util.c", "parseArgs"], ["scr_stream.c", "stream"],
|
||||
["scr_loop_kqueue.c", any("netEffective", "dgram")],
|
||||
["scr_loop_epoll.c", any("netEffective", "dgram")],
|
||||
["scr_loop_wsapoll.c", any("netEffective", "dgram")],
|
||||
["scr_net.c", "netEffective"], ["scr_http.c", "httpEffective"],
|
||||
["scr_http2.c", "http2"], ["scr_dgram.c", "dgram"], ["scr_watch.c", "watch"],
|
||||
["scr_ffi_queue.c", "foreignFfi"], ["scr_test.c", "nodeTest"],
|
||||
["scr_tls_ca.c", "tlsCaEffective"], ["scr_tls.c", "tlsEffective"],
|
||||
["scr_fetch.c", "nativeFetch"], ["scr_island.c", "dynamic"],
|
||||
["scr_web.c", "dynamic"], ["scr_inspect_island.c", all("dynamic", "inspect")],
|
||||
["scr_net_island.c", "netIslandEffective"],
|
||||
];
|
||||
|
||||
function variantsFor(source) {
|
||||
const dynamicOnly = new Set([
|
||||
"scr_zlib_island.c", "scr_island.c", "scr_web.c",
|
||||
"scr_inspect_island.c", "scr_net_island.c",
|
||||
]);
|
||||
if (dynamicOnly.has(source)) {
|
||||
return [{ id: "dynamic", when: { dynamic: true }, defines: ["SCR_DYNAMIC"] }];
|
||||
}
|
||||
const variants = [{ id: "default", when: {}, defines: [] }];
|
||||
if (source === "scr_bytes.c") {
|
||||
variants.push({ id: "text-decoder-legacy", when: { textDecoderLegacy: true }, defines: ["SCR_TEXT_DECODER_LEGACY"] });
|
||||
}
|
||||
variants.push({ id: "dynamic", when: { dynamic: true }, defines: ["SCR_DYNAMIC"] });
|
||||
if (source === "scr_bytes.c") {
|
||||
variants.push({
|
||||
id: "dynamic-text-decoder-legacy", when: { dynamic: true, textDecoderLegacy: true },
|
||||
defines: ["SCR_DYNAMIC", "SCR_TEXT_DECODER_LEGACY"],
|
||||
});
|
||||
}
|
||||
return variants;
|
||||
}
|
||||
|
||||
export function createRuntimePackMatrix({
|
||||
target,
|
||||
compileFlags,
|
||||
systemLibraries,
|
||||
extraRuntimeSources = [],
|
||||
omitRuntimeSources = [],
|
||||
omitOptionalSources = [],
|
||||
omitArchives = [],
|
||||
}) {
|
||||
const vendorArchives = [
|
||||
{ id: "quickjs", predicate: "dynamic" },
|
||||
{ id: "libregexp", predicate: { all: ["regex"], not: ["dynamic"] } },
|
||||
{ id: "zlib", predicate: "zlibEffective" },
|
||||
{ id: "mbedtls", predicate: "tlsEffective" },
|
||||
];
|
||||
return {
|
||||
schema: "scriptc.runtime-pack-matrix.v1",
|
||||
target,
|
||||
flavors: { release: { optimization: "-O2" }, dev: { optimization: "-O0" } },
|
||||
executable_section_elimination: { compile_flags: compileFlags },
|
||||
runtime_units: [
|
||||
...BASE_RUNTIME_SOURCES
|
||||
.filter((source) => !omitRuntimeSources.includes(source))
|
||||
.map((source) => ({ source, predicate: true })),
|
||||
...extraRuntimeSources.map((source) => ({ source, predicate: true })),
|
||||
...OPTIONAL
|
||||
.filter(([source]) => !omitOptionalSources.includes(source))
|
||||
.map(([source, predicate]) => ({ source, predicate })),
|
||||
].map((unit) => ({ ...unit, variants: variantsFor(unit.source) })),
|
||||
archives: vendorArchives.filter(({ id }) => !omitArchives.includes(id)),
|
||||
system_libraries: systemLibraries,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { readFile, writeFile } from "node:fs/promises";
|
||||
import { execFile } from "node:child_process";
|
||||
import { promisify } from "node:util";
|
||||
|
||||
const run = promisify(execFile);
|
||||
const globalHeader = "!<arch>\n";
|
||||
const memberHeaderSize = 60;
|
||||
|
||||
function replaceField(bytes, offset, width, value) {
|
||||
bytes.write(value.padEnd(width, " "), offset, width, "ascii");
|
||||
}
|
||||
|
||||
async function normalizeMetadata(output) {
|
||||
const bytes = await readFile(output);
|
||||
if (bytes.subarray(0, globalHeader.length).toString("ascii") !== globalHeader) throw new Error(`archiver produced an invalid archive: ${output}`);
|
||||
let offset = globalHeader.length;
|
||||
while (offset < bytes.length) {
|
||||
const end = offset + memberHeaderSize;
|
||||
if (end > bytes.length || bytes.subarray(offset + 58, end).toString("ascii") !== "`\n") throw new Error(`archiver produced a malformed member header: ${output}`);
|
||||
const size = Number(bytes.subarray(offset + 48, offset + 58).toString("ascii").trim());
|
||||
if (!Number.isSafeInteger(size) || size < 0 || end + size > bytes.length) throw new Error(`archiver produced an invalid member size: ${output}`);
|
||||
replaceField(bytes, offset + 16, 12, "0");
|
||||
replaceField(bytes, offset + 28, 6, "0");
|
||||
replaceField(bytes, offset + 34, 6, "0");
|
||||
replaceField(bytes, offset + 40, 8, "100644");
|
||||
offset = end + size + (size % 2);
|
||||
}
|
||||
if (offset !== bytes.length) throw new Error(`archiver produced a truncated archive: ${output}`);
|
||||
await writeFile(output, bytes);
|
||||
}
|
||||
|
||||
export async function createDeterministicArchive(archiver, output, objects, args = []) {
|
||||
await run(archiver, [...args, "rcs", output, ...objects], { env: { ...process.env, ZERO_AR_DATE: "1" } });
|
||||
await normalizeMetadata(output);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { installRuntimePack, withBuildLock } from "../../runtime-darwin-arm64/scripts/build-state.mjs";
|
||||
@@ -0,0 +1,125 @@
|
||||
#!/usr/bin/env node
|
||||
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 { fileURLToPath } from "node:url";
|
||||
import { promisify } from "node:util";
|
||||
import { createRuntimePackMatrix } from "../runtime-pack-matrix.mjs";
|
||||
import { createDeterministicArchive } from "./archive.mjs";
|
||||
import { installRuntimePack, withBuildLock } from "./build-state.mjs";
|
||||
|
||||
const run = promisify(execFile);
|
||||
const packageRoot = process.env.SCRIPTC_RUNTIME_PACK_ROOT;
|
||||
const configText = process.env.SCRIPTC_RUNTIME_PACK_CONFIG;
|
||||
if (!packageRoot || !configText) throw new Error("runtime-pack build requires package wrapper configuration");
|
||||
const config = JSON.parse(configText);
|
||||
const repoRoot = fileURLToPath(new URL("../../..", import.meta.url));
|
||||
const runtimeRoot = join(repoRoot, "packages/runtime");
|
||||
const runtimeSrc = join(runtimeRoot, "src");
|
||||
const vendorRoot = join(runtimeRoot, "vendor");
|
||||
const outputRoot = join(packageRoot, "artifacts");
|
||||
const manifestPath = join(packageRoot, "runtime-pack.json");
|
||||
const matrix = createRuntimePackMatrix(config);
|
||||
|
||||
async function build() {
|
||||
const buildRoot = join(packageRoot, `.runtime-pack-build-${process.pid}-${Math.random().toString(36).slice(2)}`);
|
||||
const stagedOutputRoot = join(buildRoot, "artifacts");
|
||||
const stagedManifestPath = join(buildRoot, "runtime-pack.json");
|
||||
const artifactPath = (path) => ["artifacts", ...relative(stagedOutputRoot, path).split(sep)].join("/");
|
||||
const sourcePathFlags = [`-ffile-prefix-map=${buildRoot}=${packageRoot}`, `-ffile-prefix-map=${repoRoot}=.`];
|
||||
const packageManifest = JSON.parse(await readFile(join(packageRoot, "package.json"), "utf8"));
|
||||
const compiler = process.env.CC ?? config.compiler ?? "clang";
|
||||
const compilerArgs = config.compilerArgs ?? [];
|
||||
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",
|
||||
...matrix.executable_section_elimination.compile_flags, "-Wno-deprecated-declarations", "-I", runtimeSrc,
|
||||
...(config.runtimeDefines ?? []).map((define) => `-D${define}`),
|
||||
];
|
||||
const quickjs = join(vendorRoot, "quickjs-ng");
|
||||
const zlib = join(vendorRoot, "zlib");
|
||||
const mbedtls = join(vendorRoot, "mbedtls");
|
||||
const qjsSources = ["dtoa.c", "libregexp.c", "libunicode.c", "quickjs.c"];
|
||||
const lreSources = ["libregexp.c", "libunicode.c"];
|
||||
const zlibSources = ["adler32.c", "compress.c", "crc32.c", "deflate.c", "infback.c", "inffast.c", "inflate.c", "inftrees.c", "trees.c", "uncompr.c", "zutil.c"];
|
||||
const sha256 = async (path) => createHash("sha256").update(await readFile(path)).digest("hex");
|
||||
const compile = async (source, output, flags) => {
|
||||
await mkdir(dirname(output), { recursive: true });
|
||||
await run(compiler, [...compilerArgs, ...sourcePathFlags, ...flags, "-c", source, "-o", output]);
|
||||
};
|
||||
const parallel = async (items, task) => {
|
||||
const width = Math.max(1, Math.min(8, availableParallelism()));
|
||||
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) => {
|
||||
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));
|
||||
const output = join(root, `libscriptc-${id}.a`);
|
||||
await createDeterministicArchive(archiver, output, sources.map((source) => join(objectRoot, source.replace(/\.c$/, ".o"))), archiverArgs);
|
||||
await rm(objectRoot, { recursive: true, force: true });
|
||||
return { id, path: artifactPath(output), sha256: await sha256(output), size: (await stat(output)).size };
|
||||
};
|
||||
await rm(buildRoot, { recursive: true, force: true });
|
||||
try {
|
||||
await mkdir(stagedOutputRoot, { recursive: true });
|
||||
// Zig 0.16 creates a zero-byte `a.o` in its working directory for
|
||||
// `zig cc --version`. Probe from a private temporary directory so a
|
||||
// runtime-pack build never leaves that compiler byproduct in the package.
|
||||
const versionProbeRoot = await mkdtemp(join(tmpdir(), "scriptc-runtime-pack-version-"));
|
||||
let compilerVersion;
|
||||
try {
|
||||
compilerVersion = (await run(compiler, [...compilerArgs, "--version"], {
|
||||
cwd: versionProbeRoot,
|
||||
})).stdout.split("\n", 1)[0].trim();
|
||||
} finally {
|
||||
await rm(versionProbeRoot, { recursive: true, force: true });
|
||||
}
|
||||
const flavors = {};
|
||||
for (const [flavor, flavorSpec] of Object.entries(matrix.flavors)) {
|
||||
const units = [];
|
||||
for (const unit of matrix.runtime_units) {
|
||||
const variants = [];
|
||||
for (const variant of unit.variants) {
|
||||
const output = join(stagedOutputRoot, flavor, "runtime", variant.id, unit.source.replace(/\.c$/, ".o"));
|
||||
const includeFlags = [
|
||||
...(unit.source === "scr_regex.c" || variant.defines.includes("SCR_DYNAMIC") ? ["-I", quickjs] : []),
|
||||
...(unit.source === "scr_tls.c" ? ["-I", join(mbedtls, "include")] : []),
|
||||
...(unit.source === "scr_zlib.c" || unit.source === "scr_fetch.c" ? ["-I", zlib] : []),
|
||||
];
|
||||
await compile(join(runtimeSrc, unit.source), output, [...commonFlags, flavorSpec.optimization, ...variant.defines.map((define) => `-D${define}`), ...includeFlags]);
|
||||
variants.push({ id: variant.id, when: variant.when, defines: variant.defines, path: artifactPath(output), sha256: await sha256(output), size: (await stat(output)).size });
|
||||
}
|
||||
units.push({ source: unit.source, predicate: unit.predicate, variants });
|
||||
}
|
||||
flavors[flavor] = { optimization: flavorSpec.optimization, runtime_units: units };
|
||||
}
|
||||
const mbedtlsSources = (await readdir(join(mbedtls, "library"))).filter((name) => !name.startsWith(".") && name.endsWith(".c")).sort();
|
||||
// Vendored QuickJS reads `clock_gettime` for its monotonic clock. WASI
|
||||
// exposes that declaration only when its process-clock emulation ABI is
|
||||
// selected, so vendor sources inherit the target's runtime defines too.
|
||||
const vendorTarget = [
|
||||
...config.targetArgs,
|
||||
...(config.runtimeDefines ?? []).map((define) => `-D${define}`),
|
||||
];
|
||||
const requestedArchives = new Set(matrix.archives.map((entry) => entry.id));
|
||||
const archives = config.vendorArchives === false ? [] : [
|
||||
...(requestedArchives.has("quickjs") ? [await archive("quickjs", qjsSources, quickjs, [...vendorTarget, "-std=gnu11", "-fvisibility=hidden", "-funsigned-char", "-DQUICKJS_NG_BUILD", "-D_GNU_SOURCE", "-DNDEBUG", "-Os", "-I", quickjs])] : []),
|
||||
...(requestedArchives.has("libregexp") ? [await archive("libregexp", lreSources, quickjs, [...vendorTarget, "-std=c11", "-Os", "-I", quickjs])] : []),
|
||||
...(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")])] : []),
|
||||
];
|
||||
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); }));
|
||||
const manifest = { schema: "scriptc.runtime-pack.v1", format: 1, package: packageManifest.name, version: packageManifest.version, target: matrix.target, runtime_abi: { version: 1, marker: "scr_runtime_abi_v1" }, compiler: { command: compiler, identity: compilerVersion, target: matrix.target.llvm_triple }, macros: { executable: ["SCR_DYNAMIC", "SCR_TEXT_DECODER_LEGACY"], excluded: ["SCR_LIB", "SCR_THREAD_INSTANCES", "SCR_RC_AUDIT", "SCR_ASAN_FIBERS"], sanitizer: "external-toolchain-required" }, flavors, archives: archives.map((entry) => ({ ...entry, predicate: archiveSpecs.get(entry.id).predicate })), system_libraries: matrix.system_libraries, licenses: licensed.map(([, path, license]) => ({ path, license })) };
|
||||
await writeFile(stagedManifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
|
||||
const suffix = `${process.pid}-${Math.random().toString(36).slice(2)}`;
|
||||
await installRuntimePack({ outputRoot, manifestPath, stagedOutputRoot, stagedManifestPath, backupRoot: join(packageRoot, `.runtime-pack-artifacts-backup-${suffix}`), backupManifestPath: join(packageRoot, `.runtime-pack-manifest-backup-${suffix}`) });
|
||||
process.stdout.write(`built ${packageManifest.name}@${packageManifest.version}: ${Object.keys(flavors).length} flavors, ${archives.length} vendor archives\n`);
|
||||
} finally { await rm(buildRoot, { recursive: true, force: true }); }
|
||||
}
|
||||
await withBuildLock(join(packageRoot, ".runtime-pack-build.lock"), build);
|
||||
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env node
|
||||
import { createHash } from "node:crypto";
|
||||
import { access, readFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
|
||||
const root = process.env.SCRIPTC_RUNTIME_PACK_ROOT;
|
||||
if (!root) throw new Error("runtime-pack verification requires package wrapper configuration");
|
||||
const manifest = JSON.parse(await readFile(join(root, "runtime-pack.json"), "utf8"));
|
||||
const packageManifest = JSON.parse(await readFile(join(root, "package.json"), "utf8"));
|
||||
if (manifest.schema !== "scriptc.runtime-pack.v1" || manifest.format !== 1 || manifest.package !== packageManifest.name || manifest.version !== packageManifest.version) throw new Error("runtime pack identity does not match package.json");
|
||||
const artifacts = [...Object.values(manifest.flavors).flatMap((flavor) => flavor.runtime_units.flatMap((unit) => unit.variants)), ...manifest.archives];
|
||||
for (const artifact of artifacts) {
|
||||
const bytes = await readFile(join(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}`);
|
||||
}
|
||||
for (const license of manifest.licenses) await access(join(root, license.path));
|
||||
process.stdout.write(`verified ${manifest.package}@${manifest.version}: ${artifacts.length} artifacts\n`);
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "@scriptc/runtime-wasm32-wasi", "version": "0.0.36", "description": "Precompiled scriptc runtime pack for WASI Preview 1", "license": "Apache-2.0", "homepage": "https://scriptc.dev",
|
||||
"repository": { "type": "git", "url": "git+https://github.com/vercel-labs/scriptc.git", "directory": "packages/runtime-wasm32-wasi" },
|
||||
"files": ["artifacts", "runtime-pack.json"], "scripts": { "build": "true", "build:native": "node scripts/build.mjs", "prepack": "node scripts/verify.mjs" }, "publishConfig": { "access": "public" }
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import { dirname } from "node:path"; import { fileURLToPath } from "node:url";
|
||||
process.env.SCRIPTC_RUNTIME_PACK_ROOT = dirname(dirname(fileURLToPath(import.meta.url)));
|
||||
process.env.SCRIPTC_RUNTIME_PACK_CONFIG = JSON.stringify({ platform: "wasi", runtimeDefines: ["_GNU_SOURCE", "_WASI_EMULATED_SIGNAL", "_WASI_EMULATED_PROCESS_CLOCKS"], omitRuntimeSources: ["scr_child.c"], omitOptionalSources: ["scr_dyn_handle.c", "scr_loop_kqueue.c", "scr_loop_epoll.c", "scr_loop_wsapoll.c", "scr_net.c", "scr_http.c", "scr_http2.c", "scr_dgram.c", "scr_watch.c", "scr_tls_ca.c", "scr_tls.c", "scr_fetch.c", "scr_net_island.c"], omitArchives: ["mbedtls"], compiler: "zig", compilerArgs: ["cc"], archiver: "zig", archiverArgs: ["ar"], target: { name: "wasm32-wasi", llvm_triple: "wasm32-unknown-wasi", architecture: "wasm32", object_format: "wasm", minimum_os: "WASI Preview 1" }, targetArgs: ["-target", "wasm32-wasi"], compileFlags: [], systemLibraries: [{ name: "wasi-emulated-signal", predicate: true }, { name: "wasi-emulated-process-clocks", predicate: true }] });
|
||||
await import("../../runtime-pack-common/scripts/build.mjs");
|
||||
@@ -0,0 +1,2 @@
|
||||
import { dirname } from "node:path"; import { fileURLToPath } from "node:url";
|
||||
process.env.SCRIPTC_RUNTIME_PACK_ROOT = dirname(dirname(fileURLToPath(import.meta.url))); await import("../../runtime-pack-common/scripts/verify.mjs");
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "@scriptc/runtime-win32-x64-msvc", "version": "0.0.36", "description": "Precompiled scriptc runtime pack for Windows x64 MSVC", "license": "Apache-2.0", "homepage": "https://scriptc.dev",
|
||||
"repository": { "type": "git", "url": "git+https://github.com/vercel-labs/scriptc.git", "directory": "packages/runtime-win32-x64-msvc" }, "os": ["win32"], "cpu": ["x64"],
|
||||
"files": ["artifacts", "runtime-pack.json"], "scripts": { "build": "true", "build:native": "node scripts/build.mjs", "prepack": "node scripts/verify.mjs" }, "publishConfig": { "access": "public" }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { dirname } from "node:path"; import { fileURLToPath } from "node:url";
|
||||
if (process.platform !== "win32" || process.arch !== "x64") { process.stdout.write("@scriptc/runtime-win32-x64-msvc: skipped on this host\n"); process.exit(0); }
|
||||
process.env.SCRIPTC_RUNTIME_PACK_ROOT = dirname(dirname(fileURLToPath(import.meta.url)));
|
||||
// The helper emits x64 COFF objects, whose calling convention is compatible
|
||||
// with Zig's MinGW runtime. The runtime itself intentionally uses the
|
||||
// POSIX-shaped Windows surface (unistd, dirent, clock_gettime), so compile it
|
||||
// against Zig's Windows GNU sysroot rather than MSVC's headers.
|
||||
process.env.SCRIPTC_RUNTIME_PACK_CONFIG = JSON.stringify({ platform: "win32", runtimeDefines: [], extraRuntimeSources: ["scr_win.c"], compiler: "zig", compilerArgs: ["cc"], archiver: "zig", archiverArgs: ["ar"], target: { name: "windows-x64-msvc", llvm_triple: "x86_64-pc-windows-msvc", architecture: "x64", object_format: "coff", minimum_os: "Windows 10" }, targetArgs: ["-target", "x86_64-windows-gnu"], compileFlags: ["-ffunction-sections", "-fdata-sections"], systemLibraries: [{ name: "advapi32", predicate: true }, { name: "iphlpapi", predicate: true }, { name: "ws2_32", predicate: true }, { name: "bcrypt", predicate: "tlsEffective" }, { name: "crypt32", predicate: "tlsCaEffective" }] });
|
||||
await import("../../runtime-pack-common/scripts/build.mjs");
|
||||
@@ -0,0 +1,2 @@
|
||||
import { dirname } from "node:path"; import { fileURLToPath } from "node:url";
|
||||
process.env.SCRIPTC_RUNTIME_PACK_ROOT = dirname(dirname(fileURLToPath(import.meta.url))); await import("../../runtime-pack-common/scripts/verify.mjs");
|
||||
@@ -19,6 +19,12 @@
|
||||
* Win32's missing POSIX/BSD functions live in scr_win.c. Zig's musl sysroot
|
||||
* additionally lacks arc4random_buf; scr_musl.c supplies it from Linux's
|
||||
* getrandom syscall. Both files are selected by native-toolchain.ts only for their target. */
|
||||
#if defined(_WIN32) && defined(_MSC_VER)
|
||||
/* MSVC's C headers do not define POSIX ssize_t. Keep the runtime's byte-count
|
||||
* interfaces pointer-sized on Windows without requiring a Windows SDK header
|
||||
* (and leave the Zig/MinGW compatibility route's native typedef intact). */
|
||||
typedef intptr_t ssize_t;
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#include <time.h> /* time_t / struct tm for the gmtime_r shim */
|
||||
char *stpcpy(char *dst, const char *src);
|
||||
|
||||
Generated
+67
@@ -54,16 +54,83 @@ importers:
|
||||
'@scriptc/llvm-darwin-arm64':
|
||||
specifier: workspace:*
|
||||
version: link:../llvm-darwin-arm64
|
||||
'@scriptc/llvm-darwin-x64':
|
||||
specifier: workspace:*
|
||||
version: link:../llvm-darwin-x64
|
||||
'@scriptc/llvm-linux-arm64-gnu':
|
||||
specifier: workspace:*
|
||||
version: link:../llvm-linux-arm64-gnu
|
||||
'@scriptc/llvm-linux-arm64-musl':
|
||||
specifier: workspace:*
|
||||
version: link:../llvm-linux-arm64-musl
|
||||
'@scriptc/llvm-linux-x64-gnu':
|
||||
specifier: workspace:*
|
||||
version: link:../llvm-linux-x64-gnu
|
||||
'@scriptc/llvm-linux-x64-musl':
|
||||
specifier: workspace:*
|
||||
version: link:../llvm-linux-x64-musl
|
||||
'@scriptc/llvm-win32-x64-msvc':
|
||||
specifier: workspace:*
|
||||
version: link:../llvm-win32-x64-msvc
|
||||
'@scriptc/runtime-darwin-arm64':
|
||||
specifier: workspace:*
|
||||
version: link:../runtime-darwin-arm64
|
||||
'@scriptc/runtime-darwin-x64':
|
||||
specifier: workspace:*
|
||||
version: link:../runtime-darwin-x64
|
||||
'@scriptc/runtime-linux-arm64-gnu':
|
||||
specifier: workspace:*
|
||||
version: link:../runtime-linux-arm64-gnu
|
||||
'@scriptc/runtime-linux-arm64-musl':
|
||||
specifier: workspace:*
|
||||
version: link:../runtime-linux-arm64-musl
|
||||
'@scriptc/runtime-linux-x64-gnu':
|
||||
specifier: workspace:*
|
||||
version: link:../runtime-linux-x64-gnu
|
||||
'@scriptc/runtime-linux-x64-musl':
|
||||
specifier: workspace:*
|
||||
version: link:../runtime-linux-x64-musl
|
||||
'@scriptc/runtime-wasm32-wasi':
|
||||
specifier: workspace:*
|
||||
version: link:../runtime-wasm32-wasi
|
||||
'@scriptc/runtime-win32-x64-msvc':
|
||||
specifier: workspace:*
|
||||
version: link:../runtime-win32-x64-msvc
|
||||
|
||||
packages/llvm-darwin-arm64: {}
|
||||
|
||||
packages/llvm-darwin-x64: {}
|
||||
|
||||
packages/llvm-linux-arm64-gnu: {}
|
||||
|
||||
packages/llvm-linux-arm64-musl: {}
|
||||
|
||||
packages/llvm-linux-x64-gnu: {}
|
||||
|
||||
packages/llvm-linux-x64-musl: {}
|
||||
|
||||
packages/llvm-win32-x64-msvc: {}
|
||||
|
||||
packages/runtime: {}
|
||||
|
||||
packages/runtime-darwin-arm64: {}
|
||||
|
||||
packages/runtime-darwin-x64: {}
|
||||
|
||||
packages/runtime-linux-arm64-gnu: {}
|
||||
|
||||
packages/runtime-linux-arm64-musl: {}
|
||||
|
||||
packages/runtime-linux-x64-gnu: {}
|
||||
|
||||
packages/runtime-linux-x64-musl: {}
|
||||
|
||||
packages/runtime-pack-common: {}
|
||||
|
||||
packages/runtime-wasm32-wasi: {}
|
||||
|
||||
packages/runtime-win32-x64-msvc: {}
|
||||
|
||||
packages:
|
||||
|
||||
'@bytecodealliance/preview2-shim@0.17.6':
|
||||
|
||||
@@ -28,7 +28,17 @@ const root = fileURLToPath(new URL("..", import.meta.url));
|
||||
const readJson = (path) => JSON.parse(readFileSync(root + path, "utf8"));
|
||||
|
||||
const version = readJson("packages/cli/package.json").version;
|
||||
for (const pkg of ["runtime", "runtime-darwin-arm64", "llvm-darwin-arm64", "compiler"]) {
|
||||
for (const pkg of [
|
||||
"runtime",
|
||||
"runtime-darwin-arm64", "runtime-darwin-x64",
|
||||
"runtime-linux-x64-gnu", "runtime-linux-arm64-gnu",
|
||||
"runtime-linux-x64-musl", "runtime-linux-arm64-musl",
|
||||
"runtime-win32-x64-msvc", "runtime-wasm32-wasi",
|
||||
"llvm-darwin-arm64", "llvm-darwin-x64",
|
||||
"llvm-linux-x64-gnu", "llvm-linux-arm64-gnu",
|
||||
"llvm-linux-x64-musl", "llvm-linux-arm64-musl", "llvm-win32-x64-msvc",
|
||||
"compiler",
|
||||
]) {
|
||||
const v = readJson(`packages/${pkg}/package.json`).version;
|
||||
if (v !== version) {
|
||||
console.error(
|
||||
|
||||
@@ -16,7 +16,17 @@ if (typeof version !== "string" || version.length === 0) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
for (const pkg of ["runtime", "runtime-darwin-arm64", "compiler", "llvm-darwin-arm64"]) {
|
||||
for (const pkg of [
|
||||
"runtime",
|
||||
"runtime-darwin-arm64", "runtime-darwin-x64",
|
||||
"runtime-linux-x64-gnu", "runtime-linux-arm64-gnu",
|
||||
"runtime-linux-x64-musl", "runtime-linux-arm64-musl",
|
||||
"runtime-win32-x64-msvc", "runtime-wasm32-wasi",
|
||||
"compiler",
|
||||
"llvm-darwin-arm64", "llvm-darwin-x64",
|
||||
"llvm-linux-x64-gnu", "llvm-linux-arm64-gnu",
|
||||
"llvm-linux-x64-musl", "llvm-linux-arm64-musl", "llvm-win32-x64-msvc",
|
||||
]) {
|
||||
const path = manifest(pkg);
|
||||
const json = read(path);
|
||||
if (json.version === version) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user