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.

# 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:

# 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

# 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:

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:

# 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.