| # Using IREE with Custom MLIR-Adjacent Dependencies via Bzlmod | |
| This document explains how projects that depend on IREE can provide their own | |
| LLVM, StableHLO, torch-mlir, and compiler plugin registry instead of using | |
| IREE's bundled defaults. | |
| ## Terminology | |
| ### Bzlmod | |
| Bazel's module system (introduced in Bazel 6.0, default in Bazel 7.0+). It replaces | |
| the legacy WORKSPACE file with `MODULE.bazel` for managing external dependencies. | |
| ### Root Module | |
| The top-level project being built. In bzlmod, only the root module's `MODULE.bazel` | |
| is fully evaluated - dependency modules have limited control over the build graph. | |
| ### Module Extension | |
| A mechanism for creating repositories dynamically in bzlmod. Extensions are defined | |
| in `.bzl` files and invoked via `use_extension()` in MODULE.bazel. | |
| ### `use_extension()` | |
| Runs a module extension's implementation function, which typically creates repositories. | |
| Returns an extension proxy that can be passed to `use_repo()`. | |
| ### `use_repo()` | |
| Imports repositories created by a module extension into the current module's visibility | |
| scope. Without `use_repo()`, repos created by an extension exist but aren't accessible | |
| to your BUILD files. | |
| ```python | |
| # Extension creates repos internally | |
| ext = use_extension("@some_module//:extensions.bzl", "some_extension") | |
| # use_repo makes specific repos visible as @repo_a, @repo_b, etc. | |
| use_repo(ext, "repo_a", "repo_b") | |
| ``` | |
| ### `use_repo_rule()` | |
| Imports a repository rule from another module so it can be called directly in | |
| MODULE.bazel to create a repository. | |
| ### Raw source repositories | |
| Repositories such as `llvm-raw` and `torch-mlir-raw` contain unconfigured | |
| upstream source trees. They are inputs to repository rules that overlay Bazel | |
| BUILD files and produce configured repositories such as `llvm-project` and | |
| `torch-mlir`. | |
| ### `llvm-project` | |
| The configured LLVM repository created by `llvm_configure`. It overlays Bazel BUILD | |
| files onto the `llvm-raw` source and extracts CMake configuration variables. | |
| ### `llvm-project-overlay` | |
| The bzlmod module name for LLVM's Bazel integration (located at | |
| `llvm-project/utils/bazel/`). It provides the `llvm_repos_extension` and | |
| `llvm_configure` rule. | |
| ## How It Works | |
| IREE's module extension (`iree_extension`) creates MLIR-adjacent source | |
| repositories **only when IREE is the root module**: | |
| ```python | |
| # In build_tools/bazel/extensions.bzl | |
| def _iree_extension_impl(module_ctx): | |
| if any([m.is_root and m.name == "iree_core" for m in module_ctx.modules]): | |
| new_local_repository( | |
| name = "llvm-raw", | |
| build_file_content = "# empty", | |
| path = "third_party/llvm-project", | |
| ) | |
| local_repository( | |
| name = "stablehlo", | |
| path = "third_party/stablehlo", | |
| ) | |
| new_local_repository( | |
| name = "torch-mlir-raw", | |
| build_file_content = "# empty - BUILD files overlaid by torch_mlir_configure", | |
| path = "third_party/torch-mlir", | |
| ) | |
| # ... other repos | |
| ``` | |
| When your project depends on IREE, IREE is **not** the root module - your project is. | |
| Therefore, IREE's extension will not create these MLIR-adjacent repositories, | |
| and you must provide the ones needed by the compiler plugins you enable. | |
| ## MODULE.bazel Ordering | |
| The order of statements in MODULE.bazel matters: | |
| 1. `module()` - must be first | |
| 2. `bazel_dep()` - declare module dependencies | |
| 3. `local_path_override()` - must come after the `bazel_dep()` it overrides | |
| 4. `use_extension()` - must come after the `bazel_dep()` that provides the extension | |
| 5. `use_repo()` - must come after its corresponding `use_extension()` | |
| 6. `use_repo_rule()` + invocation - can reference repos created by earlier extensions | |
| ## Example: Using Your Own LLVM, StableHLO, and torch-mlir | |
| ```python | |
| # my_project/MODULE.bazel | |
| module( | |
| name = "my_project", | |
| version = "1.0.0", | |
| ) | |
| # Standard bazel dependencies (must match or be compatible with IREE's versions) | |
| bazel_dep(name = "bazel_skylib", version = "1.8.2") | |
| bazel_dep(name = "platforms", version = "1.0.0") | |
| bazel_dep(name = "rules_cc", version = "0.2.11") | |
| # ... other deps as needed | |
| # Depend on IREE | |
| bazel_dep(name = "iree_core", version = "0.0.1") | |
| # Override IREE to use your local checkout (optional, for development) | |
| local_path_override( | |
| module_name = "iree_core", | |
| path = "third_party/iree", | |
| ) | |
| # Depend on LLVM overlay module | |
| bazel_dep(name = "llvm-project-overlay", version = "main") | |
| local_path_override( | |
| module_name = "llvm-project-overlay", | |
| path = "my/custom/llvm-project/utils/bazel", | |
| ) | |
| # Create your own raw repositories pointing to the upstream projects you want. | |
| new_local_repository = use_repo_rule( | |
| "@bazel_tools//tools/build_defs/repo:local.bzl", | |
| "new_local_repository", | |
| ) | |
| new_local_repository( | |
| name = "llvm-raw", | |
| path = "my/custom/llvm-project", | |
| build_file_content = "# empty", | |
| ) | |
| new_local_repository( | |
| name = "torch-mlir-raw", | |
| path = "my/custom/torch-mlir", | |
| build_file_content = "# empty", | |
| ) | |
| local_repository = use_repo_rule( | |
| "@bazel_tools//tools/build_defs/repo:local.bzl", | |
| "local_repository", | |
| ) | |
| local_repository( | |
| name = "stablehlo", | |
| path = "my/custom/stablehlo", | |
| ) | |
| # Use LLVM's extension for third-party deps (gmp, mpfr, etc.) | |
| llvm_repos_ext = use_extension( | |
| "@llvm-project-overlay//:extensions.bzl", | |
| "llvm_repos_extension", | |
| ) | |
| use_repo( | |
| llvm_repos_ext, | |
| "gmp", | |
| "mpc", | |
| "mpfr", | |
| "nanobind", | |
| "pfm", | |
| "pybind11", | |
| "vulkan_sdk", | |
| ) | |
| # Use IREE's extension (won't create llvm-raw since you're the root module) | |
| iree_ext = use_extension( | |
| "@iree_core//build_tools/bazel:extensions.bzl", | |
| "iree_extension", | |
| ) | |
| use_repo( | |
| iree_ext, | |
| "com_github_dvidelabs_flatcc", | |
| "com_google_benchmark", | |
| "com_google_googletest", | |
| "stablehlo", | |
| # ... other IREE repos you need | |
| ) | |
| # Configure LLVM (creates llvm-project from your llvm-raw) | |
| llvm_configure = use_repo_rule( | |
| "@llvm-raw//utils/bazel:configure.bzl", | |
| "llvm_configure", | |
| ) | |
| llvm_configure(name = "llvm-project") | |
| # Configure torch-mlir from your raw source repository if you enable the Torch | |
| # input plugin. | |
| torch_mlir_configure = use_repo_rule( | |
| "@torch-mlir-raw//utils/bazel:configure.bzl", | |
| "torch_mlir_configure", | |
| ) | |
| torch_mlir_configure( | |
| name = "torch-mlir", | |
| src_workspace = "@torch-mlir-raw//:CMakeLists.txt", | |
| ) | |
| ``` | |
| ## Custom Compiler Plugin Registry | |
| IREE's `//compiler/plugins` package loads the plugin registry from the root | |
| workspace: | |
| ```python | |
| load("@//build_tools/bazel:default_compiler_plugins.bzl", ...) | |
| ``` | |
| When IREE is the root module, this resolves to IREE's default registry. A | |
| downstream root workspace can provide a file at the same path to register | |
| additional compiler plugins, replace registration targets, or change the | |
| default enabled plugin IDs. In-tree IREE plugin labels should be qualified with | |
| `@iree_core//...` from such a downstream file. | |
| ## Using LLVM from an HTTP Archive | |
| If you want to fetch LLVM from a release tarball instead of a local path: | |
| ```python | |
| # my_project/MODULE.bazel | |
| http_archive = use_repo_rule( | |
| "@bazel_tools//tools/build_defs/repo:http.bzl", | |
| "http_archive", | |
| ) | |
| LLVM_COMMIT = "abc123..." # Your desired commit | |
| LLVM_SHA256 = "..." # SHA256 of the tarball | |
| http_archive( | |
| name = "llvm-raw", | |
| build_file_content = "# empty", | |
| sha256 = LLVM_SHA256, | |
| strip_prefix = "llvm-project-" + LLVM_COMMIT, | |
| urls = ["https://github.com/llvm/llvm-project/archive/{}.tar.gz".format(LLVM_COMMIT)], | |
| ) | |
| ``` | |
| ## Version Compatibility | |
| When providing your own LLVM, ensure compatibility with IREE: | |
| 1. **LLVM Version**: IREE targets a specific LLVM commit. Check IREE's | |
| `third_party/llvm-project` submodule for the expected version. | |
| 2. **Bazel Dependencies**: Your LLVM's `utils/bazel/MODULE.bazel` declares | |
| dependency versions. These should be compatible with IREE's dependencies. | |
| 3. **API Compatibility**: LLVM APIs change between versions. Your LLVM must | |
| be API-compatible with what IREE expects. | |
| ## Troubleshooting | |
| ### "repository 'llvm-raw' is not defined" | |
| You haven't created the `llvm-raw` repository. As the root module, you must | |
| define it yourself if you configure LLVM (see examples above). | |
| ### "repository 'stablehlo' is not defined" | |
| You enabled the StableHLO input plugin without providing a `stablehlo` | |
| repository from your root module. | |
| ### "repository 'torch-mlir' is not defined" | |
| You enabled the Torch input plugin without configuring a `torch-mlir` repository | |
| from your root module. | |
| ### Build errors in LLVM code | |
| Your LLVM version may be incompatible with IREE. Check that your LLVM commit | |
| is close to IREE's expected version. | |
| ### Duplicate repository errors | |
| Multiple modules may be trying to create the same repository. Ensure only | |
| one source defines each repository name. |