How to expose headers from a PyPI package
When you depend on a PyPI package that includes C headers (like numpy), you
need to make those headers available to your cc_library or
cc_binary targets.
The recommended way to do this is to inject a BUILD.bazel file into the
external repository for the package. This BUILD file will create
a cc_library target that exposes the header files.
First, create a .bzl file that has the extra logic we’ll inject. Putting it
in a separate bzl file avoids having to redownload and extract the whl file
when our logic changes.
# pypi_extra_targets.bzl
load("@rules_cc//cc:cc_library.bzl", "cc_library")
def extra_numpy_targets():
cc_library(
name = "headers",
hdrs = glob(["**/*.h"]),
visibility = ["//visibility:public"],
)
Bzlmod setup
In your MODULE.bazel file, use the build_file_content attribute of
pip.parse to inject the BUILD file content for the numpy package.
# MODULE.bazel
load("@rules_python//python/extensions:pip.bzl", "parse", "whl_mods")
pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
whl_mods = use_extension("@rules_python//python/extensions:pip.bzl", "whl_mods")
# Define a specific modification for a wheel
whl_mods(
hub_name = "pypi_mods",
whl_name = "numpy-1.0.0-py3-none-any.whl", # The exact wheel filename
additive_build_content = """
load("@//:pypi_extra_targets.bzl", "numpy_hdrs")
extra_numpy_targets()
""",
)
pip.parse(
hub_name = "pypi",
wheel_name = "numpy",
requirements_lock = "//:requirements.txt",
whl_modifications = {
"@pypi_mods//:numpy.json": "numpy",
},
extra_hub_aliases = {
"numpy": ["headers"],
}
)
WORKSPACE setup
In your WORKSPACE file, use the annotations attribute of pip_parse to
inject additional BUILD file content, then use extra_hub_targets to expose
that target in the @pypi hub repo.
The package_annotation helper can be used to construct the value for the
annotations attribute.
# WORKSPACE
load("@rules_python//python:pip.bzl", "package_annotation", "pip_parse")
pip_parse(
name = "pypi",
requirements_lock = "//:requirements.txt",
annotations = {
"numpy": package_annotation(
additive_build_content = """\
load("@//:pypi_extra_targets.bzl", "numpy_hdrs")
extra_numpy_targets()
"""
),
},
extra_hub_targets = {
"numpy": ["headers"],
},
)
Using the headers
In your BUILD.bazel file, you can now depend on the generated headers
target.
# BUILD.bazel
cc_library(
name = "my_c_extension",
srcs = ["my_c_extension.c"],
deps = ["@pypi//numpy:headers"],
)