Files
amethyst/quartz/build.gradle.kts
T
Claude 731e32eb61 fix: revert macosArm64 target (blocked by negentropy-kmp), add K/N toolchain to session hook
macosArm64 target cannot be enabled until negentropy-kmp publishes a
macosArm64 artifact — commented out with explanation. Reverted run_all.sh
back to Linux-only for K/Native benchmark.

Added Kotlin/Native toolchain dependencies (GCC sysroot, LLDB, LLVM,
libffi) to session-start.sh so K/N compilation works in Claude Code
remote environments where Gradle's own downloader fails through the
proxy.

https://claude.ai/code/session_01WSNE6QKiYM2ZutQD2UihCW
2026-04-11 00:44:33 +00:00

377 lines
12 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import com.vanniktech.maven.publish.KotlinMultiplatform
import com.vanniktech.maven.publish.SourcesJar
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType.DEBUG
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType.RELEASE
import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeTest
plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.androidKotlinMultiplatformLibrary)
alias(libs.plugins.serialization)
alias(libs.plugins.vanniktech.mavenPublish)
}
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xexpect-actual-classes")
// Remove Kotlin null-check assertions on parameters, return values, and receivers.
// These generate invokestatic Intrinsics.checkNotNullParameter at the entry of every
// function that takes non-null reference types (~4,000+ calls per Schnorr verify).
// Safe for this module: all internal secp256k1 code uses non-null LongArray params
// that are never null. Each check costs ~2-3ns on ART, totaling ~8-12μs per verify.
freeCompilerArgs.add("-Xno-param-assertions")
freeCompilerArgs.add("-Xno-call-assertions")
freeCompilerArgs.add("-Xno-receiver-assertions")
}
jvm {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_21)
}
}
android {
namespace = "com.vitorpamplona.quartz"
compileSdk =
libs.versions.android.compileSdk
.get()
.toInt()
minSdk =
libs.versions.android.minSdk
.get()
.toInt()
compilerOptions {
jvmTarget.set(JvmTarget.JVM_21)
}
optimization {
consumerKeepRules.apply {
publish = true
file("consumer-rules.pro")
}
}
withHostTest {}
withDeviceTest {
instrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
}
// For iOS targets, this is also where you should
// configure native binary output. For more information, see:
// https://kotlinlang.org/docs/multiplatform-build-native-binaries.html#build-xcframeworks
// A step-by-step guide on how to include this library in an XCode
// project can be found here:
// https://developer.android.com/kotlin/multiplatform/migrate
val xcfName = "quartz-kmpKit"
iosArm64 {
binaries.framework {
baseName = xcfName
isStatic = true
binaryOption("bundleId", "com.vitorpamplona.quartz")
}
}
iosSimulatorArm64 {
binaries.framework {
baseName = xcfName
isStatic = true
binaryOption("bundleId", "com.vitorpamplona.quartz")
}
}
linuxX64()
// macosArm64() — blocked until negentropy-kmp publishes a macosArm64 artifact
// This makes sure that the resource file directory is visible for iOS tests.
val rootDir = "${rootProject.rootDir.path}/quartz/src/commonTest/resources"
tasks.withType<Test>().configureEach {
maxHeapSize = "4g"
environment("TEST_RESOURCES_ROOT", rootDir)
}
tasks.withType<KotlinNativeTest>().configureEach {
environment("TEST_RESOURCES_ROOT", rootDir)
// This is necessary to have the variable propagated on iOS
environment("SIMCTL_CHILD_TEST_RESOURCES_ROOT", rootDir)
}
// Enable LLVM optimizations for native test binaries (benchmark accuracy).
// Without -opt, K/N test binaries compile in debug mode (~20× slower).
targets.withType<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget>().configureEach {
compilations["test"].compileTaskProvider.configure {
compilerOptions {
freeCompilerArgs.add("-opt")
}
}
}
// Source set declarations.
// Declaring a target automatically creates a source set with the same name. By default, the
// Kotlin Gradle Plugin creates additional source sets that depend on each other, since it is
// common to share sources between related targets.
// See: https://kotlinlang.org/docs/multiplatform-hierarchy.html
sourceSets {
commonMain {
dependencies {
implementation(libs.kotlin.stdlib)
implementation(libs.kotlinx.coroutines.core)
// For LruCache
implementation(libs.androidx.collection)
// @Immutable and @Stable
implementation(libs.androidx.compose.runtime.annotation)
// Bitcoin secp256k1 bindings
api(libs.secp256k1.kmp.common)
// Kotlin serialization for the times where we need the Json tree and performance is not that important.
implementation(libs.kotlinx.serialization.json)
// immutable collections to avoid recomposition
implementation(libs.kotlinx.collections.immutable)
// SQLite KMP driver for event store
api(libs.androidx.sqlite)
implementation(libs.androidx.sqlite.bundled)
// Negentropy set reconciliation (NIP-77)
api(libs.negentropy.kmp)
}
}
commonTest {
dependencies {
implementation(libs.kotlin.test)
implementation(libs.kotlinx.coroutines.test)
// SQLite bundled driver for tests
api(libs.androidx.sqlite)
implementation(libs.androidx.sqlite.bundled)
}
}
// Must be defined before androidMain and jvmMain
val jvmAndroid =
create("jvmAndroid") {
dependsOn(commonMain.get())
dependencies {
// Performant Parser of JSONs into Events
api(libs.jackson.module.kotlin)
// Websockets API
implementation(libs.okhttp)
implementation(libs.okhttpCoroutines)
// Chess engine for move validation and legal move generation
// NOTE: 1.0.4+ uses Java 21's removeLast() which crashes on Android API < 34
// TODO: Test if 1.0.0 works, or fork library to fix
implementation(libs.kchesslib)
}
}
// Must be defined before androidMain and jvmMain
val jvmAndroidTest =
create("jvmAndroidTest") {
dependsOn(commonTest.get())
dependencies {
implementation(libs.kotlin.test)
implementation(libs.kotlinx.coroutines.test)
}
}
jvmMain {
dependsOn(jvmAndroid)
dependencies {
// Bitcoin secp256k1 bindings
implementation(libs.secp256k1.kmp.jni.jvm)
}
}
jvmTest {
dependsOn(jvmAndroidTest)
dependencies {
// Bitcoin secp256k1 bindings
implementation(libs.secp256k1.kmp.jni.jvm)
// SQLite bundled driver for JVM tests
implementation(libs.androidx.sqlite.bundled.jvm)
}
}
androidMain {
dependsOn(jvmAndroid)
dependencies {
implementation(libs.androidx.core.ktx)
// Bitcoin secp256k1 bindings to Android
api(libs.secp256k1.kmp.jni.android)
}
}
getByName("androidHostTest") {
dependencies {
implementation(libs.kotlin.test)
implementation(libs.kotlinx.coroutines.test)
// Bitcoin secp256k1 bindings
implementation(libs.secp256k1.kmp.jni.jvm)
// SQLite bundled driver for Host tests
implementation(libs.androidx.sqlite.bundled.jvm)
}
}
getByName("androidDeviceTest") {
dependencies {
implementation(libs.androidx.runner)
implementation(libs.androidx.core)
implementation(libs.androidx.junit)
implementation(libs.androidx.espresso.core)
implementation(libs.kotlin.test)
implementation(libs.kotlinx.coroutines.test)
// Bitcoin secp256k1 bindings to Android
api(libs.secp256k1.kmp.jni.android)
}
}
// Must be defined before appleMain, linuxMain, etc.
val nativeMain =
create("nativeMain") {
dependsOn(commonMain.get())
}
val nativeTest =
create("nativeTest") {
dependsOn(commonTest.get())
}
// Must be defined before iosMain and macosMain
val appleMain =
create("appleMain") {
dependsOn(nativeMain)
dependencies {
implementation(libs.charlietap.cachemap)
implementation(libs.net.thauvin.erik.urlencoder.lib)
implementation(libs.dev.whyoleg.cryptography.provider.apple.optimal)
implementation("io.github.andreypfau:kotlinx-crypto-hmac:0.0.4")
implementation("io.github.andreypfau:kotlinx-crypto-sha2:0.0.4")
}
}
val appleTest =
create("appleTest") {
dependsOn(nativeTest)
}
iosMain {
dependsOn(appleMain)
}
val iosArm64Main by getting {
dependsOn(iosMain.get())
}
val iosSimulatorArm64Main by getting {
dependsOn(iosMain.get())
}
iosTest {
dependsOn(appleTest)
}
val iosArm64Test by getting {
dependsOn(iosTest.get())
}
val iosSimulatorArm64Test by getting {
dependsOn(iosTest.get())
}
// macosMain/macosTest source sets exist but are not wired until
// negentropy-kmp publishes a macosArm64 artifact.
val linuxMain =
create("linuxMain") {
dependsOn(nativeMain)
dependencies {
implementation(libs.net.thauvin.erik.urlencoder.lib)
implementation(libs.dev.whyoleg.cryptography.provider.apple.optimal)
implementation("io.github.andreypfau:kotlinx-crypto-hmac:0.0.4")
implementation("io.github.andreypfau:kotlinx-crypto-sha2:0.0.4")
}
}
val linuxTest =
create("linuxTest") {
dependsOn(nativeTest)
}
val linuxX64Main by getting {
dependsOn(linuxMain)
}
val linuxX64Test by getting {
dependsOn(linuxTest)
}
}
}
mavenPublishing {
// sources publishing is always enabled by the Kotlin Multiplatform plugin
configure(
KotlinMultiplatform(
// whether to publish a sources jar
sourcesJar = SourcesJar.Sources(),
),
)
coordinates(
groupId = "com.vitorpamplona.quartz",
artifactId = "quartz",
version = "1.08.0",
)
// Configure publishing to Maven Central
publishToMavenCentral(automaticRelease = true)
// Enable GPG signing for all publications
signAllPublications()
pom {
name = "Quartz: Nostr Library for Kotlin Multiplatform"
description = "Nostr library ported to Kotlin/Multiplatform for JVM, Android, iOS & Linux"
inceptionYear = "2025"
url = "https://github.com/vitorpamplona/amethyst/"
licenses {
license {
name = "MIT License"
url = "https://github.com/vitorpamplona/amethyst/blob/main/LICENSE"
}
}
developers {
developer {
id = "vitorpamplona"
name = "Vitor Pamplona"
url = "http://vitorpamplona.com"
email = "vitor@vitorpamplona.com"
}
}
scm {
url = "https://github.com/vitorpamplona/amethyst/"
connection = "https://github.com/vitorpamplona/amethyst/.git"
}
}
}