From f9886b54ce9d7a4283f96aeeea818e8bc56ee20e Mon Sep 17 00:00:00 2001 From: Corentin Kerisit Date: Thu, 7 May 2026 15:58:47 +0000 Subject: [PATCH 1/3] feat: implement test-obj for use_cc_common_link in zig 0.16 --- zig/private/common/zig_build.bzl | 73 +++++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 21 deletions(-) diff --git a/zig/private/common/zig_build.bzl b/zig/private/common/zig_build.bzl index dc76803f..32881145 100644 --- a/zig/private/common/zig_build.bzl +++ b/zig/private/common/zig_build.bzl @@ -218,6 +218,13 @@ def _shared_lib_extension(os): def _executable_extension(os): return ".exe" if os == "windows" else "" +def _object_extension(os): + return ".obj" if os == "windows" else ".o" + +def _supports_test_obj(zig_version): + components = zig_version.split(".") + return len(components) >= 2 and components[0] == "0" and components[1] == "16" + def zig_build_impl(ctx, *, kind): """Common implementation for Zig build rules. @@ -244,6 +251,7 @@ def zig_build_impl(ctx, *, kind): zigtargetinfo = ctx.toolchains["//zig/target:toolchain_type"].zigtargetinfo use_cc_common_link = ctx.attr._settings[ZigSettingsInfo].use_cc_common_link + use_test_obj = kind == "zig_test" and use_cc_common_link and _supports_test_obj(zigtoolchaininfo.zig_version) providers = [] exported_library_to_link = None @@ -434,6 +442,13 @@ def zig_build_impl(ctx, *, kind): transitive_inputs.append(depset(cdeps_inputs)) + if use_test_obj: + # Zig 0.16's LLVM StackProtector pass crashes for test-obj when + # compiler-rt provides __stack_chk_fail as an alias. + # See: https://codeberg.org/ziglang/zig/issues/31702 + # TODO[CK]: Remove once we bump to 0.17.0. + args.add("-fno-stack-protector") + zig_module_specifications( root_module = root_module, args = args, @@ -482,8 +497,7 @@ def zig_build_impl(ctx, *, kind): output_groups["llvm_ir"] = depset([llvm_ir_output]) args.add(llvm_ir_output, format = "-femit-llvm-ir=%s") - # TODO[CK] remove extra kind check once we drop support for Zig 0.15 and use test-obj. - if ctx.attr.emit_llvm_bc and not (kind == "zig_test" and use_cc_common_link): + if ctx.attr.emit_llvm_bc and not (kind == "zig_test" and use_cc_common_link and not use_test_obj): llvm_bc_output = ctx.actions.declare_file(ctx.label.name + ".bc") auxiliary_outputs.append(llvm_bc_output) output_groups["llvm_bc"] = depset([llvm_bc_output]) @@ -541,23 +555,40 @@ def zig_build_impl(ctx, *, kind): ) elif kind == "zig_test": if use_cc_common_link: - bc = ctx.actions.declare_file(ctx.label.name + ".bc") - test_args = ctx.actions.args() - test_args.add("-fno-emit-bin") - - # TODO[CK] Remove once we drop support for Zig 0.15 and use test-obj. - if ctx.attr.emit_llvm_bc: - output_groups["llvm_bc"] = depset([bc]) - test_args.add(bc, format = "-femit-llvm-bc=%s") - ctx.actions.run( - outputs = [bc] + auxiliary_outputs, - inputs = inputs, - executable = zigtoolchaininfo.zig_exe_path, - arguments = ["test", "--test-no-exec", global_args, args, test_args], - mnemonic = "ZigBuildTest", - progress_message = "zig test %{label}", - **zig_build_kwargs - ) + test_artifact = None + if use_test_obj: + test_obj = ctx.actions.declare_file(ctx.label.name + _object_extension(zigtargetinfo.triple.os)) + test_args = ctx.actions.args() + test_args.add(test_obj, format = "-femit-bin=%s") + ctx.actions.run( + outputs = [test_obj] + auxiliary_outputs, + inputs = inputs, + executable = zigtoolchaininfo.zig_exe, + arguments = ["test-obj", "--test-no-exec", global_args, args, test_args], + mnemonic = "ZigBuildTest", + progress_message = "zig test-obj %{label}", + **zig_build_kwargs + ) + test_artifact = test_obj + else: + bc = ctx.actions.declare_file(ctx.label.name + ".bc") + test_args = ctx.actions.args() + test_args.add("-fno-emit-bin") + + # TODO[CK] Remove once we drop support for Zig 0.15 and use test-obj. + if ctx.attr.emit_llvm_bc: + output_groups["llvm_bc"] = depset([bc]) + test_args.add(bc, format = "-femit-llvm-bc=%s") + ctx.actions.run( + outputs = [bc] + auxiliary_outputs, + inputs = inputs, + executable = zigtoolchaininfo.zig_exe_path, + arguments = ["test", "--test-no-exec", global_args, args, test_args], + mnemonic = "ZigBuildTest", + progress_message = "zig test %{label}", + **zig_build_kwargs + ) + test_artifact = bc static_lib = ctx.actions.declare_file(ctx.label.name + _static_lib_extension(zigtargetinfo.triple.os)) lib_args = ctx.actions.args() @@ -566,10 +597,10 @@ def zig_build_impl(ctx, *, kind): "-fcompiler-rt", ]) lib_args.add(static_lib, format = "-femit-bin=%s") - lib_args.add(bc) + lib_args.add(test_artifact) ctx.actions.run( outputs = [static_lib], - inputs = [bc], + inputs = [test_artifact], executable = zigtoolchaininfo.zig_exe_path, arguments = ["build-lib", global_args, lib_args], mnemonic = "ZigBuildLib", From 5e571d7bebcfce6f9671104583ca24388bd07bc9 Mon Sep 17 00:00:00 2001 From: Corentin Kerisit Date: Thu, 7 May 2026 18:14:09 +0000 Subject: [PATCH 2/3] fix --- zig/private/common/zig_build.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zig/private/common/zig_build.bzl b/zig/private/common/zig_build.bzl index 32881145..16b06234 100644 --- a/zig/private/common/zig_build.bzl +++ b/zig/private/common/zig_build.bzl @@ -563,7 +563,7 @@ def zig_build_impl(ctx, *, kind): ctx.actions.run( outputs = [test_obj] + auxiliary_outputs, inputs = inputs, - executable = zigtoolchaininfo.zig_exe, + executable = zigtoolchaininfo.zig_exe_path, arguments = ["test-obj", "--test-no-exec", global_args, args, test_args], mnemonic = "ZigBuildTest", progress_message = "zig test-obj %{label}", From 6baa77f882bf121969869deb84717967c6412e2d Mon Sep 17 00:00:00 2001 From: Corentin Kerisit Date: Sat, 9 May 2026 10:23:48 +0000 Subject: [PATCH 3/3] Introduce and use semver.gte --- zig/private/common/BUILD.bazel | 1 + zig/private/common/semver.bzl | 5 +++++ zig/private/common/zig_build.bzl | 7 ++----- zig/tests/semver_test.bzl | 16 ++++++++++++++++ 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/zig/private/common/BUILD.bazel b/zig/private/common/BUILD.bazel index 57d2d063..160c86c6 100644 --- a/zig/private/common/BUILD.bazel +++ b/zig/private/common/BUILD.bazel @@ -29,6 +29,7 @@ bzl_library( ":filetypes", ":linker_script", ":location_expansion", + ":semver", ":translate_c", ":zig_cache", ":zig_lib_dir", diff --git a/zig/private/common/semver.bzl b/zig/private/common/semver.bzl index b035f533..139cd797 100644 --- a/zig/private/common/semver.bzl +++ b/zig/private/common/semver.bzl @@ -111,7 +111,12 @@ def _sorted(versions, *, reverse = False): return sorted(versions, key = key, reverse = reverse) +def _gte(version, minimum): + """Check whether a semantic version is greater than or equal to a minimum.""" + return _sorted([minimum, version])[0] == minimum + semver = struct( + gte = _gte, grouped = _grouped, sorted = _sorted, is_valid = _is_valid, diff --git a/zig/private/common/zig_build.bzl b/zig/private/common/zig_build.bzl index 48ee7a51..cf4b42e3 100644 --- a/zig/private/common/zig_build.bzl +++ b/zig/private/common/zig_build.bzl @@ -22,6 +22,7 @@ load( ) load("//zig/private/common:linker_script.bzl", "zig_linker_script") load("//zig/private/common:location_expansion.bzl", "location_expansion") +load("//zig/private/common:semver.bzl", "semver") load("//zig/private/common:translate_c.bzl", "zig_translate_c") load("//zig/private/common:zig_cache.bzl", "zig_cache_output") load("//zig/private/common:zig_lib_dir.bzl", "zig_lib_dir") @@ -222,10 +223,6 @@ def _executable_extension(os): def _object_extension(os): return ".obj" if os == "windows" else ".o" -def _supports_test_obj(zig_version): - components = zig_version.split(".") - return len(components) >= 2 and components[0] == "0" and components[1] == "16" - def zig_build_impl(ctx, *, kind): """Common implementation for Zig build rules. @@ -254,7 +251,7 @@ def zig_build_impl(ctx, *, kind): translatectoolchaininfo = translate_c_toolchain.translatectoolchaininfo if translate_c_toolchain else None use_cc_common_link = ctx.attr._settings[ZigSettingsInfo].use_cc_common_link - use_test_obj = kind == "zig_test" and use_cc_common_link and _supports_test_obj(zigtoolchaininfo.zig_version) + use_test_obj = kind == "zig_test" and use_cc_common_link and semver.gte(zigtoolchaininfo.zig_version, "0.16.0") providers = [] exported_library_to_link = None diff --git a/zig/tests/semver_test.bzl b/zig/tests/semver_test.bzl index 72fdf673..92ede0e7 100644 --- a/zig/tests/semver_test.bzl +++ b/zig/tests/semver_test.bzl @@ -222,9 +222,25 @@ def _sorted_test_impl(ctx): _sorted_test = unittest.make(_sorted_test_impl) +def _gte_test_impl(ctx): + env = unittest.begin(ctx) + + asserts.true(env, semver.gte("0.16.0", "0.16.0")) + asserts.true(env, semver.gte("0.16.1", "0.16.0")) + asserts.true(env, semver.gte("0.17.0-dev.135+9df02121d", "0.16.0")) + asserts.true(env, semver.gte("1.0.0", "0.16.0")) + + asserts.false(env, semver.gte("0.15.2", "0.16.0")) + asserts.false(env, semver.gte("0.16.0-dev.1", "0.16.0")) + + return unittest.end(env) + +_gte_test = unittest.make(_gte_test_impl) + def semver_test_suite(name): unittest.suite( name, partial.make(_grouped_test, size = "small"), partial.make(_sorted_test, size = "small"), + partial.make(_gte_test, size = "small"), )