ReviewOS

also looking at this

craft-native/craft

fix(build): select the core Zig project explicitly

#383
Merged chris wants to merge codex/zig-core-build-root into main
4 files +44 -2
.github/workflows/ci.ymlmodified+3-0
Changes to .github/workflows/ci.yml
@@ -192,6 +192,9 @@ jobs:
192192 # including its adjacent standard library on Windows.
193193 run: bun run build:core
194194
195 - name: Verify pinned compiler core project selection
196 run: bun scripts/verify-zig-core-project.ts
197
195198 - name: Stage pinned WebView2 loader
196199 shell: pwsh
197200 run: |
scripts/verify-zig-core-project.tsadded+30-0
Changes to scripts/verify-zig-core-project.ts
@@ -0,0 +1,30 @@
1import { existsSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
2import { join, resolve } from 'node:path'
3import { resolveZig } from './zig'
4
5const source = resolve(import.meta.dir, '..')
6const zig = resolveZig(source)
7console.log('Tracked core project:', JSON.stringify({ file: join(source, 'packages/zig/build.zig'), exists: existsSync(join(source, 'packages/zig/build.zig')) }))
8// Keep the fixture on the checkout's volume. Hosted Windows keeps the
9// checkout on D: and the system temporary directory/compiler cache on C:.
10const root = mkdtempSync(join(source, '.zig-core-project-'))
11const core = join(root, 'packages', 'zig')
12try {
13 mkdirSync(core, { recursive: true })
14 writeFileSync(join(root, 'pantry.lock'), readFileSync(join(source, 'pantry.lock')))
15 writeFileSync(join(root, 'package.json'), JSON.stringify({ version: '1.2.3' }))
16 writeFileSync(join(root, 'build.zig'), 'const std=; pub fn build(b:*std.Build) void {_=b.standardOptimizeOption(.{});}\n')
17 writeFileSync(join(core, 'build.zig'), 'const std=; pub fn build(b:*std.Build) void {_=b.standardOptimizeOption(.{}); const version=b.option([]const u8,"version","version") orelse "missing"; std.debug.print("PROJECT_VERSION={s}\\n",.{version});}\n')
18 const env = { ...process.env, CRAFT_ZIG: zig.path }
19 const runner = join(root, 'runner.ts')
20 writeFileSync(runner, `import {runZig} from ${JSON.stringify(join(source, 'scripts/zig.ts'))};process.exitCode=runZig(${JSON.stringify(root)},['--core','--versioned','build']);\n`)
21 const result = Bun.spawnSync([process.execPath, runner], { cwd: root, env, stdout: 'pipe', stderr: 'pipe' })
22 console.log(result.stdout.toString(), result.stderr.toString())
23 // The root wrapper rejects -Dversion. A successful configure therefore
24 // proves core selection even when Zig reuses its cached configuration.
25 if (result.exitCode !== 0)
26 throw new Error('The actual pinned compiler did not configure the selected core project with its package version.')
27}
28finally {
29 rmSync(root, { recursive: true, force: true })
30}
scripts/zig.test.tsmodified+3-1
Changes to scripts/zig.test.ts
@@ -80,7 +80,9 @@ test('fails early for absent executables, invalid lock versions, and invalid com
8080test('forwards arguments, core working directory, package version and compiler exit status', () => {
8181 const f = fixture()
8282 expect(runZig(f.root, ['--core', '--versioned', 'build', '-Doptimize=ReleaseSafe', '-Dfoo=a b'], f.env)).toBe(23)
83 expect(JSON.parse(readFileSync(f.env.ZIG_TEST_LOG, 'utf8'))).toEqual({ cwd: join(f.root, 'packages/zig'), args: ['build', '-Doptimize=ReleaseSafe', '-Dfoo=a b', '-Dversion=1.2.3'] })
83 expect(JSON.parse(readFileSync(f.env.ZIG_TEST_LOG, 'utf8'))).toEqual({ cwd: join(f.root, 'packages/zig'), args: ['build', '--build-file', join(f.root, 'packages/zig/build.zig'), '-Doptimize=ReleaseSafe', '-Dfoo=a b', '-Dversion=1.2.3'] })
84 expect(runZig(f.root, ['--core', 'fmt', 'src/'], f.env)).toBe(23)
85 expect(JSON.parse(readFileSync(f.env.ZIG_TEST_LOG, 'utf8'))).toEqual({ cwd: join(f.root, 'packages/zig'), args: ['fmt', 'src/'] })
8486 expect(runZig(f.root, ['fmt', 'src/'], f.env)).toBe(23)
8587 expect(JSON.parse(readFileSync(f.env.ZIG_TEST_LOG, 'utf8'))).toEqual({ cwd: f.root, args: ['fmt', 'src/'] })
8688})
scripts/zig.tsmodified+8-1
Changes to scripts/zig.ts
@@ -59,10 +59,17 @@ export function runZig(root: string, args: string[], env: NodeJS.ProcessEnv = pr
5959 const { version } = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'))
6060 command.push(`-Dversion=${version}`)
6161 }
62 if (core && command[0] === 'build') {
63 // Select the core project explicitly. A monorepo has another build.zig
64 // at its root; compiler build discovery must not select that wrapper.
65 command.splice(1, 0, '--build-file', join(root, 'packages/zig/build.zig'))
66 }
6267 const zig = resolveZig(root, env)
68 const cwd = core ? join(root, 'packages/zig') : root
6369 console.error(`Zig ${zig.version}: ${zig.path}${zig.overridden ? ' (explicit unpinned override)' : ''}`)
70 console.error(`Zig project directory: ${cwd}`)
6471 const result = Bun.spawnSync([zig.path, ...command], {
65 cwd: core ? join(root, 'packages/zig') : root,
72 cwd,
6673 env,
6774 stdin: 'inherit',
6875 stdout: 'inherit',