diff --git a/MODULE.bazel b/MODULE.bazel index c50471017a..6269216734 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -175,8 +175,11 @@ register_toolchains( "//proto/prost:default_prost_toolchain", ) +bindgen = use_extension("//bindgen:extension.bzl", "bindgen") +use_repo(bindgen, "bindgen_toolchains") + register_toolchains( - "//bindgen:default_bindgen_toolchain", + "@bindgen_toolchains//:default_bindgen_toolchain", ) rust_host_tools = use_extension("//rust:extensions.bzl", "rust_host_tools") diff --git a/bindgen/3rdparty/patches/llvm-project.workspace_root.patch b/bindgen/3rdparty/patches/llvm-project.workspace_root.patch new file mode 100644 index 0000000000..46f77112f5 --- /dev/null +++ b/bindgen/3rdparty/patches/llvm-project.workspace_root.patch @@ -0,0 +1,68 @@ +diff --git b/utils/bazel/llvm-project-overlay/clang/BUILD.bazel a/utils/bazel/llvm-project-overlay/clang/BUILD.bazel +--- b/utils/bazel/llvm-project-overlay/clang/BUILD.bazel ++++ a/utils/bazel/llvm-project-overlay/clang/BUILD.bazel +@@ -1,8 +1,9 @@ + # 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 + ++load("//:workspace_root.bzl", "workspace_root") + load("//llvm:tblgen.bzl", "gentbl") + load("//llvm:binary_alias.bzl", "binary_alias") + load("//llvm:cc_plugin_library.bzl", "cc_plugin_library") + load("//llvm:config.bzl", "llvm_stdcxx_copts") +@@ -684,8 +685,10 @@ gentbl( + td_srcs = [ + "include/clang/Basic/ASTNode.td", + "include/clang/Basic/TypeNodes.td", + ], + ) ++ ++workspace_root(name = "workspace_root") + + cc_library( + name = "ast", +@@ -711,8 +714,8 @@ cc_library( + # least bad approach. Using `includes` is *specifically* problematic for + # this library because it contains files that collide easily with system + # headers such as `CXXABI.h`. +- "-I$(GENDIR)/external/llvm-project/clang/lib/AST", +- "-I$(GENDIR)/external/llvm-project/clang/lib/AST/Interp", ++ "-I$(GENDIR)/$(WORKSPACE_ROOT)/clang/lib/AST", ++ "-I$(GENDIR)/$(WORKSPACE_ROOT)/clang/lib/AST/Interp", + ] + llvm_stdcxx_copts, + textual_hdrs = [ + "include/clang/AST/AttrImpl.inc", +@@ -730,8 +733,11 @@ cc_library + "include/clang/AST/StmtDataCollectors.inc", + "include/clang/AST/StmtNodes.inc", + ] + glob([ + "include/clang/AST/*.def", + ], allow_empty = True), ++ toolchains = [ ++ ":workspace_root", ++ ], + deps = [ + ":ast_attr_gen", + ":ast_comment_command_info_gen", + +--- /dev/null ++++ a/utils/bazel/llvm-project-overlay/workspace_root.bzl +@@ -0,0 +1,17 @@ ++def _workspace_root_impl(ctx): ++ """Dynamically determine the workspace root from the current context. ++ ++ The path is made available as a `WORKSPACE_ROOT` environmment variable and ++ may for instance be consumed in the `toolchains` attributes for `cc_library` ++ and `genrule` targets. ++ """ ++ return [ ++ platform_common.TemplateVariableInfo({ ++ "WORKSPACE_ROOT": ctx.label.workspace_root, ++ }), ++ ] ++ ++workspace_root = rule( ++ implementation = _workspace_root_impl, ++ attrs = {}, ++) diff --git a/bindgen/BUILD.bazel b/bindgen/BUILD.bazel index 0ee90783ba..69ead2c8fd 100644 --- a/bindgen/BUILD.bazel +++ b/bindgen/BUILD.bazel @@ -1,5 +1,4 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library") -load("//bindgen:defs.bzl", "rust_bindgen_toolchain") package(default_visibility = ["//visibility:public"]) @@ -11,21 +10,18 @@ bzl_library( name = "bzl_lib", srcs = glob(["**/*.bzl"]), deps = [ - "//bindgen/3rdparty:bzl_lib", - "//bindgen/private:bzl_lib", - "//rust:bzl_lib", + "@rules_rust//bindgen/3rdparty:bzl_lib", + "@rules_rust//bindgen/private:bzl_lib", + "@rules_rust//rust:bzl_lib", ], ) -rust_bindgen_toolchain( +alias( name = "default_bindgen_toolchain_impl", - bindgen = "//bindgen/3rdparty:bindgen", - clang = "@llvm-project//clang:clang", - libclang = "@llvm-project//clang:libclang", + actual = "//bindgen/toolchain:default_bindgen_toolchain_impl", ) -toolchain( +alias( name = "default_bindgen_toolchain", - toolchain = "default_bindgen_toolchain_impl", - toolchain_type = "//bindgen:toolchain_type", + actual = "//bindgen/toolchain:default_bindgen_toolchain", ) diff --git a/bindgen/extension.bzl b/bindgen/extension.bzl new file mode 100644 index 0000000000..b02c749b77 --- /dev/null +++ b/bindgen/extension.bzl @@ -0,0 +1,47 @@ +"""Module extension for accessing a bindgen toolchain""" + +load(":repositories.bzl", "rust_bindgen_dependencies") +load(":transitive_repositories.bzl", "rust_bindgen_transitive_dependencies") + +def _bindgen_impl(_): + rust_bindgen_transitive_dependencies(repo_mapping = None) + rust_bindgen_dependencies() + bindgen_toolchains( + name = "bindgen_toolchains", + build_file = "//bindgen/toolchain:BUILD.bazel", + ) + +bindgen = module_extension(implementation = _bindgen_impl) + +def _bindgen_toolchains_impl(rctx): + if (rctx.attr.build_file == None) == (rctx.attr.build_file_content == "_UNSET"): + fail("exactly one of `build_file` or `build_file_content` must be specified") + + if rctx.attr.build_file != None: + rctx.file("BUILD.bazel", rctx.read(rctx.attr.build_file)) + else: + rctx.file("BUILD.bazel", rctx.attr.build_file_content) + +bindgen_toolchains = repository_rule( + implementation = _bindgen_toolchains_impl, + attrs = { + "build_file": attr.label( + doc = + "A file to use as a BUILD file for this repo." + + "

