|
1 | | -import app.cash.sqldelight.core.capitalize |
| 1 | +import com.android.build.gradle.internal.tasks.factory.dependsOn |
2 | 2 | import com.powersync.plugins.sonatype.setupGithubRepository |
3 | 3 | import de.undercouch.gradle.tasks.download.Download |
4 | 4 | import org.gradle.internal.os.OperatingSystem |
5 | 5 | import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi |
6 | 6 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget |
7 | 7 | import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget |
| 8 | +import org.jetbrains.kotlin.gradle.plugin.mpp.TestExecutable |
8 | 9 | import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmTest |
9 | | -import java.util.* |
| 10 | +import org.jetbrains.kotlin.konan.target.Family |
10 | 11 |
|
11 | 12 | plugins { |
12 | 13 | alias(libs.plugins.kotlinMultiplatform) |
@@ -76,6 +77,56 @@ val buildCInteropDef by tasks.registering { |
76 | 77 | outputs.files(defFile) |
77 | 78 | } |
78 | 79 |
|
| 80 | +val binariesFolder = project.layout.buildDirectory.dir("binaries/desktop") |
| 81 | +val downloadPowersyncDesktopBinaries by tasks.registering(Download::class) { |
| 82 | + val coreVersion = libs.versions.powersync.core.get() |
| 83 | + val linux_aarch64 = "https://github.com/powersync-ja/powersync-sqlite-core/releases/download/v$coreVersion/libpowersync_aarch64.so" |
| 84 | + val linux_x64 = "https://github.com/powersync-ja/powersync-sqlite-core/releases/download/v$coreVersion/libpowersync_x64.so" |
| 85 | + val macos_aarch64 = "https://github.com/powersync-ja/powersync-sqlite-core/releases/download/v$coreVersion/libpowersync_aarch64.dylib" |
| 86 | + val macos_x64 = "https://github.com/powersync-ja/powersync-sqlite-core/releases/download/v$coreVersion/libpowersync_x64.dylib" |
| 87 | + val windows_x64 = "https://github.com/powersync-ja/powersync-sqlite-core/releases/download/v$coreVersion/powersync_x64.dll" |
| 88 | + |
| 89 | + if (binariesAreProvided) { |
| 90 | + src(listOf(linux_aarch64, linux_x64, macos_aarch64, macos_x64, windows_x64)) |
| 91 | + } else { |
| 92 | + val (aarch64, x64) = when { |
| 93 | + os.isLinux -> linux_aarch64 to linux_x64 |
| 94 | + os.isMacOsX -> macos_aarch64 to macos_x64 |
| 95 | + os.isWindows -> null to windows_x64 |
| 96 | + else -> error("Unknown operating system: $os") |
| 97 | + } |
| 98 | + val arch = System.getProperty("os.arch") |
| 99 | + src(when { |
| 100 | + crossArch -> listOfNotNull(aarch64, x64) |
| 101 | + arch == "aarch64" -> listOfNotNull(aarch64) |
| 102 | + arch == "amd64" || arch == "x86_64" -> listOfNotNull(x64) |
| 103 | + else -> error("Unsupported architecture: $arch") |
| 104 | + }) |
| 105 | + } |
| 106 | + dest(binariesFolder.map { it.dir("powersync") }) |
| 107 | + onlyIfModified(true) |
| 108 | +} |
| 109 | + |
| 110 | +val downloadPowersyncFramework by tasks.registering(Download::class) { |
| 111 | + val coreVersion = libs.versions.powersync.core.get() |
| 112 | + val framework = "https://github.com/powersync-ja/powersync-sqlite-core/releases/download/v$coreVersion/powersync-sqlite-core.xcframework.zip" |
| 113 | + |
| 114 | + src(framework) |
| 115 | + dest(binariesFolder.map { it.file("framework/powersync-sqlite-core.xcframework.zip") }) |
| 116 | + onlyIfModified(true) |
| 117 | +} |
| 118 | + |
| 119 | +val unzipPowersyncFramework by tasks.registering(Copy::class) { |
| 120 | + dependsOn(downloadPowersyncFramework) |
| 121 | + |
| 122 | + from( |
| 123 | + zipTree(downloadPowersyncFramework.get().dest).matching { |
| 124 | + include("powersync-sqlite-core.xcframework/**") |
| 125 | + }, |
| 126 | + ) |
| 127 | + into(binariesFolder.map { it.dir("framework") }) |
| 128 | +} |
| 129 | + |
79 | 130 | kotlin { |
80 | 131 | androidTarget { |
81 | 132 | publishLibraryVariants("release", "debug") |
@@ -114,17 +165,43 @@ kotlin { |
114 | 165 | } |
115 | 166 | cinterops.create("powersync-sqlite-core") |
116 | 167 | } |
| 168 | + |
| 169 | + if (konanTarget.family == Family.IOS && konanTarget.name.contains("simulator")) { |
| 170 | + binaries.withType<TestExecutable>().configureEach { |
| 171 | + linkTaskProvider.dependsOn(unzipPowersyncFramework) |
| 172 | + linkerOpts("-framework", "powersync-sqlite-core") |
| 173 | + val frameworkRoot = binariesFolder.map { it.dir("framework/powersync-sqlite-core.xcframework/ios-arm64_x86_64-simulator") }.get().asFile.path |
| 174 | + |
| 175 | + linkerOpts("-F", frameworkRoot) |
| 176 | + linkerOpts("-rpath", frameworkRoot) |
| 177 | + } |
| 178 | + } |
| 179 | + /* |
| 180 | + If we ever need macOS support: |
| 181 | + { |
| 182 | + binaries.withType<TestExecutable>().configureEach { |
| 183 | + linkTaskProvider.dependsOn(downloadPowersyncDesktopBinaries) |
| 184 | + linkerOpts("-lpowersync") |
| 185 | + linkerOpts("-L", binariesFolder.map { it.dir("powersync") }.get().asFile.path) |
| 186 | + } |
| 187 | + } |
| 188 | + */ |
117 | 189 | } |
118 | 190 |
|
119 | 191 | explicitApi() |
120 | 192 |
|
| 193 | + applyDefaultHierarchyTemplate() |
121 | 194 | sourceSets { |
122 | 195 | all { |
123 | 196 | languageSettings { |
124 | 197 | optIn("kotlinx.cinterop.ExperimentalForeignApi") |
125 | 198 | } |
126 | 199 | } |
127 | 200 |
|
| 201 | + val commonIntegrationTest by creating { |
| 202 | + dependsOn(commonTest.get()) |
| 203 | + } |
| 204 | + |
128 | 205 | commonMain.dependencies { |
129 | 206 | implementation(libs.uuid) |
130 | 207 | implementation(libs.kotlin.stdlib) |
@@ -156,8 +233,16 @@ kotlin { |
156 | 233 | commonTest.dependencies { |
157 | 234 | implementation(libs.kotlin.test) |
158 | 235 | implementation(libs.test.coroutines) |
| 236 | + implementation(libs.test.turbine) |
159 | 237 | implementation(libs.kermit.test) |
160 | 238 | } |
| 239 | + |
| 240 | + // We're putting the native libraries into our JAR, so integration tests for the JVM can run as part of the unit |
| 241 | + // tests. |
| 242 | + jvmTest.get().dependsOn(commonIntegrationTest) |
| 243 | + |
| 244 | + // We're linking the xcframework for the simulator tests, so they can use integration tests too |
| 245 | + iosSimulatorArm64Test.orNull?.dependsOn(commonIntegrationTest) |
161 | 246 | } |
162 | 247 | } |
163 | 248 |
|
@@ -212,146 +297,13 @@ android { |
212 | 297 | val os = OperatingSystem.current() |
213 | 298 | val binariesAreProvided = project.findProperty("powersync.binaries.provided") == "true" |
214 | 299 | val crossArch = project.findProperty("powersync.binaries.cross-arch") == "true" |
215 | | -val binariesFolder = project.layout.buildDirectory.dir("binaries/desktop") |
216 | 300 |
|
217 | 301 | if (binariesAreProvided && crossArch) { |
218 | 302 | error("powersync.binaries.provided and powersync.binaries.cross-arch must not be both defined.") |
219 | 303 | } |
220 | 304 |
|
221 | | -val getBinaries = if (binariesAreProvided) { |
222 | | - // Binaries for all OS must be provided (manually or by the CI) in binaries/desktop |
223 | | - |
224 | | - val verifyPowersyncBinaries = tasks.register("verifyPowersyncBinaries") { |
225 | | - val directory = projectDir.resolve("binaries/desktop") |
226 | | - val binaries = listOf( |
227 | | - directory.resolve("libpowersync-sqlite_aarch64.so"), |
228 | | - directory.resolve("libpowersync-sqlite_x64.so"), |
229 | | - directory.resolve("libpowersync-sqlite_aarch64.dylib"), |
230 | | - directory.resolve("libpowersync-sqlite_x64.dylib"), |
231 | | - directory.resolve("powersync-sqlite_x64.dll"), |
232 | | - ) |
233 | | - doLast { |
234 | | - binaries.forEach { |
235 | | - if (!it.exists()) error("File $it does not exist") |
236 | | - if (!it.isFile) error("File $it is not a regular file") |
237 | | - } |
238 | | - } |
239 | | - outputs.files(*binaries.toTypedArray()) |
240 | | - } |
241 | | - verifyPowersyncBinaries |
242 | | -} else { |
243 | | - // Building locally for the current OS |
244 | | - |
245 | | - val localProperties = Properties() |
246 | | - val localPropertiesFile = rootProject.file("local.properties") |
247 | | - if (localPropertiesFile.exists()) { |
248 | | - localPropertiesFile.inputStream().use { localProperties.load(it) } |
249 | | - } |
250 | | - val cmakeExecutable = localProperties.getProperty("cmake.path") ?: "cmake" |
251 | | - |
252 | | - fun registerCMakeTasks( |
253 | | - suffix: String, |
254 | | - vararg defines: String, |
255 | | - ): TaskProvider<Exec> { |
256 | | - val cmakeConfigure = tasks.register<Exec>("cmakeJvmConfigure${suffix.capitalize()}") { |
257 | | - dependsOn(unzipSQLiteSources) |
258 | | - group = "cmake" |
259 | | - workingDir = layout.buildDirectory.dir("cmake/$suffix").get().asFile |
260 | | - inputs.files( |
261 | | - "src/jvmMain/cpp", |
262 | | - "src/jvmNative/cpp", |
263 | | - sqliteSrcFolder, |
264 | | - ) |
265 | | - outputs.dir(workingDir) |
266 | | - executable = cmakeExecutable |
267 | | - args(listOf(file("src/jvmMain/cpp/CMakeLists.txt").absolutePath, "-DSUFFIX=$suffix", "-DCMAKE_BUILD_TYPE=Release") + defines.map { "-D$it" }) |
268 | | - doFirst { |
269 | | - workingDir.mkdirs() |
270 | | - } |
271 | | - } |
272 | | - |
273 | | - val cmakeBuild = tasks.register<Exec>("cmakeJvmBuild${suffix.capitalize()}") { |
274 | | - dependsOn(cmakeConfigure) |
275 | | - group = "cmake" |
276 | | - workingDir = layout.buildDirectory.dir("cmake/$suffix").get().asFile |
277 | | - inputs.files( |
278 | | - "src/jvmMain/cpp", |
279 | | - "src/jvmNative/cpp", |
280 | | - sqliteSrcFolder, |
281 | | - workingDir, |
282 | | - ) |
283 | | - outputs.dir(workingDir.resolve(if (os.isWindows) "output/Release" else "output")) |
284 | | - executable = cmakeExecutable |
285 | | - args("--build", ".", "--config", "Release") |
286 | | - } |
287 | | - |
288 | | - return cmakeBuild |
289 | | - } |
290 | | - |
291 | | - val (aarch64, x64) = when { |
292 | | - os.isMacOsX -> { |
293 | | - val aarch64 = registerCMakeTasks("aarch64", "CMAKE_OSX_ARCHITECTURES=arm64") |
294 | | - val x64 = registerCMakeTasks("x64", "CMAKE_OSX_ARCHITECTURES=x86_64") |
295 | | - aarch64 to x64 |
296 | | - } |
297 | | - os.isLinux -> { |
298 | | - val aarch64 = registerCMakeTasks("aarch64", "CMAKE_C_COMPILER=aarch64-linux-gnu-gcc", "CMAKE_CXX_COMPILER=aarch64-linux-gnu-g++") |
299 | | - val x64 = registerCMakeTasks("x64", "CMAKE_C_COMPILER=x86_64-linux-gnu-gcc", "CMAKE_CXX_COMPILER=x86_64-linux-gnu-g++") |
300 | | - aarch64 to x64 |
301 | | - } |
302 | | - os.isWindows -> { |
303 | | - val x64 = registerCMakeTasks("x64") |
304 | | - null to x64 |
305 | | - } |
306 | | - else -> error("Unknown operating system: $os") |
307 | | - } |
308 | | - |
309 | | - val arch = System.getProperty("os.arch") |
310 | | - val cmakeJvmBuilds = when { |
311 | | - crossArch -> listOfNotNull(aarch64, x64) |
312 | | - arch == "aarch64" -> listOfNotNull(aarch64) |
313 | | - arch == "amd64" || arch == "x86_64" -> listOfNotNull(x64) |
314 | | - else -> error("Unsupported architecture: $arch") |
315 | | - } |
316 | | - |
317 | | - tasks.register<Copy>("cmakeJvmBuild") { |
318 | | - dependsOn(cmakeJvmBuilds) |
319 | | - group = "cmake" |
320 | | - from(cmakeJvmBuilds) |
321 | | - into(binariesFolder.map { it.dir("sqlite") }) |
322 | | - } |
323 | | -} |
324 | | - |
325 | | -val downloadPowersyncDesktopBinaries = tasks.register<Download>("downloadPowersyncDesktopBinaries") { |
326 | | - val coreVersion = libs.versions.powersync.core.get() |
327 | | - val linux_aarch64 = "https://github.com/powersync-ja/powersync-sqlite-core/releases/download/v$coreVersion/libpowersync_aarch64.so" |
328 | | - val linux_x64 = "https://github.com/powersync-ja/powersync-sqlite-core/releases/download/v$coreVersion/libpowersync_x64.so" |
329 | | - val macos_aarch64 = "https://github.com/powersync-ja/powersync-sqlite-core/releases/download/v$coreVersion/libpowersync_aarch64.dylib" |
330 | | - val macos_x64 = "https://github.com/powersync-ja/powersync-sqlite-core/releases/download/v$coreVersion/libpowersync_x64.dylib" |
331 | | - val windows_x64 = "https://github.com/powersync-ja/powersync-sqlite-core/releases/download/v$coreVersion/powersync_x64.dll" |
332 | | - if (binariesAreProvided) { |
333 | | - src(listOf(linux_aarch64, linux_x64, macos_aarch64, macos_x64, windows_x64)) |
334 | | - } else { |
335 | | - val (aarch64, x64) = when { |
336 | | - os.isLinux -> linux_aarch64 to linux_x64 |
337 | | - os.isMacOsX -> macos_aarch64 to macos_x64 |
338 | | - os.isWindows -> null to windows_x64 |
339 | | - else -> error("Unknown operating system: $os") |
340 | | - } |
341 | | - val arch = System.getProperty("os.arch") |
342 | | - src(when { |
343 | | - crossArch -> listOfNotNull(aarch64, x64) |
344 | | - arch == "aarch64" -> listOfNotNull(aarch64) |
345 | | - arch == "amd64" || arch == "x86_64" -> listOfNotNull(x64) |
346 | | - else -> error("Unsupported architecture: $arch") |
347 | | - }) |
348 | | - } |
349 | | - dest(binariesFolder.map { it.dir("powersync") }) |
350 | | - onlyIfModified(true) |
351 | | -} |
352 | | - |
353 | 305 | tasks.named<ProcessResources>(kotlin.jvm().compilations["main"].processResourcesTaskName) { |
354 | | - from(getBinaries, downloadPowersyncDesktopBinaries) |
| 306 | + from(downloadPowersyncDesktopBinaries) |
355 | 307 | } |
356 | 308 |
|
357 | 309 | // We want to build with recent JDKs, but need to make sure we support Java 8. https://jakewharton.com/build-on-latest-java-test-through-lowest-java/ |
|
0 commit comments