# JAR Assembly

> Build JARs, sources and Javadoc JARs, and runnable application distributions.

## Common operations

`jar` options go after `--`:

```bash
elide jar -- --create --file app.jar -C out .                              # create
elide jar -- --list --file app.jar                                         # list
elide jar -- --extract --file app.jar --dir extracted                      # extract
elide jar -- --create --file app.jar --main-class com.example.Main -C out . # executable JAR
elide jar -- -help
```

## Compile and create a JAR

```bash
elide javac --jar target/app.jar -- src/Main.java src/Util.java
elide javac --jar target/app.jar --manifest src/MANIFEST.MF -- src/Main.java
```

## Project artifacts

```pkl
amends "elide:project.pkl"
import "elide:Jvm.pkl" as Jvm

artifacts {
  ["app"] = new Jvm.Jar {
    name = "app"
    options {
      entrypoint = "com.example.Main"
    }
  }
}
```

`elide build` writes `.dev/artifacts/jar/<name>/`. The JAR holds every non-test source set's classes and resources.

### `Jvm.Jar`

| Property | Meaning | Default |
| --- | --- | --- |
| `name` | File name; `"app"` and `"app.jar"` both give `app.jar`. | the artifact key |
| `sources` | Source sets to package; empty means every non-test set. | none |
| `resources` | Extra files: paths or `new { from = …; into = … }`. | none |
| `manifest` | Extra `META-INF/MANIFEST.MF` attributes. | none |
| `manifestFile` | Manifest file to use instead of a generated one. | — |
| `excludes` | Entries to omit: a pattern with `/ * ? [ ]` is a path glob; a dotted name is a package prefix. | none |
| `options.entrypoint` | `Main-Class`. | `jvm.main` |
| `options.compress` | Compress entries. | `true` |
| `options.defaultManifestProperties` | Add `Implementation-*` attributes. | `true` |
| `main` | Not read when packaging; use `options.entrypoint`. | — |
| `dependsOn` | Artifacts to build first. | none |

```pkl
artifacts {
  ["app"] = new Jvm.Jar {
    sources { "main" }
    excludes {
      "com.example.internal"   // a package and its subpackages
      "**/*.proto"             // a path glob
    }
    manifest {
      ["Implementation-Vendor"] = "Example"
    }
    resources {
      "LICENSE.txt"
      new { from = "config"; into = "META-INF/config" }
    }
  }
}
```

### Sources and Javadoc JARs

```pkl
artifacts {
  ["sources"] = new Jvm.SourceJar {
    classifier = "sources"
    excludes { "**/internal/**" }
  }
  ["javadoc"] = new Jvm.JavadocJar {
    windowTitle = "Example API"
    links { "https://docs.oracle.com/en/java/javase/25/docs/api/" }
    groups {
      ["Core"] { "com.example.core" }
    }
  }
}
```

| `Jvm.SourceJar` | Meaning |
| --- | --- |
| `sources` | Source sets to package; empty means every non-test set. |
| `classifier` | Inserted before the extension (`app-sources.jar`). |
| `includes`, `excludes` | Path globs over the sources. |

| `Jvm.JavadocJar` | Meaning |
| --- | --- |
| `sources` | Source sets to document; empty means every non-test set. |
| `groups` | Package groups: title to package list. |
| `links` | External documentation URLs. |
| `excludes` | Patterns to leave undocumented. |
| `windowTitle`, `docTitle` | Window and document titles. |

## Runnable application distributions

A `Jvm.JvmApplication` is a runnable tree, like Gradle's `application` plugin: runtime JARs in `lib/`, start scripts
in `bin/`, and optional archives.

```pkl
artifacts {
  ["dist"] = new Jvm.JvmApplication {
    from { "app" }
    entrypoint = "com.example.Main"
    defaultJvmArgs { "-Xmx512m" }
    contents {
      new { from = "config"; into = "etc" }
    }
    options {
      archives { "zip"; "tar" }
    }
  }
}
```

| Property | Meaning | Default |
| --- | --- | --- |
| `from` | JAR artifacts with the app's code; empty means every declared JAR, or a JAR of the project's classes. | none |
| `name` | Directory and start-script name. | the artifact key |
| `entrypoint` | Main class. | `jvm.main` |
| `defaultJvmArgs` | JVM options in the scripts, after `jvm.flags`. | none |
| `executableDir` | Directory for the scripts. | `"bin"` |
| `contents` | Extra files in the root, in the same form as source-set resources. | none |
| `options.unixStartScript`, `options.windowsStartScript` | Generate each script. | `true` |
| `options.archives` | `"zip"` and/or `"tar"` (gzip). | none |
| `dependsOn` | Artifacts to build first. | none |

| Output | Path |
| --- | --- |
| Install tree | `.dev/artifacts/install/<name>/` |
| Archives | `.dev/artifacts/distributions/` |

- `elide run` launches the installed tree with the scripts' JVM options.
- Scripts also read `JAVA_OPTS` and `<NAME>_OPTS` (`sample-app` → `SAMPLE_APP_OPTS`).
- The POSIX script follows symlinks to itself; on Windows, run the script directly or via `PATH`.
- `name`, `version` (when archiving) and each `into` must be valid file names everywhere: no `/`, `\`, `:*?"<>|`,
  control characters, trailing dot or space, or Windows device names such as `NUL`. Otherwise the build fails
  before writing.

Workspace members use a sibling's `Jvm.Jar` with `project("core")`; see
[Workspaces](https://elide.help/docs/elide-pkl-reference#workspaces).
