feat: Expose Python C headers through the toolchain. (#1287)
This allows getting a build's `cc_library` of Python headers through
toolchain resolution instead of having to use the underlying toolchain's
repository `:python_headers` target directly.
Without this feature, it's not possible to reliably and correctly get
the C information about the runtime a build is going to use. Existing
solutions require carefully setting up repo names, external state,
and/or using specific build rules. In comparison, with this feature,
consumers are able to simply ask for the current headers via a helper
target or manually lookup the toolchain and pull the relevant
information; toolchain resolution handles finding the correct headers.
The basic way this works is by registering a second toolchain to carry
C/C++ related information; as such, it is named `py_cc_toolchain`. The
py cc toolchain has the same constraint settings as the regular py
toolchain; an expected invariant is that there is a 1:1 correspondence
between the two. This base functionality allows a consuming rule
implementation to use toolchain resolution to find the Python C
toolchain information.
Usually what downstream consumers need are the headers to feed into
another `cc_library` (or equivalent) target, so, rather than have every
project re-implement the same "lookup and forward cc_library info"
logic,
this is provided by the `//python/cc:current_py_cc_headers` target.
Targets that need the headers can then depend on that target as if it
was a `cc_library` target.
Work towards https://github.com/bazelbuild/rules_python/issues/824
diff --git a/python/cc/BUILD.bazel b/python/cc/BUILD.bazel
new file mode 100644
index 0000000..d4a6bb8
--- /dev/null
+++ b/python/cc/BUILD.bazel
@@ -0,0 +1,44 @@
+# Package for C/C++ specific functionality of the Python rules.
+
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+load("//python/private:current_py_cc_headers.bzl", "current_py_cc_headers")
+load("//python/private:util.bzl", "BZLMOD_ENABLED")
+
+package(
+ default_visibility = ["//:__subpackages__"],
+)
+
+# This target provides the C headers for whatever the current toolchain is
+# for the consuming rule. It basically acts like a cc_library by forwarding
+# on the providers for the underlying cc_library that the toolchain is using.
+current_py_cc_headers(
+ name = "current_py_cc_headers",
+ # Building this directly will fail unless a py cc toolchain is registered,
+ # and it's only under bzlmod that one is registered by default.
+ tags = [] if BZLMOD_ENABLED else ["manual"],
+ visibility = ["//visibility:public"],
+)
+
+toolchain_type(
+ name = "toolchain_type",
+ visibility = ["//visibility:public"],
+)
+
+bzl_library(
+ name = "py_cc_toolchain_bzl",
+ srcs = ["py_cc_toolchain.bzl"],
+ visibility = ["//visibility:public"],
+ deps = ["//python/private:py_cc_toolchain_bzl"],
+)
+
+bzl_library(
+ name = "py_cc_toolchain_info_bzl",
+ srcs = ["py_cc_toolchain_info.bzl"],
+ visibility = ["//visibility:public"],
+ deps = ["//python/private:py_cc_toolchain_info_bzl"],
+)
+
+filegroup(
+ name = "distribution",
+ srcs = glob(["**"]),
+)