Skip to content

Commit 9ca8eed

Browse files
committed
fix(cxx_zig_toolchain): resolve wrapper paths and expand nested argsfiles
The zig wrapper scripts generated by cxx_zig_toolchain had two issues: 1. Relative paths break when invoked from a different working directory. go_go_wrapper uses --use-tmp-workdir which changes to BUCK_SCRATCH_PATH, causing failures like: # runtime/cgo zig_cc.sh: line 2: buck-out/v2/gen/mise/.../zig: No such file or directory 2. zig cc doesn't support nested response files. Buck2's cxx compile generates argsfiles containing @file references, causing: error: unable to parse command line parameters: NestedResponseFile This PR: - Uses BASH_SOURCE to resolve paths from the script's location - Recursively expands @file references to flat files in BUCK_SCRATCH_PATH - Applies fixes to Unix only; Windows left unchanged (can't validate %~dp0)
1 parent babf9d5 commit 9ca8eed

File tree

1 file changed

+94
-24
lines changed

1 file changed

+94
-24
lines changed

prelude/toolchains/cxx/zig/defs.bzl

Lines changed: 94 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,65 @@ load(
133133
"releases",
134134
)
135135

136+
def _write_zig_wrapper(ctx: AnalysisContext, name: str, zig_artifact: Artifact, subcmd: str) -> cmd_args:
137+
"""Write a zig wrapper script that resolves paths from its own location.
138+
139+
Uses BASH_SOURCE to calculate the script's directory, then constructs
140+
paths relative to that location. This ensures the script works regardless
141+
of the caller's working directory - go_go_wrapper changes to a temporary
142+
directory which breaks scripts using relative paths.
143+
144+
Also expands nested @argsfile references since zig cc doesn't support them.
145+
"""
146+
script = ctx.actions.declare_output("{}.sh".format(name))
147+
ctx.actions.write(
148+
script,
149+
[
150+
"#!/usr/bin/env bash",
151+
'SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"',
152+
# Expand nested @argsfile references - zig cc doesn't support them
153+
# Write expanded args to a temp file to handle shell quoting correctly
154+
'expand_argsfile() {',
155+
' local file="$1"',
156+
' while IFS= read -r line || [[ -n "$line" ]]; do',
157+
' if [[ "$line" == @* ]]; then',
158+
' expand_argsfile "${line:1}"',
159+
' else',
160+
' echo "$line"',
161+
' fi',
162+
' done < "$file"',
163+
'}',
164+
'args=()',
165+
'argfile_n=0',
166+
'for arg in "$@"; do',
167+
' if [[ "$arg" == @* ]]; then',
168+
' file="${arg:1}"',
169+
' if [[ -f "$file" ]]; then',
170+
' tmpfile="$BUCK_SCRATCH_PATH/argsfile_$argfile_n"',
171+
' argfile_n=$((argfile_n + 1))',
172+
' expand_argsfile "$file" > "$tmpfile"',
173+
' args+=("@$tmpfile")',
174+
' else',
175+
' args+=("$arg")',
176+
' fi',
177+
' else',
178+
' args+=("$arg")',
179+
' fi',
180+
'done',
181+
cmd_args(
182+
'exec "$SCRIPT_DIR/',
183+
cmd_args(zig_artifact, relative_to = (script, 1)),
184+
'" ',
185+
subcmd,
186+
' "${args[@]}"',
187+
delimiter = "",
188+
),
189+
],
190+
is_executable = True,
191+
allow_args = True,
192+
)
193+
return cmd_args(script, hidden = zig_artifact)
194+
136195
ZigReleaseInfo = provider(
137196
# @unsorted-dict-items
138197
fields = {
@@ -326,31 +385,42 @@ def _get_linker_type(os: str) -> LinkerType:
326385
def _cxx_zig_toolchain_impl(ctx: AnalysisContext) -> list[Provider]:
327386
dist = ctx.attrs.distribution[ZigDistributionInfo]
328387
zig = ctx.attrs.distribution[RunInfo]
388+
zig_artifact = ctx.attrs.distribution[DefaultInfo].default_outputs[0]
329389
target = ["-target", ctx.attrs.target] if ctx.attrs.target else []
330-
zig_cc = cmd_script(
331-
actions = ctx.actions,
332-
name = "zig_cc",
333-
cmd = cmd_args(zig, "cc"),
334-
language = ScriptLanguage("bat" if dist.os == "windows" else "sh"),
335-
)
336-
zig_cxx = cmd_script(
337-
actions = ctx.actions,
338-
name = "zig_cxx",
339-
cmd = cmd_args(zig, "c++"),
340-
language = ScriptLanguage("bat" if dist.os == "windows" else "sh"),
341-
)
342-
zig_ar = cmd_script(
343-
actions = ctx.actions,
344-
name = "zig_ar",
345-
cmd = cmd_args(zig, "ar"),
346-
language = ScriptLanguage("bat" if dist.os == "windows" else "sh"),
347-
)
348-
zig_ranlib = cmd_script(
349-
actions = ctx.actions,
350-
name = "zig_ranlib",
351-
cmd = cmd_args(zig, "ranlib"),
352-
language = ScriptLanguage("bat" if dist.os == "windows" else "sh"),
353-
)
390+
391+
# On Unix, use BASH_SOURCE-based wrapper scripts that resolve paths
392+
# relative to the script's location. This ensures they work when invoked
393+
# from different working directories (go_go_wrapper changes to a temp dir).
394+
if dist.os == "windows":
395+
zig_cc = cmd_script(
396+
actions = ctx.actions,
397+
name = "zig_cc",
398+
cmd = cmd_args(zig, "cc"),
399+
language = ScriptLanguage("bat"),
400+
)
401+
zig_cxx = cmd_script(
402+
actions = ctx.actions,
403+
name = "zig_cxx",
404+
cmd = cmd_args(zig, "c++"),
405+
language = ScriptLanguage("bat"),
406+
)
407+
zig_ar = cmd_script(
408+
actions = ctx.actions,
409+
name = "zig_ar",
410+
cmd = cmd_args(zig, "ar"),
411+
language = ScriptLanguage("bat"),
412+
)
413+
zig_ranlib = cmd_script(
414+
actions = ctx.actions,
415+
name = "zig_ranlib",
416+
cmd = cmd_args(zig, "ranlib"),
417+
language = ScriptLanguage("bat"),
418+
)
419+
else:
420+
zig_cc = _write_zig_wrapper(ctx, "zig_cc", zig_artifact, "cc")
421+
zig_cxx = _write_zig_wrapper(ctx, "zig_cxx", zig_artifact, "c++")
422+
zig_ar = _write_zig_wrapper(ctx, "zig_ar", zig_artifact, "ar")
423+
zig_ranlib = _write_zig_wrapper(ctx, "zig_ranlib", zig_artifact, "ranlib")
354424
return [ctx.attrs.distribution[DefaultInfo]] + cxx_toolchain_infos(
355425
internal_tools = ctx.attrs._cxx_internal_tools[CxxInternalTools],
356426
platform_name = dist.arch,

0 commit comments

Comments
 (0)