| # This file is licensed under the Apache License v2.0 with LLVM Exceptions. | |
| # See https://llvm.org/LICENSE.txt for license information. | |
| # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| """bzlmod extension for making Linux kernel UAPI headers available in Bazel.""" | |
| _SYSTEM_HEADERS_PATH_ENV_VAR = "LINUX_UAPI_INCLUDE_DIR" | |
| _SYSTEM_BUILD = """\ | |
| load("@rules_cc//cc:defs.bzl", "cc_library") | |
| cc_library( | |
| name = "linux_uapi_headers", | |
| # Builds using /usr/include may have a lot of junk that does not cleanly | |
| # compile, so use `textual_hdrs` instead of `hdrs`. | |
| textual_hdrs = glob(["include/**"]), | |
| includes = ["include"], | |
| visibility = ["//visibility:public"], | |
| ) | |
| """ | |
| def _setup_from_system(repository_ctx, include_dir): | |
| """Sets up the repository from a user-provided include directory.""" | |
| if not include_dir.startswith("/"): | |
| fail("{} must be absolute, was {}".format( | |
| _SYSTEM_HEADERS_PATH_ENV_VAR, | |
| include_dir, | |
| )) | |
| if not repository_ctx.path(include_dir + "/linux").exists: | |
| fail( | |
| "{} does not contain Linux UAPI headers (no linux/ subdirectory)" | |
| .format(include_dir), | |
| ) | |
| repository_ctx.symlink(include_dir, "include") | |
| repository_ctx.file("BUILD.bazel", _SYSTEM_BUILD) | |
| return None | |
| _LIBC_DEV_PACKAGE_BUILD = """\ | |
| load("@rules_cc//cc:defs.bzl", "cc_library") | |
| cc_library( | |
| name = "linux_uapi_headers", | |
| # The linux-libc-dev package has headers for many platforms. | |
| # These may not compile, so use `textual_hdrs` instead of `hdrs`. | |
| textual_hdrs = glob(["usr/include/**/*.h"]), | |
| includes = [ | |
| "usr/include", | |
| ] + select( | |
| {{ | |
| # LLVM-libc requires the `asm` directory to exist, | |
| # so include the arch-specific directory. | |
| "@platforms//cpu:x86_64": ["usr/include/x86_64-linux-gnu"], | |
| "@platforms//cpu:arm64": ["usr/include/aarch64-linux-gnu"], | |
| "@platforms//cpu:riscv64": ["usr/include/riscv64-linux-gnu"], | |
| }}, | |
| no_match_error = \"""Unsupported CPU for the Linux UAPI headers. | |
| Use --repo_env={var_name}=/path/to/uapi/include to load from system headers, | |
| or add support for your architecture. | |
| \""", | |
| ), | |
| visibility = ["//visibility:public"], | |
| ) | |
| """.format(var_name = _SYSTEM_HEADERS_PATH_ENV_VAR) | |
| def _setup_from_libc_dev_package(repository_ctx): | |
| """Sets up linux UAPI headers from Debian's linux-libc-dev package.""" | |
| # Pulling from Linux sources and generating the headers ourselves would | |
| # provide more control, but downloading from linux-libc-dev is much faster. | |
| repository_ctx.download_and_extract( | |
| url = "https://snapshot.debian.org/archive/debian/20260501T022911Z/pool/main/l/linux/linux-libc-dev_7.0.3-1_all.deb", | |
| sha256 = "02eb444940d2e8aee116b9b1525ca2618e48b025aff75e0b75515812af121c59", | |
| ) | |
| repository_ctx.extract(archive = "data.tar.xz") | |
| repository_ctx.delete("data.tar.xz") | |
| repository_ctx.file("BUILD.bazel", _LIBC_DEV_PACKAGE_BUILD) | |
| return repository_ctx.repo_metadata(reproducible = True) | |
| def _linux_uapi_setup_impl(repository_ctx): | |
| """Sets up a repository of Linux UAPI headers.""" | |
| include_dir = repository_ctx.getenv(_SYSTEM_HEADERS_PATH_ENV_VAR, "") | |
| if include_dir: | |
| return _setup_from_system(repository_ctx, include_dir) | |
| return _setup_from_libc_dev_package(repository_ctx) | |
| linux_uapi_setup = repository_rule(implementation = _linux_uapi_setup_impl) |