Skip to content

Commit 4aee79d

Browse files
committed
Some build docs
1 parent dea89c0 commit 4aee79d

File tree

2 files changed

+184
-4
lines changed

2 files changed

+184
-4
lines changed

static-sqlite-driver/README.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1 @@
1-
This builds [SQLiter](https://github.com/touchlab/SQLiter) and the [SQlDelight native driver](https://github.com/sqldelight/sqldelight/tree/master/drivers/native-driver)
2-
as an independent project.
3-
4-
We use unchanged source code, but change the buil logic to link SQLite statically.
1+
This project builds a `.klib` linking sqlite3 statically, without containing other Kotlin sources.
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
import java.io.File
2+
import com.powersync.plugins.sonatype.setupGithubRepository
3+
import de.undercouch.gradle.tasks.download.Download
4+
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
5+
import org.jetbrains.kotlin.gradle.utils.NativeCompilerDownloader
6+
import org.jetbrains.kotlin.konan.target.HostManager
7+
import org.jetbrains.kotlin.konan.target.PlatformManager
8+
9+
plugins {
10+
alias(libs.plugins.kotlinMultiplatform)
11+
alias(libs.plugins.downloadPlugin)
12+
id("com.powersync.plugins.sonatype")
13+
}
14+
15+
val sqliteVersion = "3450200"
16+
val sqliteReleaseYear = "2024"
17+
18+
setupGithubRepository()
19+
20+
val downloads = layout.buildDirectory.dir("downloads")
21+
val sqliteSrcFolder = downloads.map { it.dir("sqlite3") }
22+
23+
val downloadSQLiteSources by tasks.registering(Download::class) {
24+
val zipFileName = "sqlite-amalgamation-$sqliteVersion.zip"
25+
src("https://www.sqlite.org/$sqliteReleaseYear/$zipFileName")
26+
dest(downloads.map { it.file(zipFileName) })
27+
onlyIfNewer(true)
28+
overwrite(false)
29+
}
30+
31+
val unzipSQLiteSources by tasks.registering(Copy::class) {
32+
dependsOn(downloadSQLiteSources)
33+
34+
from(
35+
zipTree(downloadSQLiteSources.get().dest).matching {
36+
include("*/sqlite3.*")
37+
exclude {
38+
it.isDirectory
39+
}
40+
eachFile {
41+
this.path = this.name
42+
}
43+
},
44+
)
45+
into(sqliteSrcFolder)
46+
}
47+
48+
// Obtain host and platform manager from Kotlin multiplatform plugin. They're supposed to be
49+
// internal, but it's very convenient to have them because they expose the necessary toolchains we
50+
// use to compile SQLite for the platforms we need.
51+
val hostManager = HostManager()
52+
val platformManager: PlatformManager get() {
53+
val distribution = org.jetbrains.kotlin.konan.target.Distribution(
54+
konanHome = NativeCompilerDownloader(project).compilerDirectory.absolutePath
55+
)
56+
return PlatformManager(distribution = distribution)
57+
}
58+
59+
fun compileSqlite(target: KotlinNativeTarget): TaskProvider<Task> {
60+
val name = target.targetName
61+
val outputDir = layout.buildDirectory.dir("c/$name")
62+
63+
val compileSqlite = tasks.register("${name}CompileSqlite") {
64+
dependsOn(unzipSQLiteSources)
65+
val targetDirectory = outputDir.get()
66+
val sqliteSource = sqliteSrcFolder.map { it.file("sqlite3.c") }.get()
67+
val output = targetDirectory.file("sqlite3.o")
68+
69+
inputs.file(sqliteSource)
70+
outputs.file(output)
71+
72+
doFirst {
73+
targetDirectory.asFile.mkdirs()
74+
output.asFile.delete()
75+
}
76+
77+
doLast {
78+
val platform = platformManager.platform(target.konanTarget)
79+
80+
providers.exec {
81+
commandLine = platform.clang.clangC(
82+
"--compile",
83+
"-I${sqliteSrcFolder.get().asFile.absolutePath}",
84+
sqliteSource.asFile.absolutePath,
85+
"-DHAVE_GETHOSTUUID=0",
86+
"-DSQLITE_ENABLE_DBSTAT_VTAB",
87+
"-DSQLITE_ENABLE_FTS5",
88+
"-DSQLITE_ENABLE_RTREE",
89+
"-O3",
90+
"-o",
91+
"sqlite3.o",
92+
)
93+
94+
workingDir = targetDirectory.asFile
95+
}.result.get()
96+
}
97+
}
98+
99+
val createStaticLibrary = tasks.register("${name}ArchiveSqlite") {
100+
dependsOn(compileSqlite)
101+
val targetDirectory = outputDir.get()
102+
inputs.file(targetDirectory.file("sqlite3.o"))
103+
outputs.file(targetDirectory.file("libsqlite3.a"))
104+
105+
doLast {
106+
val platform = platformManager.platform(target.konanTarget)
107+
providers.exec {
108+
commandLine = platform.clang.llvmAr(
109+
"rc",
110+
"libsqlite3.a",
111+
"sqlite3.o",
112+
)
113+
114+
workingDir = targetDirectory.asFile
115+
}.result.get()
116+
}
117+
}
118+
119+
val buildCInteropDef = tasks.register("${name}CinteropSqlite") {
120+
dependsOn(createStaticLibrary)
121+
122+
val archive = createStaticLibrary.get().outputs.files.singleFile
123+
inputs.file(archive)
124+
125+
val parent = archive.parentFile
126+
val defFile = File(parent, "sqlite3.def")
127+
outputs.file(defFile)
128+
129+
doFirst {
130+
defFile.writeText(
131+
"""
132+
package = com.powersync.sqlite3
133+
134+
linkerOpts.linux_x64 = -lpthread -ldl
135+
linkerOpts.macos_x64 = -lpthread -ldl
136+
staticLibraries=${archive.name}
137+
libraryPaths=${parent.relativeTo(project.layout.projectDirectory.asFile.canonicalFile)}
138+
""".trimIndent(),
139+
)
140+
}
141+
}
142+
143+
return buildCInteropDef
144+
}
145+
146+
kotlin {
147+
iosX64()
148+
iosArm64()
149+
iosSimulatorArm64()
150+
151+
applyDefaultHierarchyTemplate()
152+
153+
sourceSets {
154+
all {
155+
languageSettings.apply {
156+
optIn("kotlin.experimental.ExperimentalNativeApi")
157+
optIn("kotlinx.cinterop.ExperimentalForeignApi")
158+
optIn("kotlinx.cinterop.BetaInteropApi")
159+
}
160+
}
161+
162+
nativeTest {
163+
dependencies {
164+
implementation(libs.sqliter)
165+
}
166+
}
167+
}
168+
169+
targets.withType<KotlinNativeTarget> {
170+
if (hostManager.isEnabled(konanTarget)) {
171+
val compileSqlite3 = compileSqlite(this)
172+
173+
compilations.named("main") {
174+
cinterops.create("sqlite3") {
175+
val cInteropTask = tasks[interopProcessingTaskName]
176+
cInteropTask.dependsOn(compileSqlite3)
177+
definitionFile = compileSqlite3.get().outputs.files.singleFile
178+
includeDirs(sqliteSrcFolder.get())
179+
}
180+
}
181+
}
182+
}
183+
}

0 commit comments

Comments
 (0)