-zig_configure(name, actual, mode) +zig_configure(name, actual, mode, threaded)@@ -41,6 +41,7 @@ zig_configure(name, name | A unique name for this target. | Name | required | | | actual | The target to transition. | Label | required | | | mode | The build mode setting | String | optional |
"" |
+| threaded | The threaded setting | String | optional | "" |
@@ -48,7 +49,7 @@ zig_configure(name, name, actual, mode)
+zig_configure_binary(name, actual, mode, threaded)
@@ -61,6 +62,7 @@ zig_configure_binary(name, name | A unique name for this target. | Name | required | |
| actual | The target to transition. | Label | required | |
| mode | The build mode setting | String | optional | "" |
+| threaded | The threaded setting | String | optional | "" |
@@ -68,7 +70,7 @@ zig_configure_binary(name, name, actual, mode)
+zig_configure_test(name, actual, mode, threaded)
@@ -81,6 +83,7 @@ zig_configure_test(name, name | A unique name for this target. | Name | required | |
| actual | The target to transition. | Label | required | |
| mode | The build mode setting | String | optional | "" |
+| threaded | The threaded setting | String | optional | "" |
diff --git a/e2e/workspace/configure-threaded/BUILD.bazel b/e2e/workspace/configure-threaded/BUILD.bazel
new file mode 100644
index 00000000..477b0d8e
--- /dev/null
+++ b/e2e/workspace/configure-threaded/BUILD.bazel
@@ -0,0 +1,124 @@
+load("@bazel_skylib//rules:build_test.bzl", "build_test")
+load("@bazel_skylib//rules:diff_test.bzl", "diff_test")
+load(
+ "@rules_zig//zig:defs.bzl",
+ "zig_binary",
+ "zig_configure",
+ "zig_configure_binary",
+ "zig_configure_test",
+ "zig_library",
+ "zig_test",
+)
+load(":defs.bzl", "run")
+
+zig_library(
+ name = "library",
+ main = "library.zig",
+ tags = ["manual"],
+)
+
+zig_configure(
+ name = "library_single",
+ actual = ":library",
+ threaded = "single",
+)
+
+zig_configure(
+ name = "library_multi",
+ actual = ":library",
+ threaded = "multi",
+)
+
+genrule(
+ name = "library_single_symbol",
+ srcs = [":library_single"],
+ outs = ["library_single_symbol.txt"],
+ cmd = "$(NM) -j --defined-only $(SRCS) | grep single_threaded > $(OUTS)",
+ toolchains = ["@bazel_tools//tools/cpp:current_cc_toolchain"],
+)
+
+genrule(
+ name = "library_multi_symbol",
+ srcs = [":library_multi"],
+ outs = ["library_multi_symbol.txt"],
+ cmd = "$(NM) -j --defined-only $(SRCS) | grep multi_threaded > $(OUTS)",
+ toolchains = ["@bazel_tools//tools/cpp:current_cc_toolchain"],
+)
+
+build_test(
+ name = "library_test",
+ targets = [
+ ":library_single_symbol",
+ ":library_multi_symbol",
+ ],
+)
+
+zig_binary(
+ name = "binary",
+ main = "binary.zig",
+ tags = ["manual"],
+)
+
+zig_configure_binary(
+ name = "binary_single",
+ actual = ":binary",
+ threaded = "single",
+)
+
+zig_configure_binary(
+ name = "binary_multi",
+ actual = ":binary",
+ threaded = "multi",
+)
+
+# NOTE using genrule instead of run fails with Bazel version 5.3.2.
+# It seems that the configuration transition is not handled correctly by
+# genrule in Bazel version 5.3.2.
+
+run(
+ name = "binary_single_output",
+ out = "binary_single_output.actual",
+ tool = ":binary_single",
+)
+
+run(
+ name = "binary_multi_output",
+ out = "binary_multi_output.actual",
+ tool = ":binary_multi",
+)
+
+diff_test(
+ name = "binary_single_output_test",
+ file1 = ":binary_single_output.expected",
+ file2 = ":binary_single_output.actual",
+)
+
+diff_test(
+ name = "binary_multi_output_test",
+ file1 = ":binary_multi_output.expected",
+ file2 = ":binary_multi_output.actual",
+)
+
+zig_test(
+ name = "_test_single",
+ main = "test_single.zig",
+ tags = ["manual"],
+)
+
+zig_configure_test(
+ name = "test_single",
+ actual = "_test_single",
+ threaded = "single",
+)
+
+zig_test(
+ name = "_test_multi",
+ main = "test_multi.zig",
+ tags = ["manual"],
+)
+
+zig_configure_test(
+ name = "test_multi",
+ actual = "_test_multi",
+ threaded = "multi",
+)
diff --git a/e2e/workspace/configure-threaded/binary.zig b/e2e/workspace/configure-threaded/binary.zig
new file mode 100644
index 00000000..8cf0d7dd
--- /dev/null
+++ b/e2e/workspace/configure-threaded/binary.zig
@@ -0,0 +1,9 @@
+const std = @import("std");
+const builtin = @import("builtin");
+
+pub fn main() void {
+ std.io.getStdOut().writer().print(
+ "{}\n",
+ .{builtin.single_threaded},
+ ) catch unreachable;
+}
diff --git a/e2e/workspace/configure-threaded/binary_multi_output.expected b/e2e/workspace/configure-threaded/binary_multi_output.expected
new file mode 100644
index 00000000..c508d536
--- /dev/null
+++ b/e2e/workspace/configure-threaded/binary_multi_output.expected
@@ -0,0 +1 @@
+false
diff --git a/e2e/workspace/configure-threaded/binary_single_output.expected b/e2e/workspace/configure-threaded/binary_single_output.expected
new file mode 100644
index 00000000..27ba77dd
--- /dev/null
+++ b/e2e/workspace/configure-threaded/binary_single_output.expected
@@ -0,0 +1 @@
+true
diff --git a/e2e/workspace/configure-threaded/defs.bzl b/e2e/workspace/configure-threaded/defs.bzl
new file mode 100644
index 00000000..e6a153d7
--- /dev/null
+++ b/e2e/workspace/configure-threaded/defs.bzl
@@ -0,0 +1,19 @@
+"""Implements a rule to run a binary and write its output to a file."""
+
+def _run_impl(ctx):
+ ctx.actions.run_shell(
+ outputs = [ctx.outputs.out],
+ tools = [ctx.executable.tool],
+ mnemonic = "RunBinary",
+ command = "{} > {}".format(ctx.executable.tool.path, ctx.outputs.out.path),
+ progress_message = "Running binary to create %{output}",
+ )
+ return [DefaultInfo(files = depset([ctx.outputs.out]))]
+
+run = rule(
+ _run_impl,
+ attrs = {
+ "out": attr.output(),
+ "tool": attr.label(executable = True, cfg = "exec"),
+ },
+)
diff --git a/e2e/workspace/configure-threaded/library.zig b/e2e/workspace/configure-threaded/library.zig
new file mode 100644
index 00000000..b76c02a4
--- /dev/null
+++ b/e2e/workspace/configure-threaded/library.zig
@@ -0,0 +1,8 @@
+const std = @import("std");
+const builtin = @import("builtin");
+
+comptime {
+ @export(internalName, .{ .name = if (builtin.single_threaded) "single_threaded" else "multi_threaded", .linkage = .Strong });
+}
+
+fn internalName() callconv(.C) void {}
diff --git a/e2e/workspace/configure-threaded/test_multi.zig b/e2e/workspace/configure-threaded/test_multi.zig
new file mode 100644
index 00000000..ebecf3b8
--- /dev/null
+++ b/e2e/workspace/configure-threaded/test_multi.zig
@@ -0,0 +1,6 @@
+const std = @import("std");
+const builtin = @import("builtin");
+
+test "single_threaded is false" {
+ try std.testing.expect(!builtin.single_threaded);
+}
diff --git a/e2e/workspace/configure-threaded/test_single.zig b/e2e/workspace/configure-threaded/test_single.zig
new file mode 100644
index 00000000..63951ffd
--- /dev/null
+++ b/e2e/workspace/configure-threaded/test_single.zig
@@ -0,0 +1,6 @@
+const std = @import("std");
+const builtin = @import("builtin");
+
+test "single_threaded is true" {
+ try std.testing.expect(builtin.single_threaded);
+}
diff --git a/zig/config/BUILD.bazel b/zig/config/BUILD.bazel
index b6fabcc6..a694dccb 100644
--- a/zig/config/BUILD.bazel
+++ b/zig/config/BUILD.bazel
@@ -4,6 +4,7 @@ filegroup(
srcs = [
":BUILD.bazel",
"//zig/config/mode:all_files",
+ "//zig/config/threaded:all_files",
],
visibility = ["//zig:__pkg__"],
)
diff --git a/zig/config/threaded/BUILD.bazel b/zig/config/threaded/BUILD.bazel
new file mode 100644
index 00000000..e69dc8dc
--- /dev/null
+++ b/zig/config/threaded/BUILD.bazel
@@ -0,0 +1,20 @@
+config_setting(
+ name = "multi",
+ flag_values = {
+ "//zig/settings:threaded": "multi",
+ },
+)
+
+config_setting(
+ name = "single",
+ flag_values = {
+ "//zig/settings:threaded": "single",
+ },
+)
+
+# Execute `bazel run //util:update_filegroups` to update this target.
+filegroup(
+ name = "all_files",
+ srcs = [":BUILD.bazel"],
+ visibility = ["//zig/config:__pkg__"],
+)
diff --git a/zig/private/providers/zig_settings_info.bzl b/zig/private/providers/zig_settings_info.bzl
index 3da9762a..55a6aff6 100644
--- a/zig/private/providers/zig_settings_info.bzl
+++ b/zig/private/providers/zig_settings_info.bzl
@@ -4,6 +4,7 @@ ZigSettingsInfo = provider(
doc = "Collection of all active Zig build settings.",
fields = {
"mode": "The Zig build mode.",
+ "threaded": "The Zig multi- or single-threaded setting.",
"args": "The collected compiler arguments for all active settings.",
},
)
diff --git a/zig/private/settings.bzl b/zig/private/settings.bzl
index 4ddef3c1..e780df7d 100644
--- a/zig/private/settings.bzl
+++ b/zig/private/settings.bzl
@@ -11,6 +11,10 @@ ATTRS = {
doc = "The build mode setting.",
mandatory = True,
),
+ "threaded": attr.label(
+ doc = "The Zig multi- or single-threaded setting.",
+ mandatory = True,
+ ),
}
MODE_ARGS = {
@@ -22,14 +26,25 @@ MODE_ARGS = {
MODE_VALUES = ["debug", "release_safe", "release_small", "release_fast"]
+THREADED_ARGS = {
+ "multi": ["-fno-single-threaded"],
+ "single": ["-fsingle-threaded"],
+}
+
+THREADED_VALUES = ["multi", "single"]
+
def _settings_impl(ctx):
args = []
mode = ctx.attr.mode[BuildSettingInfo].value
args.extend(MODE_ARGS[mode])
+ threaded = ctx.attr.threaded[BuildSettingInfo].value
+ args.extend(THREADED_ARGS[threaded])
+
settings_info = ZigSettingsInfo(
mode = mode,
+ threaded = threaded,
args = args,
)
diff --git a/zig/private/zig_configure.bzl b/zig/private/zig_configure.bzl
index 5debd504..0501ccee 100644
--- a/zig/private/zig_configure.bzl
+++ b/zig/private/zig_configure.bzl
@@ -1,21 +1,29 @@
"""Implementation of the zig_configure rule."""
load("@bazel_skylib//lib:paths.bzl", "paths")
-load("//zig/private:settings.bzl", "MODE_VALUES")
+load("//zig/private:settings.bzl", "MODE_VALUES", "THREADED_VALUES")
DOC = """\
"""
def _zig_transition_impl(settings, attr):
- result = {}
+ result = dict(settings)
if attr.mode:
result["//zig/settings:mode"] = attr.mode
+ if attr.threaded:
+ result["//zig/settings:threaded"] = attr.threaded
return result
_zig_transition = transition(
implementation = _zig_transition_impl,
- inputs = [],
- outputs = ["//zig/settings:mode"],
+ inputs = [
+ "//zig/settings:mode",
+ "//zig/settings:threaded",
+ ],
+ outputs = [
+ "//zig/settings:mode",
+ "//zig/settings:threaded",
+ ],
)
def _make_attrs(*, executable, test):
@@ -31,6 +39,11 @@ def _make_attrs(*, executable, test):
mandatory = False,
values = MODE_VALUES,
),
+ "threaded": attr.string(
+ doc = "The threaded setting",
+ mandatory = False,
+ values = THREADED_VALUES,
+ ),
"_whitelist_function_transition": attr.label(
default = "@bazel_tools//tools/whitelists/function_transition_whitelist",
),
diff --git a/zig/settings/BUILD.bazel b/zig/settings/BUILD.bazel
index 752e93d5..609c3542 100644
--- a/zig/settings/BUILD.bazel
+++ b/zig/settings/BUILD.bazel
@@ -1,21 +1,30 @@
load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
-load("//zig/private:settings.bzl", "settings")
+load(
+ "//zig/private:settings.bzl",
+ "MODE_VALUES",
+ "THREADED_VALUES",
+ "settings",
+)
settings(
name = "settings",
mode = ":mode",
+ threaded = ":threaded",
visibility = ["//visibility:public"],
)
string_flag(
name = "mode",
build_setting_default = "debug",
- values = [
- "debug",
- "release_safe",
- "release_small",
- "release_fast",
- ],
+ values = MODE_VALUES,
+ visibility = ["//zig/config/mode:__pkg__"],
+)
+
+string_flag(
+ name = "threaded",
+ build_setting_default = "multi",
+ values = THREADED_VALUES,
+ visibility = ["//zig/config/threaded:__pkg__"],
)
# Execute `bazel run //util:update_filegroups` to update this target.
diff --git a/zig/tests/BUILD.bazel b/zig/tests/BUILD.bazel
index 9bf0f4c1..b539fe77 100644
--- a/zig/tests/BUILD.bazel
+++ b/zig/tests/BUILD.bazel
@@ -1,12 +1,26 @@
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+load(":config_test.bzl", "config_test_suite")
load(":mode_test.bzl", "mode_test_suite")
load(":package_info_test.bzl", "package_info_test_suite")
load(":rules_test.bzl", "rules_test_suite")
+load(":threaded_test.bzl", "threaded_test_suite")
load(":versions_test.bzl", "versions_test_suite")
+config_test_suite(name = "config_test")
+
mode_test_suite(name = "mode_test")
package_info_test_suite(name = "package_info_test")
rules_test_suite(name = "rules_test")
+threaded_test_suite(name = "threaded_test")
+
versions_test_suite(name = "versions_test")
+
+bzl_library(
+ name = "util",
+ srcs = ["util.bzl"],
+ visibility = ["//visibility:public"],
+ deps = ["@bazel_skylib//lib:unittest"],
+)
diff --git a/zig/tests/config_test.bzl b/zig/tests/config_test.bzl
new file mode 100644
index 00000000..b9fbee1e
--- /dev/null
+++ b/zig/tests/config_test.bzl
@@ -0,0 +1,83 @@
+"""Analysis tests for Zig configuration settings."""
+
+load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts", "unittest")
+load("@bazel_skylib//lib:partial.bzl", "partial")
+
+_ValueInfo = provider(
+ doc = "Returns the value attribute of a value rule.",
+ fields = ["value"],
+)
+
+def _value_impl(ctx):
+ return [_ValueInfo(value = ctx.attr.value)]
+
+_string_value = rule(
+ _value_impl,
+ attrs = {
+ "value": attr.string(mandatory = True),
+ },
+)
+
+def _define_config_settings_test(*, flag, value):
+ def _test_impl(ctx):
+ env = analysistest.begin(ctx)
+
+ actual_value = analysistest.target_under_test(env)[_ValueInfo].value
+ asserts.equals(env, value, actual_value, "Unexpected value for {}".format(flag))
+
+ return analysistest.end(env)
+
+ return analysistest.make(
+ _test_impl,
+ config_settings = {flag: value},
+ )
+
+# TODO[AH] Canonicalize this label (`str(Label(...))`) for `bzlmod` support.
+# Note, that canonicalization is not compatible with Bazel 5.3.2, where it will
+# strip the requried `@` prefix.
+_SETTINGS_MODE = "@//zig/settings:mode"
+_SETTINGS_THREADED = "@//zig/settings:threaded"
+
+_mode_debug_test = _define_config_settings_test(flag = _SETTINGS_MODE, value = "debug")
+_mode_release_safe_test = _define_config_settings_test(flag = _SETTINGS_MODE, value = "release_safe")
+_mode_release_small_test = _define_config_settings_test(flag = _SETTINGS_MODE, value = "release_small")
+_mode_release_fast_test = _define_config_settings_test(flag = _SETTINGS_MODE, value = "release_fast")
+
+_threaded_single_test = _define_config_settings_test(flag = _SETTINGS_THREADED, value = "single")
+_threaded_multi_test = _define_config_settings_test(flag = _SETTINGS_THREADED, value = "multi")
+
+def config_test_suite(name):
+ """Test suite for configuration settings.
+
+ Args:
+ name: String, A unique name to assign to the test-suite.
+ """
+ mode_name = "{}_mode".format(name)
+ _string_value(
+ name = mode_name,
+ value = select({
+ "//zig/config/mode:debug": "debug",
+ "//zig/config/mode:release_safe": "release_safe",
+ "//zig/config/mode:release_small": "release_small",
+ "//zig/config/mode:release_fast": "release_fast",
+ }),
+ )
+ threaded_name = "{}_threaded".format(name)
+ _string_value(
+ name = threaded_name,
+ value = select({
+ "//zig/config/threaded:single": "single",
+ "//zig/config/threaded:multi": "multi",
+ }),
+ )
+ unittest.suite(
+ name,
+ # mode
+ partial.make(_mode_debug_test, target_under_test = mode_name),
+ partial.make(_mode_release_safe_test, target_under_test = mode_name),
+ partial.make(_mode_release_small_test, target_under_test = mode_name),
+ partial.make(_mode_release_fast_test, target_under_test = mode_name),
+ # threaded
+ partial.make(_threaded_single_test, target_under_test = threaded_name),
+ partial.make(_threaded_multi_test, target_under_test = threaded_name),
+ )
diff --git a/zig/tests/mode_test.bzl b/zig/tests/mode_test.bzl
index 83f5f570..39fd5992 100644
--- a/zig/tests/mode_test.bzl
+++ b/zig/tests/mode_test.bzl
@@ -3,25 +3,17 @@
load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts", "unittest")
load("@bazel_skylib//lib:partial.bzl", "partial")
load("//zig/private/providers:zig_settings_info.bzl", "ZigSettingsInfo")
+load(
+ ":util.bzl",
+ "assert_find_action",
+ "assert_find_unique_option",
+)
# TODO[AH] Canonicalize this label (`str(Label(...))`) for `bzlmod` support.
# Note, that canonicalization is not compatible with Bazel 5.3.2, where it will
# strip the requried `@` prefix.
_SETTINGS_MODE = "@//zig/settings:mode"
-def _assert_find_unique_option(env, name, args):
- index = -1
- for i, arg in enumerate(args):
- if arg == name:
- asserts.equals(env, -1, index, "The option {} should be unique.".format(name))
- index = i
- asserts.true(env, index + 1 <= len(args), "The option {} should have an argument.".format(name))
- asserts.false(env, index == -1, "The option {} should be set.".format(name))
- if index != -1:
- return args[index + 1]
- else:
- return None
-
def _define_settings_mode_test(mode, option):
def _test_impl(ctx):
env = analysistest.begin(ctx)
@@ -29,7 +21,7 @@ def _define_settings_mode_test(mode, option):
settings = analysistest.target_under_test(env)[ZigSettingsInfo]
asserts.equals(env, mode, settings.mode)
- mode_option = _assert_find_unique_option(env, "-O", settings.args)
+ mode_option = assert_find_unique_option(env, "-O", settings.args)
asserts.equals(env, option, mode_option)
return analysistest.end(env)
@@ -44,20 +36,12 @@ _settings_mode_release_safe_test = _define_settings_mode_test("release_safe", "R
_settings_mode_release_small_test = _define_settings_mode_test("release_small", "ReleaseSmall")
_settings_mode_release_fast_test = _define_settings_mode_test("release_fast", "ReleaseFast")
-def _assert_find_action(env, mnemonic):
- actions = analysistest.target_actions(env)
- for action in actions:
- if action.mnemonic == mnemonic:
- return action
- asserts.true(env, False, "Expected an action with mnemonic {}.".format(mnemonic))
- return None
-
def _define_build_mode_test(mnemonic, mode, option):
def _test_impl(ctx):
env = analysistest.begin(ctx)
- action = _assert_find_action(env, mnemonic)
- mode_option = _assert_find_unique_option(env, "-O", action.argv)
+ action = assert_find_action(env, mnemonic)
+ mode_option = assert_find_unique_option(env, "-O", action.argv)
asserts.equals(env, option, mode_option)
return analysistest.end(env)
diff --git a/zig/tests/threaded_test.bzl b/zig/tests/threaded_test.bzl
new file mode 100644
index 00000000..72c06e71
--- /dev/null
+++ b/zig/tests/threaded_test.bzl
@@ -0,0 +1,78 @@
+"""Analysis tests for Zig multi- or single-threaded settings."""
+
+load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts", "unittest")
+load("@bazel_skylib//lib:partial.bzl", "partial")
+load("//zig/private/providers:zig_settings_info.bzl", "ZigSettingsInfo")
+load(
+ ":util.bzl",
+ "assert_find_action",
+ "assert_flag_set",
+ "assert_flag_unset",
+)
+
+# TODO[AH] Canonicalize this label (`str(Label(...))`) for `bzlmod` support.
+# Note, that canonicalization is not compatible with Bazel 5.3.2, where it will
+# strip the requried `@` prefix.
+_SETTINGS_THREADED = "@//zig/settings:threaded"
+
+def _define_settings_threaded_test(threaded, flag_set, flag_not_set):
+ def _test_impl(ctx):
+ env = analysistest.begin(ctx)
+
+ settings = analysistest.target_under_test(env)[ZigSettingsInfo]
+ asserts.equals(env, threaded, settings.threaded)
+
+ assert_flag_set(env, flag_set, settings.args)
+ assert_flag_unset(env, flag_not_set, settings.args)
+
+ return analysistest.end(env)
+
+ return analysistest.make(
+ _test_impl,
+ config_settings = {_SETTINGS_THREADED: threaded},
+ )
+
+_settings_threaded_single_test = _define_settings_threaded_test("single", "-fsingle-threaded", "-fno-single-threaded")
+_settings_threaded_multi_test = _define_settings_threaded_test("multi", "-fno-single-threaded", "-fsingle-threaded")
+
+def _define_build_threaded_test(mnemonic, threaded, flag_set, flag_not_set):
+ def _test_impl(ctx):
+ env = analysistest.begin(ctx)
+
+ action = assert_find_action(env, mnemonic)
+
+ assert_flag_set(env, flag_set, action.argv)
+ assert_flag_unset(env, flag_not_set, action.argv)
+
+ return analysistest.end(env)
+
+ return analysistest.make(
+ _test_impl,
+ config_settings = {_SETTINGS_THREADED: threaded},
+ )
+
+_build_exe_threaded_single_test = _define_build_threaded_test("ZigBuildExe", "single", "-fsingle-threaded", "-fno-single-threaded")
+_build_exe_threaded_multi_test = _define_build_threaded_test("ZigBuildExe", "multi", "-fno-single-threaded", "-fsingle-threaded")
+
+_build_lib_threaded_single_test = _define_build_threaded_test("ZigBuildLib", "single", "-fsingle-threaded", "-fno-single-threaded")
+_build_lib_threaded_multi_test = _define_build_threaded_test("ZigBuildLib", "multi", "-fno-single-threaded", "-fsingle-threaded")
+
+_build_test_threaded_single_test = _define_build_threaded_test("ZigBuildTest", "single", "-fsingle-threaded", "-fno-single-threaded")
+_build_test_threaded_multi_test = _define_build_threaded_test("ZigBuildTest", "multi", "-fno-single-threaded", "-fsingle-threaded")
+
+def threaded_test_suite(name):
+ unittest.suite(
+ name,
+ # Test Zig threaded setting on the settings target
+ partial.make(_settings_threaded_single_test, target_under_test = "//zig/settings"),
+ partial.make(_settings_threaded_multi_test, target_under_test = "//zig/settings"),
+ # Test Zig threaded setting on a binary target
+ partial.make(_build_exe_threaded_single_test, target_under_test = "//zig/tests/simple-binary:binary"),
+ partial.make(_build_exe_threaded_multi_test, target_under_test = "//zig/tests/simple-binary:binary"),
+ # Test Zig threaded setting on a library target
+ partial.make(_build_lib_threaded_single_test, target_under_test = "//zig/tests/simple-library:library"),
+ partial.make(_build_lib_threaded_multi_test, target_under_test = "//zig/tests/simple-library:library"),
+ # Test Zig threaded setting on a test target
+ partial.make(_build_test_threaded_single_test, target_under_test = "//zig/tests/simple-test:test"),
+ partial.make(_build_test_threaded_multi_test, target_under_test = "//zig/tests/simple-test:test"),
+ )
diff --git a/zig/tests/util.bzl b/zig/tests/util.bzl
new file mode 100644
index 00000000..15d469d6
--- /dev/null
+++ b/zig/tests/util.bzl
@@ -0,0 +1,83 @@
+"""Utilities for unit and analysis tests."""
+
+load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
+
+def _is_flag_set(flag, args):
+ """Check whether the given flag is set.
+
+ Args:
+ flag: String, The name of the flag, including any `--` prefix.
+ args: sequence of String, The list of arguments to search in.
+
+ Returns:
+ True if the flag is set, False otherwise.
+ """
+ for arg in args:
+ if arg == flag:
+ return True
+ return False
+
+def assert_flag_set(env, flag, args):
+ """Assert that the given flag is set.
+
+ Args:
+ env: The Skylib unittest environment object.
+ flag: String, The name of the flag, including any `--` prefix.
+ args: sequence of String, The list of arguments to search in.
+ """
+ is_set = _is_flag_set(flag, args)
+ asserts.true(env, is_set, "The flag {} should have been set.".format(flag))
+
+def assert_flag_unset(env, flag, args):
+ """Assert that the given flag is not set.
+
+ Args:
+ env: The Skylib unittest environment object.
+ flag: String, The name of the flag, including any `--` prefix.
+ args: sequence of String, The list of arguments to search in.
+ """
+ is_set = _is_flag_set(flag, args)
+ asserts.false(env, is_set, "The flag {} should not have been set.".format(flag))
+
+def assert_find_unique_option(env, name, args):
+ """Assert that the given option is set and unique and return its value.
+
+ Args:
+ env: The Skylib unittest environment object.
+ name: String, The name of the flag, including any `--` prefix.
+ args: sequence of String, The list of arguments to search in.
+
+ Returns:
+ The option value of the argument or `None` if unset.
+ """
+ index = -1
+ for i, arg in enumerate(args):
+ if arg == name:
+ asserts.equals(env, -1, index, "The option {} should be unique.".format(name))
+ index = i
+ asserts.true(env, index + 1 <= len(args), "The option {} should have an argument.".format(name))
+ asserts.false(env, index == -1, "The option {} should be set.".format(name))
+ if index != -1:
+ return args[index + 1]
+ else:
+ return None
+
+def assert_find_action(env, mnemonic):
+ """Assert that the given action mnemonic exists and return the first instance.
+
+ Args:
+ env: The Skylib unittest environment object.
+ mnemonic: String, The action mnemonic to look for.
+
+ Returns:
+ The action object or `None` if not found.
+ """
+ actions = analysistest.target_actions(env)
+
+ for action in actions:
+ if action.mnemonic == mnemonic:
+ return action
+
+ asserts.true(env, False, "Expected an action with mnemonic {}.".format(mnemonic))
+
+ return None