diff --git a/lib/BUILD b/lib/BUILD index c44ee12..f2bb778 100644 --- a/lib/BUILD +++ b/lib/BUILD @@ -20,6 +20,7 @@ bzl_library( srcs = ["compatibility.bzl"], deps = [ ":selects", + "//lib/compatibility:defs", ], ) diff --git a/lib/compatibility.bzl b/lib/compatibility.bzl index 8c8f230..ea6bbc4 100644 --- a/lib/compatibility.bzl +++ b/lib/compatibility.bzl @@ -10,51 +10,7 @@ more information. """ load(":selects.bzl", "selects") - -def _get_name_from_target_list(targets, joiner = " or "): - """Join a list of strings into a string which is suitable as a target name. - - The return value has a hash appended so that it is different between multiple "targets" values - that have the same name portion. For readability, we keep only the name portion of the - specified targets. But for uniqueness we need the hash. For example, the following two calls - may return strings as follows. The hashes are arbitrary in this example. - - >>> _get_name_from_target_list(["@platforms//os:linux", "@platforms//cpu:x86_64"]) - "linux or x86_64 (3ef2349)" - >>> _get_name_from_target_list(["//some/custom:linux", "//some/custom:x86_64"]) - "linux or x86_64 (98ab64)" - - Args: - targets: A list of target names. - joiner: An optional string to use for joining the list. - - Returns: - A string which is a valid target name. - """ - - # Compute absolute labels from the user-specified ones. They can be - # relative or absolute. We do this to make the final name as unique as - # possible via a hash. - package_label = Label("//" + native.package_name()) - absolute_targets = sorted([package_label.relative(target) for target in targets]) - joined_names = joiner.join([target.name for target in absolute_targets]) - name = "%s (%x)" % (joined_names, hash(str(absolute_targets))) - return name - -def _maybe_make_unique_incompatible_value(name): - """Creates a `native.constraint_value` which is "incompatible." - - When composing selects which could all resolve to "incompatible" we need distinct labels. - This will create a `constraint_value` with the given name, if it does not already exist. - - Args: - name: A target name to check and use. - """ - if not native.existing_rule(name): - native.constraint_value( - name = name, - constraint_setting = "@platforms//:incompatible_setting", - ) +load("//lib/compatibility:defs.bzl", "MAX_NUM_ALL_OF_SETTINGS") def _none_of(*settings): """Create a `select()` for `target_compatible_with` which matches none of the given settings. @@ -83,12 +39,9 @@ def _none_of(*settings): Returns: A native `select()` which maps any of the settings to the incompatible target. """ - compat_name = " incompatible with " + _get_name_from_target_list(settings) - _maybe_make_unique_incompatible_value(compat_name) - return selects.with_or({ "//conditions:default": [], - tuple(settings): [":" + compat_name], + tuple(settings): ["@bazel_skylib//lib/compatibility:none_of"], }) def _any_of(*settings): @@ -118,12 +71,9 @@ def _any_of(*settings): Returns: A native `select()` which maps any of the settings an empty list. """ - compat_name = " compatible with any of " + _get_name_from_target_list(settings) - _maybe_make_unique_incompatible_value(compat_name) - return selects.with_or({ tuple(settings): [], - "//conditions:default": [":" + compat_name], + "//conditions:default": ["@bazel_skylib//lib/compatibility:any_of"], }) def _all_of(*settings): @@ -160,23 +110,18 @@ def _all_of(*settings): *settings: The `config_setting` or `constraint_value` targets. Returns: - A native `select()` which is "incompatible" unless all settings are true. + A native series of `select()`s. The result is "incompatible" unless all settings are true. """ - group_name = _get_name_from_target_list(settings, joiner = " and ") - compat_name = " compatible with all of " + group_name - _maybe_make_unique_incompatible_value(compat_name) + if len(settings) > MAX_NUM_ALL_OF_SETTINGS: + fail("Cannot support more than {} arguments. Use selects.config_setting_group() instead.".format(MAX_NUM_ALL_OF_SETTINGS)) - # all_of can only be accomplished with a config_setting_group.match_all. - if not native.existing_rule(group_name): - selects.config_setting_group( - name = group_name, - match_all = settings, - ) - - return select({ - ":" + group_name: [], - "//conditions:default": [":" + compat_name], - }) + result = [] + for i, setting in enumerate(settings): + result += select({ + setting: [], + "//conditions:default": ["@bazel_skylib//lib/compatibility:all_of_{}".format(i)], + }) + return result compatibility = struct( all_of = _all_of, diff --git a/lib/compatibility/BUILD b/lib/compatibility/BUILD new file mode 100644 index 0000000..0aa2d32 --- /dev/null +++ b/lib/compatibility/BUILD @@ -0,0 +1,32 @@ +load(":defs.bzl", "MAX_NUM_ALL_OF_SETTINGS") +load("//:bzl_library.bzl", "bzl_library") + +licenses(["notice"]) + +package(default_visibility = ["//visibility:public"]) + +bzl_library( + name = "defs", + srcs = ["defs.bzl"], +) + +filegroup( + name = "build_file", + testonly = True, + srcs = ["BUILD"], +) + +constraint_value( + name = "none_of", + constraint_setting = "@platforms//:incompatible_setting", +) + +constraint_value( + name = "any_of", + constraint_setting = "@platforms//:incompatible_setting", +) + +[constraint_value( + name = "all_of_" + str(i), + constraint_setting = "@platforms//:incompatible_setting", +) for i in range(50)] diff --git a/lib/compatibility/defs.bzl b/lib/compatibility/defs.bzl new file mode 100644 index 0000000..19da5a2 --- /dev/null +++ b/lib/compatibility/defs.bzl @@ -0,0 +1,2 @@ +# The maximum number of arguments we support for compatibility.all_of(). +MAX_NUM_ALL_OF_SETTINGS = 50 diff --git a/tests/BUILD b/tests/BUILD index babb4b9..87b34fb 100644 --- a/tests/BUILD +++ b/tests/BUILD @@ -98,6 +98,7 @@ sh_test( data = [ ":unittest.bash", "//lib:compatibility", + "//lib/compatibility:build_file", ], tags = ["local"], deps = [ diff --git a/tests/compatibility_test.sh b/tests/compatibility_test.sh index 5f0b6a6..a9c06a8 100755 --- a/tests/compatibility_test.sh +++ b/tests/compatibility_test.sh @@ -67,11 +67,21 @@ EOF workspace(name = 'bazel_skylib') EOF + cat > BUILD < bzl_library.bzl < lib/BUILD <" + expect_log "//lib/compatibility:none_of\\>" } cd "$TEST_TMPDIR"