Write Your First Sourcegen (Kotlin)
This page walks through the Kotlin flow for adding a source
generator to your build — a small program that writes source
files compile then sees. For what a sourcegen script is, why
bleep makes it a first-class concept, and how it differs from a
bleep script, see
Source generation.
Prerequisites
- A working bleep project (see Your First Project)
- Kotlin and a JVM version that matches
template-commonbelow
Step 1: The build
Add a scripts project to host the generator and point myapp at
it via sourcegen:. The scripts project depends on bleepscript,
the same dep you'd add for a regular bleep script:
$schema: https://raw.githubusercontent.com/oyvindberg/bleep/master/schema.json
$version: 1.0.0-M9
jvm:
name: graalvm-community:25.0.1
projects:
myapp:
kotlin:
jvmTarget: "25"
version: 2.3.0
platform:
name: jvm
mainClass: com.example.MainKt
sourcegen:
project: scripts
main: scripts.GenConstants
scripts:
dependencies:
- build.bleep:bleepscript:${BLEEP_VERSION}
kotlin:
jvmTarget: "25"
version: 2.3.0
platform:
name: jvm
Key points:
sourcegen:onmyappnames the project that holds the generator and the fully qualified main class. Bleep will run the generator beforemyappcompiles, and rerun it whenever the script project or its dependencies change.${BLEEP_VERSION}keeps the script'sbleepscriptdep in lockstep with whatever bleep is running you.- A project can list more than one sourcegen script — each gets its own isolated output directory.
Step 2: Write the generator
Extend bleepscript.BleepCodegenScript and override run. The
framework hands you a List<CodegenTarget> — one entry per
project (or cross-id) that consumes this generator. Write source
files under target.sources():
package scripts
import bleepscript.BleepCodegenScript
import bleepscript.CodegenTarget
import bleepscript.Commands
import bleepscript.Started
import java.nio.file.Files
class GenConstants : BleepCodegenScript("GenConstants") {
override fun run(started: Started, commands: Commands, targets: List<CodegenTarget>, args: List<String>) {
for (target in targets) {
val file = target.sources().resolve("generated/Constants.kt")
Files.createDirectories(file.parent)
Files.writeString(file,
"package generated\n\n" +
"object Constants {\n" +
" const val ANSWER: Int = 42\n" +
"}\n"
)
}
}
}
BleepCodegenScript provides main for you. The output goes to a
temp directory the framework supplies; only on a successful return
does bleep sync the temp tree to the real generated-sources
directory. A failed run never leaves stale code behind.
Step 3: The consumer
myapp imports Constants like any other Kotlin object — the
generated package is on the consumer's source path automatically:
package com.example
import generated.Constants
fun main() {
println("answer: ${Constants.ANSWER}")
}
Step 4: Run it
bleep run myapp
answer: 42
bleep compile triggers the generator, then compiles myapp against
the generated Constants declaration, then runs it. Subsequent
invocations skip the generator (its inputs haven't changed) until you
edit the script project.
Where to go from here
- Source generation (concept) —
the
BleepCodegenScriptAPI, cross-build targets, the temp-directory cleanup model, and how invalidation works. - Bleep scripts (concept) — the after-compile half: scripts that act on artifacts.
- Run sourcegen explicitly —
bleep sourcegen --watch myappre-runs generators when their inputs change.