11import com.powersync.compile.ClangCompile
22import com.powersync.compile.UnzipSqlite
33import de.undercouch.gradle.tasks.download.Download
4+ import kotlin.io.path.Path
45import org.gradle.kotlin.dsl.register
56import org.jetbrains.kotlin.konan.target.KonanTarget
67import com.powersync.compile.CreateStaticLibrary
8+ import com.powersync.compile.JniLibraryCompile
9+ import com.powersync.compile.JniTarget
10+ import kotlin.io.path.absolutePathString
711
812plugins {
913 alias(libs.plugins.downloadPlugin)
@@ -14,6 +18,13 @@ val sqlite3BaseVersion = "3.51.1"
1418val sqlite3ReleaseYear = " 2025"
1519val sqlite3ExpandedVersion = " 3510100"
1620
21+ data class CompiledAsset (
22+ val output : Provider <RegularFileProperty >,
23+ val fullName : String ,
24+ )
25+
26+ val xCodeInstallation = ClangCompile .resolveXcode(providers)
27+
1728val downloadSQLiteSources by tasks.registering(Download ::class ) {
1829 val zipFileName = " sqlite-amalgamation-$sqlite3ExpandedVersion .zip"
1930 src(" https://www.sqlite.org/$sqlite3ReleaseYear /$zipFileName " )
@@ -51,6 +62,44 @@ val unzipSqlite3MultipleCipherSources by tasks.registering(UnzipSqlite::class) {
5162 )
5263}
5364
65+ fun compileJni (target : JniTarget ): CompiledAsset {
66+ val name = target.filename(" sqlite3mc_jni" )
67+
68+ val task = tasks.register<JniLibraryCompile >(" compile${target.name} " ) {
69+ this .target.set(target)
70+ inputFiles.from(
71+ " jni/sqlite_bindings.cpp" ,
72+ unzipSqlite3MultipleCipherSources.flatMap { it.destination.file(" sqlite3mc_amalgamation.c" ) }
73+ )
74+ include.set(unzipSqlite3MultipleCipherSources.flatMap { it.destination })
75+ sharedLibrary.set(layout.buildDirectory.file(" jni/$name " ))
76+
77+ when (target) {
78+ JniTarget .LINUX_X64 , JniTarget .LINUX_ARM -> {}
79+ JniTarget .WINDOWS_X64 , JniTarget .WINDOWS_ARM -> {
80+ // For Windows, we compile with LLVM MinGW: https://github.com/mstorsjo/llvm-mingw
81+ val path = providers.gradleProperty(" llvmMingw" )
82+ val clang = path.orNull?.let {
83+ Path (path.get()).resolve(" bin/clang" ).toString()
84+ } ? : " clang"
85+ clangPath.set(clang)
86+ }
87+ JniTarget .MACOS_X64 , JniTarget .MACOS_ARM -> {
88+ // on macOS: Compile with xcode tools
89+ toolchain.set(xCodeInstallation.map {
90+ val xcode = Path (it)
91+ xcode.resolve(" Toolchains/XcodeDefault.xctoolchain/usr/bin" ).absolutePathString()
92+ })
93+ }
94+ }
95+ }
96+
97+ return CompiledAsset (
98+ output = task.map { it.sharedLibrary },
99+ fullName = name
100+ )
101+ }
102+
54103fun compileSqliteForKotlinNativeOnApple (library : String , abi : String ): TaskProvider <CreateStaticLibrary > {
55104 val name = " $library$abi "
56105 val outputDir = layout.buildDirectory.dir(" c/$abi " )
@@ -66,7 +115,7 @@ fun compileSqliteForKotlinNativeOnApple(library: String, abi: String): TaskProvi
66115 }
67116
68117 inputs.dir(sourceTask.map { it.destination })
69- include.set(unzipSQLiteSources .flatMap { it.destination })
118+ include.set(sourceTask .flatMap { it.destination })
70119 inputFile.set(sourceTask.flatMap { it.destination.file(filename) })
71120
72121 konanTarget.set(abi)
@@ -82,12 +131,7 @@ fun compileSqliteForKotlinNativeOnApple(library: String, abi: String): TaskProvi
82131 return createStaticLibrary
83132}
84133
85- data class CompiledAsset (
86- val output : Provider <RegularFileProperty >,
87- val fullName : String ,
88- )
89-
90- val compileTasks = buildList {
134+ val kotlinNativeCompileTasks = buildList {
91135 val targets = KonanTarget .predefinedTargets.values.filter { it.family.isAppleFamily }.map { it.name }.toList()
92136 for (library in listOf (" sqlite3" , " sqlite3mc" )) {
93137 for (abi in targets) {
@@ -101,27 +145,48 @@ val compileTasks = buildList {
101145}
102146
103147val compileNative by tasks.registering(Copy ::class ) {
104- into(project.layout.buildDirectory.dir(" output" ))
148+ into(project.layout.buildDirectory.dir(" output/static" ))
149+
150+ for (task in kotlinNativeCompileTasks) {
151+ from(task.output) {
152+ rename { task.fullName }
153+ }
154+ }
155+ }
105156
106- for (task in compileTasks) {
157+ val jniCompileTasks: List <CompiledAsset > = JniTarget .entries.map(::compileJni)
158+ val compileJni by tasks.registering(Copy ::class ) {
159+ into(project.layout.buildDirectory.dir(" output/jni" ))
160+
161+ for (task in jniCompileTasks) {
107162 from(task.output) {
108163 rename { task.fullName }
109164 }
110165 }
111166}
112167
168+ val compileAll by tasks.registering {
169+ dependsOn(jniCompileTasks)
170+ dependsOn(compileJni)
171+ }
172+
113173val hasPrebuiltAssets = providers.gradleProperty(" hasPrebuiltAssets" ).map { it.toBooleanStrict() }
114174
115175val nativeSqliteConfiguration by configurations.creating {
116176 isCanBeResolved = false
117177}
178+ val jniSqlite3McConfiguration by configurations.creating {
179+ isCanBeResolved = false
180+ }
118181
119182artifacts {
120183 if (hasPrebuiltAssets.getOrElse(false )) {
121184 // In CI builds, we set hasPrebuiltAssets=true. In that case, contents of build/output have been downloaded from
122185 // cache and don't need to be rebuilt.
123- add(nativeSqliteConfiguration.name, layout.buildDirectory.dir(" output" ))
186+ add(nativeSqliteConfiguration.name, layout.buildDirectory.dir(" output/native" ))
187+ add(jniSqlite3McConfiguration.name, layout.buildDirectory.dir(" output/jni" ))
124188 } else {
125189 add(nativeSqliteConfiguration.name, compileNative)
190+ add(jniSqlite3McConfiguration.name, compileJni)
126191 }
127192}
0 commit comments