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 8d290890..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") @@ -219,6 +220,9 @@ 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 zig_build_impl(ctx, *, kind): """Common implementation for Zig build rules. @@ -247,6 +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 semver.gte(zigtoolchaininfo.zig_version, "0.16.0") providers = [] exported_library_to_link = None @@ -438,6 +443,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, @@ -486,8 +498,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]) @@ -545,23 +556,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_path, + 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() @@ -570,10 +598,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", 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"), )