# Bazel

> Compile, test and format Java and Kotlin in Bazel with rules_elide, swap rules_kotlin's builder, or call `elide javac` and `elide kotlinc` as persistent workers from your own rules.

`rules_elide` is a Bazel module with Java and Kotlin rules that compile through `elide javac` and `elide kotlinc`
running as persistent workers. It downloads Elide itself; no JDK or Kotlin toolchain is needed.

## Requirements

| | Version |
| --- | --- |
| Bazel | 8 or 9, with Bzlmod |
| `rules_elide` | 0.7.0 |
| Elide | 1.6.0-rc.2 (the default) |
| Platforms | Linux x86_64 and arm64, macOS arm64 |

## Install

```python
# MODULE.bazel
bazel_dep(name = "rules_elide", version = "0.7.0")

elide = use_extension("@rules_elide//elide:extensions.bzl", "elide")
elide.install(version = "1.6.0-rc.2")
use_repo(elide, "elide_toolchains")
register_toolchains("@elide_toolchains//:all")
```

`elide.install()` downloads the Elide release for the host and checks it against a pinned hash; `version` must be one
the module lists. To use an Elide you installed yourself:

```python
elide.use(local_path = "/opt/elide")
```

## Rules

Load from `@rules_elide//elide:defs.bzl`.

| Rule | Does |
| --- | --- |
| `elide_java_library` | Compiles `.java` sources into a JAR |
| `elide_java_binary` | Library plus a launcher (`bazel run`) |
| `elide_java_test` | Library plus a JUnit Platform launcher (`bazel test`) |
| `elide_kotlin_library` | Compiles `.kt` and mixed `.kt`/`.java` sources |
| `elide_kotlin_binary`, `elide_kotlin_test` | As the Java variants, for Kotlin |
| `elide_format` | `bazel run` target that formats sources in place (Java or Kotlin, one per target) |
| `elide_native_image` | Native binary from JVM targets |

Every compile rule returns `JavaInfo`, so `java_library`, `kt_jvm_library` and `rules_jvm_external` targets mix freely
in `deps`. Test rules need `org.junit.platform:junit-platform-console-standalone` in `runtime_deps`.

Full attribute reference: [rules_elide docs](https://github.com/elide-dev/rules_elide/tree/main/docs).

## Example

```text
MODULE.bazel
BUILD.bazel
src/Greeter.java
src/App.kt
src/GreeterTest.java
```

```python
# MODULE.bazel
module(name = "hello")

bazel_dep(name = "rules_elide", version = "0.7.0")
bazel_dep(name = "rules_jvm_external", version = "7.1")

elide = use_extension("@rules_elide//elide:extensions.bzl", "elide")
elide.install(version = "1.6.0-rc.2")
use_repo(elide, "elide_toolchains")
register_toolchains("@elide_toolchains//:all")

maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
maven.install(
    artifacts = [
        "org.junit.jupiter:junit-jupiter-api:5.13.4",
        "org.junit.platform:junit-platform-console-standalone:1.13.4",
    ],
)
use_repo(maven, "maven")
```

```python
# BUILD.bazel
load("@rules_elide//elide:defs.bzl", "elide_java_library", "elide_java_test", "elide_kotlin_binary")

elide_java_library(
    name = "greeter",
    srcs = ["src/Greeter.java"],
)

elide_kotlin_binary(
    name = "app",
    srcs = ["src/App.kt"],
    main_class = "AppKt",
    deps = [":greeter"],
)

elide_java_test(
    name = "greeter_test",
    srcs = ["src/GreeterTest.java"],
    test_class = "GreeterTest",
    runtime_deps = ["@maven//:org_junit_platform_junit_platform_console_standalone"],
    deps = [
        ":greeter",
        "@maven//:org_junit_jupiter_junit_jupiter_api",
    ],
)
```

```bash
bazel build //...
bazel run //:app
bazel test //:greeter_test
```

```terminaloutput
INFO: 35 processes: 12 internal, 16 linux-sandbox, 7 worker.
INFO: Build completed successfully, 35 total actions

Hello, Bazel

//:greeter_test                                                 PASSED in 2.0s
Executed 1 out of 1 test: 1 test passes.
```

## Persistent workers

The compile rules run `elide javac --persistent_worker` and `elide kotlinc --persistent_worker`: one warm process per
tool serves every compile action, accepting concurrent requests and compiling them one at a time. `bazel shutdown`
stops them.

To compile each target in a new process (for example under remote execution):

```bash
bazel build --@rules_elide//elide:use_workers=false //...
```

### Workers from your own rules

Without `rules_elide`, any rule can run Elide as a worker. Bazel adds `--persistent_worker` itself; the rule passes
arguments in a parameter file:

```python
# elide.bzl
def _elide_javac_impl(ctx):
    out = ctx.actions.declare_directory(ctx.label.name + "_classes")
    args = ctx.actions.args()
    args.add("-d", out.path)
    args.add_all(ctx.files.srcs)
    args.use_param_file("@%s", use_always = True)
    args.set_param_file_format("multiline")
    ctx.actions.run(
        executable = ctx.executable._elide,
        arguments = ["javac", args],
        inputs = ctx.files.srcs,
        outputs = [out],
        mnemonic = "ElideJavac",
        execution_requirements = {"supports-workers": "1", "supports-multiplex-workers": "1"},
    )
    return [DefaultInfo(files = depset([out]))]

elide_javac = rule(
    implementation = _elide_javac_impl,
    attrs = {
        "srcs": attr.label_list(allow_files = [".java"]),
        "_elide": attr.label(default = "//tools:elide", executable = True, cfg = "exec", allow_single_file = True),
    },
)
```

```python
# BUILD.bazel
load(":elide.bzl", "elide_javac")

elide_javac(
    name = "hello",
    srcs = glob(["src/*.java"]),
)
```

```bash
mkdir -p tools && ln -s "$(command -v elide)" tools/elide
echo 'exports_files(["elide"])' > tools/BUILD.bazel
bazel build //:hello
```

```text
Target //:hello up-to-date:
  bazel-bin/hello_classes
INFO: 2 processes: 1 internal, 1 worker.
```

For `javac`, pass `["javac", "--classpath-cache", args]` to reuse parsed classpath JARs between requests. A `kotlinc`
rule takes the same form, without `--classpath-cache`.

## Keep `kt_jvm_*` targets

`register_elide_kotlin_toolchain` from `@rules_elide//elide/kotlin:toolchain.bzl` replaces the builder of a
`rules_kotlin` toolchain, so existing `kt_jvm_library`, `kt_jvm_binary` and `kt_jvm_test` targets compile with Elide
without BUILD changes. Targets with annotation processors fall back to the stock `rules_kotlin` builder. Setup:
[KotlinBuilder shim](https://github.com/elide-dev/rules_elide/blob/main/docs/kotlin_builder.md).

## OpenRewrite and dependency queries

For projects with an `elide.pkl`, see [OpenRewrite](https://elide.help/docs/toolchain/jvm/rewrite) and
[Dependency code index](https://elide.help/docs/toolchain/jvm/code-index). These commands do not consume Bazel's `JavaInfo` or its target
graph, and the rules listed above do not add a rewrite or code-index target. See
[the project setup boundary](https://elide.help/docs/build-tools#openrewrite-and-dependency-queries) before using them alongside Bazel.

## Limits

- Windows is not supported.
- `elide.install` accepts only versions listed in the module; use `elide.use` for others.
- Kotlin compiler plugins from external JARs (the `plugins` attribute of `elide_kotlin_*` rules) other than all-open,
  no-arg, sam-with-receiver, assignment and Lombok fail with a compiler error.