Exactly one of build_file or build_file_content" + + "must be specified.", + ), + "build_file_content": attr.string( + doc = + "The content of a BUILD file to be created for this repo." + + "

Exactly one of build_file or build_file_content" + + "must be specified.", + default = "_UNSET", + ), + }, + doc = + "Creates a local repository containing a provided BUILD file to be used for defining " + + "bindgen toolchains." + + "

This rule is a replacement for the local_repository rule available " + + "in later supported versions of Bazel.", +) diff --git a/bindgen/repositories.bzl b/bindgen/repositories.bzl index 25e8c8a6bc..8da059bc1d 100644 --- a/bindgen/repositories.bzl +++ b/bindgen/repositories.bzl @@ -40,6 +40,7 @@ def rust_bindgen_dependencies(): patches = [ Label("//bindgen/3rdparty/patches:llvm-project.cxx17.patch"), Label("//bindgen/3rdparty/patches:llvm-project.incompatible_disallow_empty_glob.patch"), + Label("//bindgen/3rdparty/patches:llvm-project.workspace_root.patch"), ], ) diff --git a/bindgen/toolchain/BUILD.bazel b/bindgen/toolchain/BUILD.bazel new file mode 100644 index 0000000000..21af90e50d --- /dev/null +++ b/bindgen/toolchain/BUILD.bazel @@ -0,0 +1,16 @@ +load("@rules_rust//bindgen:defs.bzl", "rust_bindgen_toolchain") + +package(default_visibility = ["//visibility:public"]) + +rust_bindgen_toolchain( + name = "default_bindgen_toolchain_impl", + bindgen = "@rules_rust//bindgen/3rdparty:bindgen", + clang = "@llvm-project//clang:clang", + libclang = "@llvm-project//clang:libclang", +) + +toolchain( + name = "default_bindgen_toolchain", + toolchain = "default_bindgen_toolchain_impl", + toolchain_type = "@rules_rust//bindgen:toolchain_type", +) diff --git a/bindgen/transitive_repositories.bzl b/bindgen/transitive_repositories.bzl index 66c80ee5fc..f39c3ac89e 100644 --- a/bindgen/transitive_repositories.bzl +++ b/bindgen/transitive_repositories.bzl @@ -2,18 +2,35 @@ load("@llvm-raw//utils/bazel:configure.bzl", "llvm_configure", "llvm_disable_optional_support_deps") +DEFAULT_REPO_MAPPING = { + "@llvm_zlib": "@zlib", +} +LLVM_TARGETS = ["AArch64", "X86"] + # buildifier: disable=unnamed-macro -def rust_bindgen_transitive_dependencies(): - """Declare transitive dependencies needed for bindgen.""" +def rust_bindgen_transitive_dependencies(repo_mapping = DEFAULT_REPO_MAPPING): + """Declare transitive dependencies needed for bindgen. + + Args: + repo_mapping: Mapping for renaming repositories created by this function. + The repository names created by this function are undocumented and subject + to change in the future. + """ - llvm_configure( - name = "llvm-project", - repo_mapping = {"@llvm_zlib": "@zlib"}, - targets = [ - "AArch64", - "X86", - ], - ) + # Bzlmod does not support the `repo_mapping` parameter *at all*, so we have + # to only specify it when requested. + if repo_mapping == None: + llvm_configure( + name = "llvm-project", + targets = LLVM_TARGETS, + ) + else: + llvm_repo_name = repo_mapping.get("llvm-project", "llvm-project") + llvm_configure( + name = llvm_repo_name, + repo_mapping = repo_mapping, + targets = LLVM_TARGETS, + ) # Disables optional dependencies for Support like zlib and terminfo. You may # instead want to configure them using the macros in the corresponding bzl