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