diff --git a/docs/extensions.md b/docs/extensions.md index 78d6b450..780471aa 100644 --- a/docs/extensions.md +++ b/docs/extensions.md @@ -8,7 +8,11 @@ Extensions for bzlmod.
 zig = use_extension("@rules_zig//zig:extensions.bzl", "zig")
-zig.toolchain(default, zig_version)
+zig.toolchain(name, default, extra_exec_compatible_with, extra_target_compatible_with,
+              extra_target_settings, zig_version)
+zig.extra_exec_compatible_with(constraints)
+zig.extra_target_compatible_with(constraints)
+zig.extra_target_settings(settings)
 zig.index(file)
 zig.mirrors(urls)
 
@@ -37,9 +41,49 @@ Defaults to the latest known version. | Name | Description | Type | Mandatory | Default | | :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A descriptive suffix for generated toolchain targets. Leave empty for the default wrapper names. | Name | optional | `""` | | default | Make this the default Zig SDK version. Can only be used once, and only in the root module. | Boolean | optional | `False` | +| extra_exec_compatible_with | Additional execution platform constraints for generated Zig SDK toolchain targets. | List of labels | optional | `[]` | +| extra_target_compatible_with | Additional target platform constraints for generated Zig SDK toolchain targets. | List of labels | optional | `[]` | +| extra_target_settings | Additional target settings for generated Zig SDK toolchain targets. | List of labels | optional | `[]` | | zig_version | The Zig SDK version. | String | required | | + + +### extra_exec_compatible_with + +Add execution platform constraints to all generated Zig SDK toolchain targets. + +**Attributes** + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| constraints | Additional execution platform constraints for generated Zig SDK toolchain targets. | List of labels | optional | `[]` | + + + +### extra_target_compatible_with + +Add target platform constraints to all generated Zig SDK toolchain targets. + +**Attributes** + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| constraints | Additional target platform constraints for generated Zig SDK toolchain targets. | List of labels | optional | `[]` | + + + +### extra_target_settings + +Add target settings to all generated Zig SDK toolchain targets. + +**Attributes** + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| settings | Additional target settings for generated Zig SDK toolchain targets. | List of labels | optional | `[]` | + ### index diff --git a/zig/private/bzlmod/zig.bzl b/zig/private/bzlmod/zig.bzl index a9d635d2..3aa4853c 100644 --- a/zig/private/bzlmod/zig.bzl +++ b/zig/private/bzlmod/zig.bzl @@ -21,12 +21,32 @@ _DEFAULT_NAME = "zig" zig_toolchain = tag_class( attrs = { + "name": attr.string( + doc = "A descriptive suffix for generated toolchain targets. Leave empty for the default wrapper names.", + mandatory = False, + default = "", + ), "zig_version": attr.string(doc = "The Zig SDK version.", mandatory = True), "default": attr.bool( doc = "Make this the default Zig SDK version. Can only be used once, and only in the root module.", mandatory = False, default = False, ), + "extra_exec_compatible_with": attr.label_list( + doc = "Additional execution platform constraints for generated Zig SDK toolchain targets.", + mandatory = False, + default = [], + ), + "extra_target_compatible_with": attr.label_list( + doc = "Additional target platform constraints for generated Zig SDK toolchain targets.", + mandatory = False, + default = [], + ), + "extra_target_settings": attr.label_list( + doc = "Additional target settings for generated Zig SDK toolchain targets.", + mandatory = False, + default = [], + ), }, doc = """\ Fetch and define toolchain targets for the given Zig SDK version. @@ -35,6 +55,45 @@ Defaults to the latest known version. """, ) +zig_extra_exec_compatible_with = tag_class( + attrs = { + "constraints": attr.label_list( + doc = "Additional execution platform constraints for generated Zig SDK toolchain targets.", + mandatory = False, + default = [], + ), + }, + doc = """\ +Add execution platform constraints to all generated Zig SDK toolchain targets. +""", +) + +zig_extra_target_compatible_with = tag_class( + attrs = { + "constraints": attr.label_list( + doc = "Additional target platform constraints for generated Zig SDK toolchain targets.", + mandatory = False, + default = [], + ), + }, + doc = """\ +Add target platform constraints to all generated Zig SDK toolchain targets. +""", +) + +zig_extra_target_settings = tag_class( + attrs = { + "settings": attr.label_list( + doc = "Additional target settings for generated Zig SDK toolchain targets.", + mandatory = False, + default = [], + ), + }, + doc = """\ +Add target settings to all generated Zig SDK toolchain targets. +""", +) + zig_index = tag_class( attrs = { "file": attr.label(doc = "The Zig version index JSON file.", mandatory = True), @@ -56,6 +115,9 @@ zig_mirrors = tag_class( TAG_CLASSES = { "toolchain": zig_toolchain, + "extra_exec_compatible_with": zig_extra_exec_compatible_with, + "extra_target_compatible_with": zig_extra_target_compatible_with, + "extra_target_settings": zig_extra_target_settings, "index": zig_index, "mirrors": zig_mirrors, } @@ -70,23 +132,67 @@ def handle_toolchain_tags(modules, *, known_versions): known_versions: sequence of string, The set of known Zig versions. Returns: - (err, versions), maybe an error or the list of versions. + (err, versions, variants), maybe an error, the ordered list of versions, + and the list of requested toolchain wrappers. """ default = None versions = sets.make() + variants = [] + variant_keys = {} + global_extra_exec_compatible_with = [] + global_extra_target_compatible_with = [] + global_extra_target_settings = [] + + for mod in modules: + for extra in mod.tags.extra_exec_compatible_with: + if not mod.is_root: + return (["Only the root module may specify extra Zig SDK execution constraints.", extra], None, None) + + global_extra_exec_compatible_with.extend([str(label) for label in extra.constraints]) + + for extra in mod.tags.extra_target_compatible_with: + if not mod.is_root: + return (["Only the root module may specify extra Zig SDK target constraints.", extra], None, None) + + global_extra_target_compatible_with.extend([str(label) for label in extra.constraints]) + + for extra in mod.tags.extra_target_settings: + if not mod.is_root: + return (["Only the root module may specify extra Zig SDK target settings.", extra], None, None) + + global_extra_target_settings.extend([str(label) for label in extra.settings]) for mod in modules: for toolchain in mod.tags.toolchain: if toolchain.default: if not mod.is_root: - return (["Only the root module may specify a default Zig SDK version.", toolchain], None) + return (["Only the root module may specify a default Zig SDK version.", toolchain], None, None) if default != None: - return (["You may only specify one default Zig SDK version.", toolchain], None) + return (["You may only specify one default Zig SDK version.", toolchain], None, None) default = toolchain.zig_version sets.insert(versions, toolchain.zig_version) + key = "{}\n{}".format(toolchain.zig_version, toolchain.name) + extra_exec_compatible_with = global_extra_exec_compatible_with + [str(label) for label in toolchain.extra_exec_compatible_with] + extra_target_compatible_with = global_extra_target_compatible_with + [str(label) for label in toolchain.extra_target_compatible_with] + extra_target_settings = global_extra_target_settings + [str(label) for label in toolchain.extra_target_settings] + variant_fingerprint = repr((extra_exec_compatible_with, extra_target_compatible_with, extra_target_settings)) + if key in variant_keys: + if variant_keys[key] == variant_fingerprint: + continue + + return (["Conflicting Zig SDK toolchain variant name '{}' for version '{}'.".format(toolchain.name, toolchain.zig_version), toolchain], None, None) + + variant_keys[key] = variant_fingerprint + variants.append(struct( + name = toolchain.name, + zig_version = toolchain.zig_version, + extra_exec_compatible_with = extra_exec_compatible_with, + extra_target_compatible_with = extra_target_compatible_with, + extra_target_settings = extra_target_settings, + )) if default != None: sets.remove(versions, default) @@ -98,8 +204,15 @@ def handle_toolchain_tags(modules, *, known_versions): if len(versions) == 0: versions.append(known_versions[0]) + variants.append(struct( + name = "", + zig_version = known_versions[0], + extra_exec_compatible_with = global_extra_exec_compatible_with, + extra_target_compatible_with = global_extra_target_compatible_with, + extra_target_settings = global_extra_target_settings, + )) - return None, versions + return None, versions, variants def parse_zig_versions_json(json_string): """Parse a Zig SDK versions index in JSON format. @@ -182,7 +295,7 @@ def _toolchain_extension(module_ctx): known_versions = merge_version_specs(version_specs) - (err, versions) = handle_toolchain_tags(module_ctx.modules, known_versions = known_versions.keys()) + (err, versions, toolchain_variants) = handle_toolchain_tags(module_ctx.modules, known_versions = known_versions.keys()) if err != None: fail(*err) @@ -191,15 +304,14 @@ def _toolchain_extension(module_ctx): toolchain_zig_versions = [] toolchain_exec_lengths = [] toolchain_exec_constraints = [] + toolchain_target_compatible_lengths = [] + toolchain_target_compatible_constraints = [] + toolchain_target_settings_lengths = [] + toolchain_target_settings = [] for zig_version in versions: sanitized_zig_version = sanitize_version(zig_version) for platform, meta in PLATFORMS.items(): repo_name = _DEFAULT_NAME + "_" + sanitized_zig_version + "_" + platform - toolchain_names.append(repo_name) - toolchain_labels.append("@{}//:zig_toolchain".format(repo_name)) - toolchain_zig_versions.append(zig_version) - toolchain_exec_lengths.append(len(meta.compatible_with)) - toolchain_exec_constraints.extend(meta.compatible_with) zig_repository( name = repo_name, url = known_versions[zig_version][platform].url, @@ -208,6 +320,24 @@ def _toolchain_extension(module_ctx): zig_version = zig_version, platform = platform, ) + for variant in toolchain_variants: + if variant.zig_version != zig_version: + continue + + name = repo_name + if variant.name: + name = "{}_{}".format(name, variant.name) + + compatible_with = meta.compatible_with + variant.extra_exec_compatible_with + toolchain_names.append(name) + toolchain_labels.append("@{}//:zig_toolchain".format(repo_name)) + toolchain_zig_versions.append(zig_version) + toolchain_exec_lengths.append(len(compatible_with)) + toolchain_exec_constraints.extend(compatible_with) + toolchain_target_compatible_lengths.append(len(variant.extra_target_compatible_with)) + toolchain_target_compatible_constraints.extend(variant.extra_target_compatible_with) + toolchain_target_settings_lengths.append(len(variant.extra_target_settings)) + toolchain_target_settings.extend(variant.extra_target_settings) toolchains_repo( name = _DEFAULT_NAME + "_toolchains", @@ -216,6 +346,10 @@ def _toolchain_extension(module_ctx): zig_versions = toolchain_zig_versions, exec_lengths = toolchain_exec_lengths, exec_constraints = toolchain_exec_constraints, + target_compatible_lengths = toolchain_target_compatible_lengths, + target_compatible_constraints = toolchain_target_compatible_constraints, + target_settings_lengths = toolchain_target_settings_lengths, + target_settings = toolchain_target_settings, ) zig = module_extension( diff --git a/zig/private/repo/toolchains_repo.bzl b/zig/private/repo/toolchains_repo.bzl index 9696a7e6..c404950e 100644 --- a/zig/private/repo/toolchains_repo.bzl +++ b/zig/private/repo/toolchains_repo.bzl @@ -34,6 +34,10 @@ ATTRS = { "zig_versions": attr.string_list(doc = "The Zig SDK versions of the corresponding toolchain targets."), "exec_lengths": attr.int_list(doc = "The length of the slice of the `exec_constraints` attribute that corresponds to each toolchain target."), "exec_constraints": attr.string_list(doc = "All toolchain execution platform constraints concatenated to a single list."), + "target_compatible_lengths": attr.int_list(doc = "The length of the slice of the `target_compatible_constraints` attribute that corresponds to each toolchain target."), + "target_compatible_constraints": attr.string_list(doc = "All toolchain target platform constraints concatenated to a single list."), + "target_settings_lengths": attr.int_list(doc = "The length of the slice of the `target_settings` attribute that corresponds to each toolchain target."), + "target_settings": attr.string_list(doc = "All extra toolchain target settings concatenated to a single list."), } def sanitize_version(zig_version): @@ -63,10 +67,10 @@ def _toolchains_repo_impl(repository_ctx): len_expected = len(repository_ctx.attr.names) len_equal = all([ len_expected == len(getattr(repository_ctx.attr, attr)) - for attr in ["labels", "zig_versions", "exec_lengths"] + for attr in ["labels", "zig_versions", "exec_lengths", "target_compatible_lengths", "target_settings_lengths"] ]) if not len_equal: - fail("Lengths of the attributes `names`, `labels`, `zig_versions`, `exec_lengths` must match.") + fail("Lengths of the attributes `names`, `labels`, `zig_versions`, `exec_lengths`, `target_compatible_lengths`, `target_settings_lengths` must match.") len_exec_constraints = 0 for exec_len in repository_ctx.attr.exec_lengths: @@ -75,6 +79,20 @@ def _toolchains_repo_impl(repository_ctx): if not len_exec_constraints == len(repository_ctx.attr.exec_constraints): fail("Length of the `exec_constraints` attribute must match the sum of `exec_lengths`.") + len_target_compatible_constraints = 0 + for target_compatible_len in repository_ctx.attr.target_compatible_lengths: + len_target_compatible_constraints += target_compatible_len + + if not len_target_compatible_constraints == len(repository_ctx.attr.target_compatible_constraints): + fail("Length of the `target_compatible_constraints` attribute must match the sum of `target_compatible_lengths`.") + + len_target_settings = 0 + for target_settings_len in repository_ctx.attr.target_settings_lengths: + len_target_settings += target_settings_len + + if not len_target_settings == len(repository_ctx.attr.target_settings): + fail("Length of the `target_settings` attribute must match the sum of `target_settings_lengths`.") + if len(repository_ctx.attr.zig_versions) < 1: fail("Must specify at least one Zig SDK version in `zig_versions`.") @@ -160,18 +178,27 @@ selects.config_setting_group( repository_ctx.attr.labels, repository_ctx.attr.zig_versions, repository_ctx.attr.exec_lengths, + repository_ctx.attr.target_compatible_lengths, + repository_ctx.attr.target_settings_lengths, ) exec_offset = 0 - for counter, (name, label, zig_version, exec_len) in enumerate(zipped): + target_compatible_offset = 0 + target_settings_offset = 0 + for counter, (name, label, zig_version, exec_len, target_compatible_len, target_settings_len) in enumerate(zipped): compatible_with = repository_ctx.attr.exec_constraints[exec_offset:exec_offset + exec_len] exec_offset += exec_len + target_compatible_with = repository_ctx.attr.target_compatible_constraints[target_compatible_offset:target_compatible_offset + target_compatible_len] + target_compatible_offset += target_compatible_len + target_settings = [":{}".format(zig_version)] + repository_ctx.attr.target_settings[target_settings_offset:target_settings_offset + target_settings_len] + target_settings_offset += target_settings_len build_content += """ # Declare a toolchain Bazel will select for running the tool in an action # on the execution platform. toolchain( name = "{prefix}_{name}_toolchain", exec_compatible_with = {compatible_with}, - target_settings = [":{version}"], + target_compatible_with = {target_compatible_with}, + target_settings = {target_settings}, toolchain = "{label}", toolchain_type = "@rules_zig//zig:toolchain_type", ) @@ -179,7 +206,8 @@ toolchain( prefix = _counter_prefix(counter, width = counter_digits), name = name, compatible_with = compatible_with, - version = zig_version, + target_compatible_with = target_compatible_with, + target_settings = target_settings, label = label, ) diff --git a/zig/tests/bzlmod_zig_test.bzl b/zig/tests/bzlmod_zig_test.bzl index c89dafd2..780ab3be 100644 --- a/zig/tests/bzlmod_zig_test.bzl +++ b/zig/tests/bzlmod_zig_test.bzl @@ -277,254 +277,566 @@ _merge_version_specs_test = unittest.make( _merge_version_specs_test_impl, ) +def _toolchain_tag(*, zig_version, default = False, name = "", extra_exec_compatible_with = [], extra_target_compatible_with = [], extra_target_settings = []): + return struct( + name = name, + zig_version = zig_version, + default = default, + extra_exec_compatible_with = extra_exec_compatible_with, + extra_target_compatible_with = extra_target_compatible_with, + extra_target_settings = extra_target_settings, + ) + +def _extra_compatible_with(*, constraints = []): + return struct( + constraints = constraints, + ) + +def _extra_target_settings(*, settings = []): + return struct( + settings = settings, + ) + +def _toolchain_variant(*, zig_version, name = "", extra_exec_compatible_with = [], extra_target_compatible_with = [], extra_target_settings = []): + return struct( + name = name, + zig_version = zig_version, + extra_exec_compatible_with = extra_exec_compatible_with, + extra_target_compatible_with = extra_target_compatible_with, + extra_target_settings = extra_target_settings, + ) + +def _handle_toolchain_tags(modules, *, known_versions): + modules = [ + struct( + is_root = mod.is_root, + tags = struct( + toolchain = mod.tags.toolchain, + extra_exec_compatible_with = getattr(mod.tags, "extra_exec_compatible_with", []), + extra_target_compatible_with = getattr(mod.tags, "extra_target_compatible_with", []), + extra_target_settings = getattr(mod.tags, "extra_target_settings", []), + ), + ) + for mod in modules + ] + return handle_toolchain_tags(modules, known_versions = known_versions) + +def _assert_toolchain_versions(env, expected, modules, *, known_versions, msg): + result = _handle_toolchain_tags(modules, known_versions = known_versions) + asserts.equals(env, None, result[0], msg) + asserts.equals(env, expected, result[1], msg) + def _zig_versions_test_impl(ctx): env = unittest.begin(ctx) + _assert_toolchain_versions( + env, + ["0.1.0"], + [], + known_versions = ["0.1.0"], + msg = "should fall back to the default Zig SDK version", + ) + asserts.equals( env, - (None, ["0.1.0"]), - handle_toolchain_tags([], known_versions = ["0.1.0"]), - "should fall back to the default Zig SDK version", + [_toolchain_variant(zig_version = "0.1.0")], + _handle_toolchain_tags([], known_versions = ["0.1.0"])[2], + "fallback should create one default wrapper", + ) + + _assert_toolchain_versions( + env, + ["0.1.0"], + [ + struct( + is_root = False, + tags = struct( + toolchain = [ + _toolchain_tag(zig_version = "0.1.0"), + ], + ), + ), + ], + known_versions = ["0.1.0"], + msg = "should choose a single configured version", + ) + + _assert_toolchain_versions( + env, + ["0.4.0", "0.2.0", "0.1.0", "0.0.1"], + [ + struct( + is_root = False, + tags = struct( + toolchain = [ + _toolchain_tag(zig_version = "0.0.1"), + _toolchain_tag(zig_version = "0.4.0"), + ], + ), + ), + struct( + is_root = False, + tags = struct( + toolchain = [ + _toolchain_tag(zig_version = "0.2.0"), + _toolchain_tag(zig_version = "0.1.0"), + ], + ), + ), + ], + known_versions = ["0.4.0", "0.2.0", "0.1.0", "0.0.1"], + msg = "should order versions by semver", + ) + + _assert_toolchain_versions( + env, + ["0.1.0", "0.0.1"], + [ + struct( + is_root = False, + tags = struct( + toolchain = [ + _toolchain_tag(zig_version = "0.0.1"), + _toolchain_tag(zig_version = "0.1.0"), + ], + ), + ), + struct( + is_root = False, + tags = struct( + toolchain = [ + _toolchain_tag(zig_version = "0.0.1"), + _toolchain_tag(zig_version = "0.1.0"), + ], + ), + ), + ], + known_versions = ["0.1.0", "0.0.1"], + msg = "should deduplicate versions", ) asserts.equals( env, - (None, ["0.1.0"]), - handle_toolchain_tags( + [ + _toolchain_variant(zig_version = "0.0.1"), + _toolchain_variant(zig_version = "0.1.0"), + ], + _handle_toolchain_tags( [ struct( is_root = False, tags = struct( toolchain = [ - struct( - default = False, + _toolchain_tag(zig_version = "0.0.1"), + _toolchain_tag(zig_version = "0.1.0"), + ], + ), + ), + struct( + is_root = False, + tags = struct( + toolchain = [ + _toolchain_tag(zig_version = "0.0.1"), + _toolchain_tag(zig_version = "0.1.0"), + ], + ), + ), + ], + known_versions = ["0.1.0", "0.0.1"], + )[2], + "should deduplicate identical wrappers", + ) + + asserts.equals( + env, + [ + _toolchain_variant( + name = "local", + zig_version = "0.1.0", + extra_exec_compatible_with = ["//constraints:local"], + extra_target_compatible_with = ["//constraints:target"], + extra_target_settings = ["//settings:enabled"], + ), + ], + _handle_toolchain_tags( + [ + struct( + is_root = True, + tags = struct( + toolchain = [ + _toolchain_tag( + name = "local", zig_version = "0.1.0", + extra_exec_compatible_with = ["//constraints:local"], + extra_target_compatible_with = ["//constraints:target"], + extra_target_settings = ["//settings:enabled"], ), ], ), ), ], known_versions = ["0.1.0"], - ), - "should choose a single configured version", + )[2], + "should preserve wrapper metadata", ) asserts.equals( env, - (None, ["0.4.0", "0.2.0", "0.1.0", "0.0.1"]), - handle_toolchain_tags( + [ + _toolchain_variant( + zig_version = "0.1.0", + extra_exec_compatible_with = ["//constraints:global"], + extra_target_compatible_with = ["//constraints:target"], + extra_target_settings = ["//settings:global"], + ), + ], + _handle_toolchain_tags( [ struct( is_root = False, tags = struct( toolchain = [ - struct( - default = False, - zig_version = "0.0.1", - ), - struct( - default = False, - zig_version = "0.4.0", - ), + _toolchain_tag(zig_version = "0.1.0"), ], ), ), struct( - is_root = False, + is_root = True, tags = struct( - toolchain = [ - struct( - default = False, - zig_version = "0.2.0", - ), - struct( - default = False, - zig_version = "0.1.0", - ), + toolchain = [], + extra_exec_compatible_with = [ + _extra_compatible_with(constraints = ["//constraints:global"]), + ], + extra_target_compatible_with = [ + _extra_compatible_with(constraints = ["//constraints:target"]), + ], + extra_target_settings = [ + _extra_target_settings(settings = ["//settings:global"]), ], ), ), ], - known_versions = ["0.4.0", "0.2.0", "0.1.0", "0.0.1"], - ), - "should order versions by semver", + known_versions = ["0.1.0"], + )[2], + "root extras should apply to transitive toolchain tags", ) asserts.equals( env, - (None, ["0.1.0", "0.0.1"]), - handle_toolchain_tags( + [ + _toolchain_variant( + name = "local", + zig_version = "0.1.0", + extra_exec_compatible_with = [ + "//constraints:global", + "//constraints:local", + ], + extra_target_compatible_with = [ + "//constraints:target-global", + "//constraints:target-local", + ], + extra_target_settings = [ + "//settings:global", + "//settings:local", + ], + ), + ], + _handle_toolchain_tags( [ struct( - is_root = False, + is_root = True, tags = struct( toolchain = [ - struct( - default = False, - zig_version = "0.0.1", - ), - struct( - default = False, + _toolchain_tag( + name = "local", zig_version = "0.1.0", + extra_exec_compatible_with = ["//constraints:local"], + extra_target_compatible_with = ["//constraints:target-local"], + extra_target_settings = ["//settings:local"], ), ], + extra_exec_compatible_with = [ + _extra_compatible_with(constraints = ["//constraints:global"]), + ], + extra_target_compatible_with = [ + _extra_compatible_with(constraints = ["//constraints:target-global"]), + ], + extra_target_settings = [ + _extra_target_settings(settings = ["//settings:global"]), + ], ), ), + ], + known_versions = ["0.1.0"], + )[2], + "per-toolchain metadata should be appended after root extras", + ) + + asserts.equals( + env, + [ + _toolchain_variant( + zig_version = "0.1.0", + extra_exec_compatible_with = [ + "//constraints:first", + "//constraints:second", + ], + extra_target_settings = [ + "//settings:first", + "//settings:second", + ], + ), + ], + _handle_toolchain_tags( + [ struct( - is_root = False, + is_root = True, tags = struct( - toolchain = [ - struct( - default = False, - zig_version = "0.0.1", - ), - struct( - default = False, - zig_version = "0.1.0", - ), + toolchain = [], + extra_exec_compatible_with = [ + _extra_compatible_with(constraints = ["//constraints:first"]), + _extra_compatible_with(constraints = ["//constraints:second"]), + ], + extra_target_settings = [ + _extra_target_settings(settings = ["//settings:first"]), + _extra_target_settings(settings = ["//settings:second"]), ], ), ), ], - known_versions = ["0.1.0", "0.0.1"], - ), - "should deduplicate versions", + known_versions = ["0.1.0"], + )[2], + "root extras should be additive", ) asserts.equals( env, - (None, ["0.1.0", "0.4.0", "0.2.0", "0.0.1"]), - handle_toolchain_tags( + [ + _toolchain_variant( + zig_version = "0.1.0", + extra_exec_compatible_with = ["//constraints:global"], + extra_target_compatible_with = ["//constraints:target-global"], + extra_target_settings = ["//settings:global"], + ), + ], + _handle_toolchain_tags( + [ + struct( + is_root = True, + tags = struct( + toolchain = [], + extra_exec_compatible_with = [ + _extra_compatible_with(constraints = ["//constraints:global"]), + ], + extra_target_compatible_with = [ + _extra_compatible_with(constraints = ["//constraints:target-global"]), + ], + extra_target_settings = [ + _extra_target_settings(settings = ["//settings:global"]), + ], + ), + ), + ], + known_versions = ["0.1.0"], + )[2], + "fallback wrapper should inherit root extras", + ) + + _assert_toolchain_versions( + env, + ["0.1.0", "0.4.0", "0.2.0", "0.0.1"], + [ + struct( + is_root = False, + tags = struct( + toolchain = [ + _toolchain_tag(zig_version = "0.0.1"), + _toolchain_tag(zig_version = "0.4.0"), + ], + ), + ), + struct( + is_root = True, + tags = struct( + toolchain = [ + _toolchain_tag(zig_version = "0.2.0"), + _toolchain_tag(zig_version = "0.1.0", default = True), + ], + ), + ), + ], + known_versions = ["0.4.0", "0.2.0", "0.1.0", "0.0.1"], + msg = "the default should take precedence", + ) + + _assert_toolchain_versions( + env, + ["0.1.0", "0.2.0", "0.0.1"], + [ + struct( + is_root = False, + tags = struct( + toolchain = [ + _toolchain_tag(zig_version = "0.0.1"), + _toolchain_tag(zig_version = "0.1.0"), + ], + ), + ), + struct( + is_root = True, + tags = struct( + toolchain = [ + _toolchain_tag(zig_version = "0.2.0"), + _toolchain_tag(zig_version = "0.1.0", default = True), + ], + ), + ), + ], + known_versions = ["0.2.0", "0.1.0", "0.0.1"], + msg = "should not duplicate default", + ) + + asserts.equals( + env, + (["Only the root module may specify a default Zig SDK version.", _toolchain_tag( + default = True, + zig_version = "0.1.0", + )], None, None), + _handle_toolchain_tags( [ struct( is_root = False, tags = struct( toolchain = [ - struct( - default = False, - zig_version = "0.0.1", - ), - struct( - default = False, - zig_version = "0.4.0", - ), + _toolchain_tag(zig_version = "0.1.0", default = True), ], ), ), + ], + known_versions = ["0.1.0"], + ), + "only root may set default", + ) + + asserts.equals( + env, + (["You may only specify one default Zig SDK version.", _toolchain_tag( + default = True, + zig_version = "0.2.0", + )], None, None), + _handle_toolchain_tags( + [ struct( is_root = True, tags = struct( toolchain = [ - struct( - default = False, - zig_version = "0.2.0", - ), - struct( - default = True, - zig_version = "0.1.0", - ), + _toolchain_tag(zig_version = "0.1.0", default = True), + _toolchain_tag(zig_version = "0.2.0", default = True), ], ), ), ], - known_versions = ["0.4.0", "0.2.0", "0.1.0", "0.0.1"], + known_versions = ["0.2.0", "0.1.0"], ), - "the default should take precedence", + "only one default allowed", ) asserts.equals( env, - (None, ["0.1.0", "0.2.0", "0.0.1"]), - handle_toolchain_tags( + (["Conflicting Zig SDK toolchain variant name 'local' for version '0.1.0'.", _toolchain_tag( + name = "local", + zig_version = "0.1.0", + extra_target_settings = ["//settings:disabled"], + )], None, None), + _handle_toolchain_tags( [ struct( - is_root = False, + is_root = True, tags = struct( toolchain = [ - struct( - default = False, - zig_version = "0.0.1", + _toolchain_tag( + name = "local", + zig_version = "0.1.0", + extra_target_settings = ["//settings:enabled"], ), - struct( - default = False, + _toolchain_tag( + name = "local", zig_version = "0.1.0", + extra_target_settings = ["//settings:disabled"], ), ], ), ), + ], + known_versions = ["0.1.0"], + ), + "conflicting duplicate wrapper metadata should fail", + ) + + asserts.equals( + env, + (["Only the root module may specify extra Zig SDK execution constraints.", _extra_compatible_with( + constraints = ["//constraints:global"], + )], None, None), + _handle_toolchain_tags( + [ struct( - is_root = True, + is_root = False, tags = struct( - toolchain = [ - struct( - default = False, - zig_version = "0.2.0", - ), - struct( - default = True, - zig_version = "0.1.0", - ), + toolchain = [], + extra_exec_compatible_with = [ + _extra_compatible_with(constraints = ["//constraints:global"]), ], ), ), ], - known_versions = ["0.2.0", "0.1.0", "0.0.1"], + known_versions = ["0.1.0"], ), - "should not duplicate default", + "only root may set extra execution constraints", ) asserts.equals( env, - (["Only the root module may specify a default Zig SDK version.", struct( - default = True, - zig_version = "0.1.0", - )], None), - handle_toolchain_tags( + (["Only the root module may specify extra Zig SDK target constraints.", _extra_compatible_with( + constraints = ["//constraints:target"], + )], None, None), + _handle_toolchain_tags( [ struct( is_root = False, tags = struct( - toolchain = [ - struct( - default = True, - zig_version = "0.1.0", - ), + toolchain = [], + extra_target_compatible_with = [ + _extra_compatible_with(constraints = ["//constraints:target"]), ], ), ), ], known_versions = ["0.1.0"], ), - "only root may set default", + "only root may set extra target constraints", ) asserts.equals( env, - (["You may only specify one default Zig SDK version.", struct( - default = True, - zig_version = "0.2.0", - )], None), - handle_toolchain_tags( + (["Only the root module may specify extra Zig SDK target settings.", _extra_target_settings( + settings = ["//settings:global"], + )], None, None), + _handle_toolchain_tags( [ struct( - is_root = True, + is_root = False, tags = struct( - toolchain = [ - struct( - default = True, - zig_version = "0.1.0", - ), - struct( - default = True, - zig_version = "0.2.0", - ), + toolchain = [], + extra_target_settings = [ + _extra_target_settings(settings = ["//settings:global"]), ], ), ), ], - known_versions = ["0.2.0", "0.1.0"], + known_versions = ["0.1.0"], ), - "only one default allowed", + "only root may set extra target settings", ) return unittest.end(env)