Skip to content

Commit b4323d4

Browse files
committed
First attempt for cross-compilation in CI
1 parent a88552e commit b4323d4

File tree

12 files changed

+238
-206
lines changed

12 files changed

+238
-206
lines changed

.github/workflows/prebuild_assets.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,18 @@ jobs:
5050
- name: Set up XCode
5151
if: steps.cache_prebuild.outputs.cache-hit != 'true'
5252
uses: maxim-lobanov/setup-xcode@v1
53+
- name: Setup Linux build docker image
54+
run: docker build -t powersync_kotlin_sqlite3mc_build_helper --load jni
55+
- name: Download llvm-mingw
56+
run: |
57+
curl -L https://github.com/mstorsjo/llvm-mingw/releases/download/20251118/llvm-mingw-20251118-ucrt-macos-universal.tar.xz -o llvm-ming.tar.xz
58+
tar --extract --gzip --file llvm-ming.tar.xz
59+
rm llvm-ming.tar.xz
60+
5361
- name: Compile SQLite with Gradle
5462
if: steps.cache_prebuild.outputs.cache-hit != 'true'
5563
run: |
56-
./gradlew --scan internal:prebuild-binaries:compileNative
64+
./gradlew --scan -PllvmMingw=$(pwd)/llvm-mingw-20251118-ucrt-macos-universal internal:prebuild-binaries:compileNative
5765
shell: bash
5866
- uses: actions/upload-artifact@v5
5967
id: upload

internal/prebuild-binaries/build.gradle.kts

Lines changed: 75 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
import com.powersync.compile.ClangCompile
22
import com.powersync.compile.UnzipSqlite
33
import de.undercouch.gradle.tasks.download.Download
4+
import kotlin.io.path.Path
45
import org.gradle.kotlin.dsl.register
56
import org.jetbrains.kotlin.konan.target.KonanTarget
67
import com.powersync.compile.CreateStaticLibrary
8+
import com.powersync.compile.JniLibraryCompile
9+
import com.powersync.compile.JniTarget
10+
import kotlin.io.path.absolutePathString
711

812
plugins {
913
alias(libs.plugins.downloadPlugin)
@@ -14,6 +18,13 @@ val sqlite3BaseVersion = "3.51.1"
1418
val sqlite3ReleaseYear = "2025"
1519
val 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+
1728
val 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+
54103
fun 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

103147
val 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+
113173
val hasPrebuiltAssets = providers.gradleProperty("hasPrebuiltAssets").map { it.toBooleanStrict() }
114174

115175
val nativeSqliteConfiguration by configurations.creating {
116176
isCanBeResolved = false
117177
}
178+
val jniSqlite3McConfiguration by configurations.creating {
179+
isCanBeResolved = false
180+
}
118181

119182
artifacts {
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
}

plugins/build-plugin/src/main/kotlin/com/powersync/compile/ClangCompile.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ abstract class ClangCompile : DefaultTask() {
132132
.exec {
133133
executable("xcode-select")
134134
args("-p")
135-
}.standardOutput.asText
135+
}.standardOutput.asText.map { it.trim() }
136136
}
137137
}
138138
}

0 commit comments

Comments
 (0)