From 2aaa7b99a643971163527bf28b4b9d3b5d455c3e Mon Sep 17 00:00:00 2001 From: Kgothatso Ngako Date: Sun, 6 Sep 2026 00:44:10 +0200 Subject: [PATCH] build: phase 0 of the jvm target -- clear the ground, correct the plan First phase of docs/jvm-target.md. Nothing here turns the target on; it removes what would break the moment it is turned on, and stages the two catalog entries that cannot be derived automatically. Two of the four steps as written in the doc turned out to be wrong, and implementing them is how that surfaced -- both are corrected in the doc in this commit. **Deleted the stale jvmMain tree.** Six files under composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/ survived from the Aux project this codebase grew out of. They have gone unnoticed because `jvmMain` is currently an orphan source set -- the accessor creates it, no target compiles it -- so the wrong package, the Room 2 imports (androidx.room, not androidx.room3), and the references to a long-gone AuxDatabase and AuxGlobal have never had to resolve. They would all become compile errors in phase 4. They are not lost: they are the closest thing to a skeleton for five of the six platform actuals phase 4 needs, and main.kt is a reasonable starting shape for the phase 5 desktop entry point. `git show HEAD~1` has them. **Added two catalog entries, not four.** sqlite-bundled-jvm and sqldelight-sqlite-driver. Both earn their place by being unreachable otherwise: sqlite-bundled-jvm has to be named explicitly because variant-aware resolution hands the *android* artifact to anything running on the host, and sqldelight-sqlite-driver is the jvm counterpart to the android-driver and native-driver entries already there. The doc also listed room3-runtime-jvm and sqldelight-jdbc-driver. Neither is right. Once jvm() exists, commonMain's existing androidx-room3-runtime resolves to the -jvm variant on its own, so an explicit entry is redundant and would drift. And the SQLDelight drivers phase 2 needs are for DbFactory, which lives in lightning-kmp-app -- a separate gradle build with its own version catalog, where an entry here is simply not visible. **kspJvm cannot be wired yet, and the build file already said so.** The doc's phase 0 told you to uncomment composeApp/build.gradle.kts:194. It contradicted its own phase 4, which is where jvm() gets turned on. The comment three lines above it states the rule: These configurations only exist when the ios targets are declared, which the kotlin block above does only on a mac. The same holds for kspJvm -- `dependencies { add("kspJvm", ...) }` throws UnknownConfigurationException until a jvm() target creates the configuration. So it moves into phase 4, into the same edit that declares the target. composeApp/build.gradle.kts is deliberately untouched by this commit. **Also documented: gradle does not run in a worktree here at all** until the submodule is checked out, which worktrees do not do automatically. `lightning-kmp-app/` is empty and configuration fails with "Project with path ':library' not found in build ':lightning-kmp-app'". Recorded in the phase 0 verification section along with the caveat that a linked worktree shares .git/modules/ with the main checkout, so both trees end up on one submodule git dir. **Not verified by a build.** For that reason. The deletion is an orphan source set and the additions are unreferenced catalog lines, so neither can change a build's outcome -- but that is an argument, not a green check, and it is the second commit in a row on this branch that has not compiled anything. Phase 4 is the first phase that genuinely cannot be done without a working gradle invocation. Co-Authored-By: Claude Opus 5 --- .../cord/auxiliary/compose/AppVersion.jvm.kt | 8 --- .../ac/cord/auxiliary/compose/Platform.jvm.kt | 7 --- .../auxiliary/compose/PlatformContext.jvm.kt | 3 - .../builder/PlatformDatabaseBuilder.jvm.kt | 20 ------ .../kotlin/ac/cord/auxiliary/compose/main.kt | 20 ------ .../auxiliary/compose/ui/theme/Theme.jvm.kt | 17 ----- docs/jvm-target.md | 63 ++++++++++++++----- gradle/libs.versions.toml | 2 + 8 files changed, 51 insertions(+), 89 deletions(-) delete mode 100644 composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/compose/AppVersion.jvm.kt delete mode 100644 composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/compose/Platform.jvm.kt delete mode 100644 composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/compose/PlatformContext.jvm.kt delete mode 100644 composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/compose/database/builder/PlatformDatabaseBuilder.jvm.kt delete mode 100644 composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/compose/main.kt delete mode 100644 composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/compose/ui/theme/Theme.jvm.kt diff --git a/composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/compose/AppVersion.jvm.kt b/composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/compose/AppVersion.jvm.kt deleted file mode 100644 index 65ea6ee4..00000000 --- a/composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/compose/AppVersion.jvm.kt +++ /dev/null @@ -1,8 +0,0 @@ -package ac.cord.auxiliary.compose - -actual object AppVersion { - actual val versionName: String - get() = "0.0.1" - actual val versionCode: String - get() = "21" -} \ No newline at end of file diff --git a/composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/compose/Platform.jvm.kt b/composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/compose/Platform.jvm.kt deleted file mode 100644 index cbce9a9b..00000000 --- a/composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/compose/Platform.jvm.kt +++ /dev/null @@ -1,7 +0,0 @@ -package ac.cord.auxiliary.compose - -class JVMPlatform: Platform { - override val name: String = "Java ${System.getProperty("java.version")}" -} - -actual fun getPlatform(): Platform = JVMPlatform() \ No newline at end of file diff --git a/composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/compose/PlatformContext.jvm.kt b/composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/compose/PlatformContext.jvm.kt deleted file mode 100644 index b52de0a8..00000000 --- a/composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/compose/PlatformContext.jvm.kt +++ /dev/null @@ -1,3 +0,0 @@ -package ac.cord.auxiliary.compose - -actual class PlatformContext \ No newline at end of file diff --git a/composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/compose/database/builder/PlatformDatabaseBuilder.jvm.kt b/composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/compose/database/builder/PlatformDatabaseBuilder.jvm.kt deleted file mode 100644 index f78769a7..00000000 --- a/composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/compose/database/builder/PlatformDatabaseBuilder.jvm.kt +++ /dev/null @@ -1,20 +0,0 @@ -package ac.cord.auxiliary.compose.database.builder - -import ac.cord.auxiliary.compose.PlatformContext -import ac.auxiliary.compose.database.AuxDatabase -import androidx.room.Room -import androidx.room.RoomDatabase -import java.io.File - -actual object PlatformDatabaseBuilder { - actual fun getDatabaseBuilder(platformContext: PlatformContext): RoomDatabase.Builder { - val dbFile = File(System.getProperty("java.io.tmpdir"), "aux.db") // TODO: Stop using tmpDir on desktop... - return Room.databaseBuilder( - name = dbFile.absolutePath, - ) - } - - actual fun getInMemoryDatabaseBuilder(platform: PlatformContext): RoomDatabase.Builder { - return Room.inMemoryDatabaseBuilder() - } -} \ No newline at end of file diff --git a/composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/compose/main.kt b/composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/compose/main.kt deleted file mode 100644 index 4a4fd9ed..00000000 --- a/composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/compose/main.kt +++ /dev/null @@ -1,20 +0,0 @@ -package ac.cord.auxiliary.compose - -import androidx.compose.ui.window.Window -import androidx.compose.ui.window.application -import androidx.navigation.compose.rememberNavController - -fun main() = application { - Window( - onCloseRequest = ::exitApplication, - title = "Torch", - ) { - val navController = rememberNavController() - AuxApp( - navController = navController, - auxGlobal = AuxGlobal( - platformContext = PlatformContext() - ) - ) - } -} \ No newline at end of file diff --git a/composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/compose/ui/theme/Theme.jvm.kt b/composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/compose/ui/theme/Theme.jvm.kt deleted file mode 100644 index 79e272fe..00000000 --- a/composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/compose/ui/theme/Theme.jvm.kt +++ /dev/null @@ -1,17 +0,0 @@ -package ac.cord.auxiliary.compose.ui.theme - -import androidx.compose.material3.ColorScheme -import androidx.compose.runtime.Composable - -@Composable -actual fun themeColorScheme( - darkTheme: Boolean, - dynamicColor: Boolean, - darkScheme: ColorScheme, - lightScheme: ColorScheme -): ColorScheme { - return when { - darkTheme -> darkScheme - else -> lightScheme - } -} \ No newline at end of file diff --git a/docs/jvm-target.md b/docs/jvm-target.md index 982625bb..fcb19ce7 100644 --- a/docs/jvm-target.md +++ b/docs/jvm-target.md @@ -90,25 +90,56 @@ Nothing here needs a decision; it is the groundwork the later phases assume. 2. **Add the missing catalog entries** to `gradle/libs.versions.toml`: ```toml - androidx-room3-runtime-jvm = { module = "androidx.room3:room3-runtime-jvm", version.ref = "room3" } androidx-sqlite-bundled-jvm = { module = "androidx.sqlite:sqlite-bundled-jvm", version.ref = "sqlite" } - sqldelight-jdbc-driver = { module = "app.cash.sqldelight:jdbc-driver", version.ref = "sqldelight" } - sqldelight-sqlite-driver = { module = "app.cash.sqldelight:sqlite-driver", version.ref = "sqldelight" } + sqldelight-sqlite-driver = { module = "app.cash.sqldelight:sqlite-driver", version.ref = "sqldelight" } ``` -3. **Wire KSP for the JVM target.** Uncomment - [composeApp/build.gradle.kts:194](../composeApp/build.gradle.kts). Without it - there is no generated `MantraDatabase_Impl` or DAO implementation for the - host, and `MantraDatabaseConstructor` has no JVM actual — Room's KSP generates - that one, so it costs nothing once the processor runs. + Only these two, and only because neither can be reached any other way. + `sqlite-bundled-jvm` has to be named explicitly because variant-aware + resolution hands the *android* artifact to anything running on the host — + that is the whole trap described in the appendix. `sqlite-driver` is the jvm + counterpart to the `android-driver` and `native-driver` entries already here. -4. **Leave `jvm()` commented out for now**, in both builds. It goes on at the - start of Phase 4, once there is something for it to resolve against. Turning - it on earlier just means living with a broken build through Phases 1–3. + No `room3-runtime-jvm` entry: once `jvm()` exists, `commonMain`'s existing + `androidx-room3-runtime` resolves to the `-jvm` variant on its own. And the + SQLDelight drivers Phase 2 needs belong in **lightning-kmp-app's own + catalog**, not this one — that is a separate gradle build with a separate + version catalog, and putting them here would not make them visible there. + +3. **Do not wire `kspJvm` yet.** It cannot be done at this point, and the reason + is already written down a few lines above it in the build file: + + > These configurations only exist when the ios targets are declared, which + > the kotlin block above does only on a mac. + + The same rule governs `kspJvm` — `dependencies { add("kspJvm", ...) }` throws + `UnknownConfigurationException` until a `jvm()` target creates that + configuration. So uncommenting [composeApp/build.gradle.kts:194](../composeApp/build.gradle.kts) + belongs in **Phase 4**, in the same edit that turns the target on, not here. + +4. **Leave `jvm()` commented out**, in both builds. It goes on at the start of + Phase 4, once there is something for it to resolve against. Turning it on + earlier just means living with a broken build through Phases 1–3. **Verification:** `./gradlew :composeApp:compileDebugKotlinAndroid` still passes. This phase changes nothing observable; the point is that it changes nothing -observable. +observable — a deleted orphan source set and two unreferenced catalog entries +cannot alter a build. + +**If you are working in a git worktree, no gradle task will run at all** until +the submodule is checked out there. Worktrees do not get submodules +automatically, so `lightning-kmp-app/` is empty and the composite build fails +during configuration: + +``` +Project with path ':library' not found in build ':lightning-kmp-app' +``` + +`git submodule update --init --recursive` fixes it, but note that a linked +worktree shares `.git/modules/` with the main checkout, so both trees end up +sharing one submodule git dir. That is fine while both want the same commit — +check with `git submodule status` in each — and worth being careful about when +they do not. --- @@ -233,7 +264,11 @@ review it attracts. **~1–2 days. Blocked by Phases 1–3.** Now turn on `jvm()` — [composeApp/build.gradle.kts:46](../composeApp/build.gradle.kts) -and `lightning-kmp-app/library/build.gradle.kts:18` — and let the compiler drive. +and `lightning-kmp-app/library/build.gradle.kts:18` — and, in the same edit, +uncomment `kspJvm` at [composeApp/build.gradle.kts:194](../composeApp/build.gradle.kts). +Those two go together: the KSP configuration does not exist until the target +does, which is why Phase 0 deliberately left it alone. Then let the compiler +drive. Mantra declares 16 expects across 8 files. They split cleanly: @@ -246,7 +281,7 @@ update Room 2 → Room 3 (`androidx.room` → `androidx.room3`), and point at `MantraDatabase` instead of `AuxDatabase`. `MantraDatabaseConstructor` needs no hand-written actual; Room's KSP generates it -once Phase 0 wired `kspJvm`. +once `kspJvm` is wired above. For `PlatformDatabaseBuilder.getDatabaseBuilder`, use the real application data directory from Phase 1 — not `java.io.tmpdir`, which is what the old Aux diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e51ecfde..0c5a0d8b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -42,6 +42,7 @@ androidx-activity-compose = { module = "androidx.activity:activity-compose", ver androidx-datastore = { module = "androidx.datastore:datastore", version.ref = "datastorePreferences" } androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastorePreferences" } androidx-sqlite-bundled = { module = "androidx.sqlite:sqlite-bundled", version.ref = "sqlite" } +androidx-sqlite-bundled-jvm = { module = "androidx.sqlite:sqlite-bundled-jvm", version.ref = "sqlite" } androidx-room3-runtime = { module = "androidx.room3:room3-runtime", version.ref = "room3" } androidx-room3-compiler = { module = "androidx.room3:room3-compiler", version.ref = "room3" } androidx-room3-sqlite-wrapper = { module = "androidx.room3:room3-sqlite-wrapper", version.ref = "room3" } @@ -78,6 +79,7 @@ sqldelight-android-driver = { module = "app.cash.sqldelight:android-driver", ver sqldelight-coroutines-extensions = { module = "app.cash.sqldelight:coroutines-extensions", version.ref = "sqldelight" } sqldelight-native-driver = { module = "app.cash.sqldelight:native-driver", version.ref = "sqldelight" } sqldelight-runtime = { module = "app.cash.sqldelight:runtime", version.ref = "sqldelight" } +sqldelight-sqlite-driver = { module = "app.cash.sqldelight:sqlite-driver", version.ref = "sqldelight" } vitorpamplona-quartz = { module = "com.vitorpamplona.quartz:quartz", version.ref = "quartz" } [plugins]