feat: make variable substitution for py_wheel abi, python_tag args (#1113)

Expands make variables in to `abi` and `python_tag` attributes

---------

Co-authored-by: Richard Levasseur <richardlev@gmail.com>
diff --git a/examples/wheel/BUILD.bazel b/examples/wheel/BUILD.bazel
index 4124a82..61a43ae 100644
--- a/examples/wheel/BUILD.bazel
+++ b/examples/wheel/BUILD.bazel
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 load("@bazel_skylib//rules:build_test.bzl", "build_test")
-load("//examples/wheel/private:wheel_utils.bzl", "directory_writer")
+load("//examples/wheel/private:wheel_utils.bzl", "directory_writer", "make_variable_tags")
 load("//python:defs.bzl", "py_library", "py_test")
 load("//python:packaging.bzl", "py_package", "py_wheel")
 load("//python:versions.bzl", "gen_python_config_settings")
@@ -62,6 +62,29 @@
     ],
 )
 
+# Populate a rule with "Make Variable" arguments for
+# abi, python_tag and version. You might want to do this
+# for the following use cases:
+#  - abi, python_tag: introspect a toolchain to map to appropriate cpython tags
+#  - version: populate given this or a dependent module's version
+make_variable_tags(
+    name = "make_variable_tags",
+)
+
+py_wheel(
+    name = "minimal_with_py_library_with_make_variables",
+    testonly = True,
+    abi = "$(ABI)",
+    distribution = "example_minimal_library",
+    python_tag = "$(PYTHON_TAG)",
+    toolchains = ["//examples/wheel:make_variable_tags"],
+    version = "$(VERSION)",
+    deps = [
+        "//examples/wheel/lib:module_with_data",
+        "//examples/wheel/lib:simple_module",
+    ],
+)
+
 build_test(
     name = "dist_build_tests",
     targets = [":minimal_with_py_library.dist"],
diff --git a/examples/wheel/private/wheel_utils.bzl b/examples/wheel/private/wheel_utils.bzl
index af4fa19..037fed0 100644
--- a/examples/wheel/private/wheel_utils.bzl
+++ b/examples/wheel/private/wheel_utils.bzl
@@ -54,3 +54,20 @@
         ),
     },
 )
+
+def _make_variable_tags_impl(ctx):  # buildifier: disable=unused-variable
+    # This example is contrived. In a real usage, this rule would
+    # look at flags or dependencies to determine what values to use.
+    # If all you're doing is setting constant values, then you can simply
+    # set them in the py_wheel() call.
+    vars = {}
+    vars["ABI"] = "cp38"
+    vars["PYTHON_TAG"] = "cp38"
+    vars["VERSION"] = "0.99.0"
+    return [platform_common.TemplateVariableInfo(vars)]
+
+make_variable_tags = rule(
+    attrs = {},
+    doc = """Make variable tags to pass to a py_wheel rule.""",
+    implementation = _make_variable_tags_impl,
+)
diff --git a/python/private/py_wheel.bzl b/python/private/py_wheel.bzl
index 77690ed..b6f2bfa 100644
--- a/python/private/py_wheel.bzl
+++ b/python/private/py_wheel.bzl
@@ -207,12 +207,15 @@
     return "%s;%s" % (py_package_lib.path_inside_wheel(input_file), input_file.path)
 
 def _py_wheel_impl(ctx):
+    abi = _replace_make_variables(ctx.attr.abi, ctx)
+    python_tag = _replace_make_variables(ctx.attr.python_tag, ctx)
     version = _replace_make_variables(ctx.attr.version, ctx)
+
     outfile = ctx.actions.declare_file("-".join([
         _escape_filename_segment(ctx.attr.distribution),
         _escape_filename_segment(version),
-        _escape_filename_segment(ctx.attr.python_tag),
-        _escape_filename_segment(ctx.attr.abi),
+        _escape_filename_segment(python_tag),
+        _escape_filename_segment(abi),
         _escape_filename_segment(ctx.attr.platform),
     ]) + ".whl")
 
@@ -237,8 +240,8 @@
     args = ctx.actions.args()
     args.add("--name", ctx.attr.distribution)
     args.add("--version", version)
-    args.add("--python_tag", ctx.attr.python_tag)
-    args.add("--abi", ctx.attr.abi)
+    args.add("--python_tag", python_tag)
+    args.add("--abi", abi)
     args.add("--platform", ctx.attr.platform)
     args.add("--out", outfile)
     args.add("--name_file", name_file)