@@ -169,54 +169,127 @@ val xCodeInstallation = ClangCompile.resolveXcode(providers)
169169// Tasks to build the JNI shared library for multiple operating systems.
170170// Since the JNI sources rarely change, we don't run these tasks on every build. Instead,
171171// we'll publish these sources as one-off releases when needed, and then reference that URL.
172+ enum class JniTarget {
173+ LINUX_ARM ,
174+ LINUX_X64 ,
175+ MACOS_ARM ,
176+ MACOS_X64 ,
177+ WINDOWS_ARM ,
178+ WINDOWS_X64 ,
179+ }
180+
181+ fun Exec.registerCompileOnHostTask (target : JniTarget , clang : String = "clang", toolchain : String? = null) {
182+ val outputDirectory = layout.buildDirectory.dir(" jni-build" )
183+ val outputFile = outputDirectory.map {
184+ it.file(when (target) {
185+ JniTarget .LINUX_ARM -> " libsqlite3mc_jni_aarch64.linux.so"
186+ JniTarget .LINUX_X64 -> " libsqlite3mc_jni_x64.linux.so"
187+ JniTarget .MACOS_ARM -> " libsqlite3mc_jni_aarch64.macos.dylib"
188+ JniTarget .MACOS_X64 -> " libsqlite3mc_jni_x64.macos.dylib"
189+ JniTarget .WINDOWS_ARM -> " sqlite3mc_jni_aarch64.dll"
190+ JniTarget .WINDOWS_X64 -> " sqlite3mc_jni_x64.dll"
191+ })
192+ }
193+ outputs.file(outputFile)
194+
195+ dependsOn(unzipSQLiteSources)
196+ val sqlite3McSources = unzipSQLiteSources.map { it.destinationDir }
197+ inputs.dir(sqlite3McSources)
198+
199+ inputs.dir(layout.projectDirectory.dir(" src/jni/" ))
200+
201+ doFirst {
202+ outputDirectory.get().asFile.mkdirs()
203+ }
204+
205+ if (target == JniTarget .LINUX_X64 || target == JniTarget .LINUX_ARM ) {
206+ executable = " /opt/homebrew/bin/docker"
207+ args(
208+ " run" ,
209+ " -v" , " ./src:/src" ,
210+ " -v" , " ./build:/build" ,
211+ " powersync_kotlin_sqlite3mc_build_helper" ,
212+ " clang" ,
213+ " -fuse-ld=lld"
214+ )
215+ } else {
216+ executable = clang
217+ }
218+
219+ val outputFilePath = outputFile.get().asFile.toRelativeString(project.projectDir)
220+ val sourceRoot = sqlite3McSources.get().toRelativeString(project.projectDir)
221+ val amalgamation = File (sourceRoot, " sqlite3mc_amalgamation.c" ).path
222+
223+ args(
224+ " -shared" ,
225+ " -fPIC" ,
226+ when (target) {
227+ JniTarget .LINUX_ARM -> " --target=aarch64-pc-linux"
228+ JniTarget .LINUX_X64 -> " --target=x86_64-pc-linux"
229+ JniTarget .MACOS_ARM -> " --target=aarch64-apple-macos"
230+ JniTarget .MACOS_X64 -> " --target=x86_64-apple-macos"
231+ JniTarget .WINDOWS_ARM -> " --target=aarch64-w64-mingw32uwp"
232+ JniTarget .WINDOWS_X64 -> " --target=x86_64-w64-mingw32uwp"
233+ },
234+ " -o" ,
235+ outputFilePath,
236+ " src/jni/sqlite_bindings.cpp" ,
237+ amalgamation,
238+ " -I" ,
239+ sourceRoot,
240+ " -I" ,
241+ " src/jni/headers/common" ,
242+ " -I" ,
243+ when (target) {
244+ JniTarget .LINUX_X64 , JniTarget .LINUX_ARM -> " src/jni/headers/inc_linux"
245+ JniTarget .MACOS_X64 , JniTarget .MACOS_ARM -> " src/jni/headers/inc_mac"
246+ JniTarget .WINDOWS_X64 , JniTarget .WINDOWS_ARM -> " src/jni/headers/inc_win"
247+ },
248+ " -O3" ,
249+ * ClangCompile .sqlite3ClangOptions,
250+ )
251+
252+ toolchain?.let { args.add(it) }
253+ }
254+
172255fun registerCompileMacOsHostTask (arm : Boolean ): TaskProvider <Exec > {
173- val architectureName = if (arm) { " aarch64 " } else { " x64 " }
256+ val architecture = if (arm) JniTarget . MACOS_ARM else JniTarget . MACOS_X64
174257
175- return tasks.register<Exec >(" jniCompileMacos $architectureName " ) {
258+ return tasks.register<Exec >(" jniCompile ${architecture.name} " ) {
176259 val xcode = Path (xCodeInstallation.get())
177260 val toolchain =
178261 xcode.resolve(" Toolchains/XcodeDefault.xctoolchain/usr/bin" ).absolutePathString()
262+ registerCompileOnHostTask(architecture, toolchain = toolchain)
263+ }
264+ }
179265
180- val outputDirectory = layout.buildDirectory.dir(" jni-build" )
181- val outputFile = outputDirectory.map {
182- it.file(" libsqlite3mc_jni_$architectureName .macos.dylib" )
183- }
184- outputs.file(outputFile)
185-
186- dependsOn(unzipSQLiteSources)
187- val sqlite3McSources = unzipSQLiteSources.map { it.destinationDir }
188- inputs.dir(sqlite3McSources)
266+ fun registerCompileWindowsOnMacOsTask (arm : Boolean ): TaskProvider <Exec > {
267+ val architecture = if (arm) JniTarget .WINDOWS_ARM else JniTarget .WINDOWS_X64
189268
190- inputs.dir(layout.projectDirectory.dir(" src/jni/" ))
269+ return tasks.register<Exec >(" jniCompile${architecture.name} " ) {
270+ registerCompileOnHostTask(architecture, clang = " /Users/simon/Downloads/llvm-mingw-20251104-ucrt-macos-universal/bin/clang" )
271+ }
272+ }
191273
192- doFirst {
193- outputDirectory.get().asFile.mkdirs()
194- }
274+ fun registerCompileLinuxOnMacOsTask (arm : Boolean ): TaskProvider <Exec > {
275+ val architecture = if (arm) JniTarget .LINUX_ARM else JniTarget .LINUX_X64
195276
196- executable = " clang"
197- args(
198- " -B$toolchain " ,
199- " -dynamiclib" ,
200- " -fPIC" ,
201- if (arm) " --target=aarch64-apple-macos" else " --target=x86_64-apple-macos" ,
202- " -o" ,
203- outputFile.get().asFile.path,
204- " src/jni/sqlite_bindings.cpp" ,
205- File (sqlite3McSources.get(), " sqlite3mc_amalgamation.c" ).path,
206- " -I" ,
207- sqlite3McSources.get().path,
208- " -I" ,
209- " src/jni/headers/inc_mac" ,
210- " -O3" ,
211- * ClangCompile .sqlite3ClangOptions,
212- )
277+ return tasks.register<Exec >(" jniCompile${architecture.name} " ) {
278+ registerCompileOnHostTask(architecture)
213279 }
214280}
215281
282+ val linuxArm64 = registerCompileLinuxOnMacOsTask(true )
283+ val linuxX64 = registerCompileLinuxOnMacOsTask(false )
284+
216285val macosArm64 = registerCompileMacOsHostTask(true )
217286val macosX64 = registerCompileMacOsHostTask(false )
218287
288+ val windowsArm64 = registerCompileWindowsOnMacOsTask(true )
289+ val windowsX64 = registerCompileWindowsOnMacOsTask(false )
290+
219291tasks.register(" jniCompile" ) {
220- dependsOn(macosArm64)
221- dependsOn(macosX64)
292+ dependsOn(linuxX64, linuxArm64)
293+ dependsOn(macosX64, macosArm64)
294+ dependsOn(windowsX64, macosArm64)
222295}
0 commit comments