Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,15 @@ jobs:
- build-jvm-linux
uses: ./.github/workflows/docs-jvm.yml

#################
# KMP

test-kmp:
needs:
- build-jvm-linux
- build-jvm-darwin
uses: ./.github/workflows/test-kmp.yml

#################
# iOS/Swift

Expand Down
49 changes: 49 additions & 0 deletions .github/workflows/test-kmp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
concurrency:
group: "${{ github.workflow }}-${{ github.ref }}-test-kmp-jvm"
cancel-in-progress: true

on:
workflow_call:
workflow_dispatch:

env:
RELEASE: 1

jobs:
test-jvm:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v6
- name: set up jdk 17
uses: actions/setup-java@v5
with:
java-version: "17"
distribution: "adopt"
- name: gradle setup
uses: gradle/actions/setup-gradle@v5
- name: validate gradle wrapper
uses: gradle/actions/wrapper-validation@v5

- name: download linux library
uses: ./.github/actions/make/jvm
with:
gh-token: ${{ secrets.GITHUB_TOKEN }}

# The specific jvm action uses `uname -s` to determine which `jvm` make rule to call.
# Because this workflow runs on ubuntu, we're using the generic action
- name: download aarch64 apple darwin artifact
uses: ./.github/actions/make
with:
key: jvm-darwin
make-rule: jvm-darwin
target-path: target/aarch64-apple-darwin/release/libcore_crypto_ffi.dylib
gh-token: ${{ secrets.GITHUB_TOKEN }}

- name: build and test kmp package
uses: ./.github/actions/make
with:
key: kmp-jvm-test
make-rule: kmp-jvm-test
always-run: ${{ github.event_name == 'workflow_dispatch' || github.ref_name == 'main' }}
gh-token: ${{ secrets.GITHUB_TOKEN }}
30 changes: 23 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,15 @@ RUST_SOURCES := $(WORKSPACE_CARGO_FILES) $(CRATE_MANIFESTS) $(RUST_RS_FILES)
hash=$$(sha256sum $($*-deps) | sha256sum | awk '{print $$1}'); \
echo "$$hash"

#-------------------------------------------------------------------------------
# Kotlin file-based heuristics
#-------------------------------------------------------------------------------

KT_WRAPPER = ./crypto-ffi/bindings/shared/src/commonMain/kotlin
KT_TESTS = ./crypto-ffi/bindings/shared/src/commonTest
KT_INTEROP = ./interop/src/clients/android-interop/src/main/java
KT_FILES := $(shell find $(KT_WRAPPER) $(KT_TESTS) $(KT_INTEROP) -type f -name '*.kt')

#-------------------------------------------------------------------------------
# Build FFI artifacts
#-------------------------------------------------------------------------------
Expand Down Expand Up @@ -436,6 +445,17 @@ $(STAMPS)/jvm-test: $(jvm-test-deps)
./gradlew jvm:test --rerun
$(TOUCH_STAMP)

#-------------------------------------------------------------------------------
# KMP (Kotlin Multiplatform) builds
#-------------------------------------------------------------------------------

kmp-jvm-test-deps := $(KT_FILES)

$(STAMPS)/kmp-jvm-test: $(kmp-jvm-test-deps)
cd crypto-ffi/bindings && \
./gradlew kmp:jvmTest --rerun
$(TOUCH_STAMP)

#-------------------------------------------------------------------------------
# TypeScript / JS tasks
#-------------------------------------------------------------------------------
Expand Down Expand Up @@ -592,7 +612,7 @@ $(STAMPS)/docs-rust-wasm: $(RUST_SOURCES)
docs-rust-wasm: $(STAMPS)/docs-rust-wasm ## Generate Rust docs for wasm32-unknown-unknown

# Kotlin docs
KOTLIN_SOURCES := $(shell find crypto-ffi/bindings/jvm/src/main/kotlin \
KOTLIN_SOURCES := $(shell find crypto-ffi/bindings/shared/src/commonMain/kotlin \
-type f -name '*.kt' 2>/dev/null | LC_ALL=C sort)
DOCS_KOTLIN := target/kotlin/doc/html/index.html
$(DOCS_KOTLIN): $(JVM_LIB) $(KOTLIN_SOURCES)
Expand Down Expand Up @@ -699,11 +719,6 @@ swift-check: $(STAMPS)/swift-check ## Lint Swift files via swift-format and swif

# Kotlin

KT_WRAPPER = ./crypto-ffi/bindings/jvm/src/main/kotlin
KT_TESTS = ./crypto-ffi/bindings/jvm/src/test
KT_INTEROP = ./interop/src/clients/android-interop/src/main/java
KT_FILES := $(shell find $(KT_WRAPPER) $(KT_TESTS) $(KT_INTEROP) -type f -name '*.kt')

$(STAMPS)/kotlin-fmt: $(KT_FILES)
ktlint --format $(KT_WRAPPER) $(KT_TESTS) $(KT_INTEROP)
$(TOUCH_STAMP)
Expand Down Expand Up @@ -746,9 +761,10 @@ check: rust-check swift-check kotlin-check ts-check ## Run all linters
# Lazy targets
#-------------------------------------------------------------------------------

LAZY_TARGETS := jvm-test ts-test android-test ios-test interop-test
LAZY_TARGETS := jvm-test kmp-jvm-test ts-test android-test ios-test interop-test

ts-test: ## Run TypeScript wrapper tests via wdio and bun. Optionally pass TEST=<test> to filter by test name.
kmp-jvm-test: ## Run Kotlin multi-platform tests on JVM
jvm-test: ## Run Kotlin tests on JVM
android-test: ## Run Kotlin tests on Android
ios-test: ## Run Swift tests on iOS (macOS only)
Expand Down
7 changes: 4 additions & 3 deletions crypto-ffi/bindings/android/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ plugins {
id("com.vanniktech.maven.publish.base")
}

val jvmSources = projectDir.resolve("../jvm/src")
val sharedSources = projectDir.resolve("../shared/src/commonMain")
val sharedTestSources = projectDir.resolve("../shared/src/commonTest")

val dokkaHtmlJar = tasks.register<Jar>("dokkaHtmlJar") {
dependsOn(tasks.dokkaGeneratePublicationHtml)
Expand Down Expand Up @@ -87,12 +88,12 @@ android {
main {
kotlin {
srcDir(projectDir.resolve("src/main/uniffi"))
srcDir(jvmSources.resolve("main/kotlin"))
srcDir(sharedSources.resolve("kotlin"))
}
}
androidTest {
kotlin {
srcDir(jvmSources.resolve("test"))
srcDir(sharedTestSources.resolve("kotlin"))
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions crypto-ffi/bindings/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,17 @@ kotlin-gradle = "1.9.21"
dokka = "2.0.0"
detekt = "1.23.8"
agp = "8.12.3"
gobley = "0.3.7"

[plugins]
android-library = { id = "com.android.library", version.ref = "agp" }
vanniktech-publish = { id = "com.vanniktech.maven.publish", version.ref = "vanniktech-publish" }
dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" }
detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
gobley-cargo = { id = "dev.gobley.cargo", version.ref = "gobley" }
gobley-uniffi = { id = "dev.gobley.uniffi", version.ref = "gobley" }
gobley-rust = { id = "dev.gobley.rust", version.ref = "gobley" }
kotlin-atomicfu = { id = "org.jetbrains.kotlin.plugin.atomicfu", version.ref = "kotlin" }

[libraries]
coroutines-bom = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-bom", version.ref = "coroutines" }
Expand Down
10 changes: 9 additions & 1 deletion crypto-ffi/bindings/jvm/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ kotlin {
jvmToolchain(17)
}

val sharedSources = projectDir.resolve("../shared/src/commonMain")
val sharedTestSources = projectDir.resolve("../shared/src/commonTest")

dependencies {
implementation(platform(kotlin("bom")))
implementation(platform(libs.coroutines.bom))
Expand Down Expand Up @@ -61,13 +64,18 @@ tasks.named("compileKotlin") {
sourceSets {
main {
kotlin {
srcDir(projectDir.resolve("src/main/kotlin"))
srcDir(sharedSources.resolve("kotlin"))
srcDir(projectDir.resolve("src/main/uniffi"))
}
resources {
srcDirs(ffiLibsBase.resolve(buildType))
}
}
test {
kotlin {
srcDir(sharedTestSources.resolve("kotlin"))
}
}
}

// Allows skipping signing jars published to 'MavenLocal' repository
Expand Down

This file was deleted.

183 changes: 183 additions & 0 deletions crypto-ffi/bindings/kmp/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import gobley.gradle.GobleyHost
import gobley.gradle.cargo.dsl.*
import org.gradle.api.tasks.bundling.Jar

plugins {
kotlin("multiplatform")
id("com.android.library")
alias(libs.plugins.gobley.cargo)
alias(libs.plugins.gobley.uniffi)
id("com.vanniktech.maven.publish.base")
alias(libs.plugins.kotlin.atomicfu)
}

val dokkaHtmlJar = tasks.register<Jar>("dokkaHtmlJar") {
dependsOn(tasks.dokkaGeneratePublicationHtml)
from(tasks.dokkaGeneratePublicationHtml.flatMap { it.outputDirectory })
archiveClassifier.set("html-docs")
}

kotlin {
jvmToolchain(17)

// Android target
androidTarget {
publishLibraryVariants("release")
}

// JVM target
jvm()

// iOS targets
iosArm64()
iosSimulatorArm64()

// macOS ARM64 target
macosArm64()

sourceSets {
val commonMain by getting {
sourceSets {
kotlin.srcDir("../shared/src/commonMain/kotlin")
}
dependencies {
implementation(libs.coroutines.core)
}
}

val commonTest by getting {
sourceSets {
kotlin.srcDir("../shared/src/commonTest/kotlin")
}
dependencies {
implementation(kotlin("test"))
implementation(libs.coroutines.test)
}
}

val jvmMain by getting {
dependencies {
implementation(libs.jna)
}
}

val jvmTest by getting {
dependencies {
implementation(libs.assertj.core)
}
}

val androidMain by getting {
dependencies {
implementation("${libs.jna.get()}@aar")
implementation("androidx.annotation:annotation:1.9.1")
}
}

val androidInstrumentedTest by getting {
dependencies {
implementation(libs.android.junit)
implementation(libs.espresso)
implementation(libs.assertj.core)
}
}

// Native targets share sources
val nativeMain by creating {
dependsOn(commonMain)
}

val nativeTest by creating {
dependsOn(commonTest)
}

val iosArm64Main by getting {
dependsOn(nativeMain)
}

val iosArm64Test by getting {
dependsOn(nativeTest)
}

val iosSimulatorArm64Main by getting {
dependsOn(nativeMain)
}

val iosSimulatorArm64Test by getting {
dependsOn(nativeTest)
}

val macosArm64Main by getting {
dependsOn(nativeMain)
}

val macosArm64Test by getting {
dependsOn(nativeTest)
}
}
}

android {
namespace = "com.wire.crypto"
compileSdk = libs.versions.sdk.compile.get().toInt()

defaultConfig {
minSdk = libs.versions.sdk.min.get().toInt()
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

ndk {
abiFilters += setOf("arm64-v8a", "armeabi-v7a", "x86_64")
}
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
}

cargo {
// Point to the crypto-ffi crate directory
packageDirectory = layout.projectDirectory.dir("../..")

// Only build JVM native libraries for the current host platform
// This disables cross-compilation for other JVM targets (e.g., Linux ARM64 on macOS)
builds.jvm {
embedRustLibrary = (rustTarget == GobleyHost.current.rustTarget)
}
}

// Configure iOS build tasks with the required environment
afterEvaluate {
tasks.matching { it.name.contains("cargoBuildIos") }.configureEach {
// Set environment via the task's additionalEnvironment if available
if (this is gobley.gradle.cargo.tasks.CargoBuildTask) {
val target = if (name.contains("Simulator")) {
"IPHONESIMULATOR_DEPLOYMENT_TARGET"
} else {
"IPHONEOS_DEPLOYMENT_TARGET"
}
additionalEnvironment.put(target, "16.0")
}
}
}

uniffi {
generateFromLibrary {
namespace = "core_crypto_ffi"
packageName = "com.wire.crypto"
}
}

mavenPublishing {
publishToMavenCentral(automaticRelease = true)
pomFromGradleProperties()
signAllPublications()
}

// Allows skipping signing jars published to 'MavenLocal' repository
tasks.withType<Sign>().configureEach {
if (System.getenv("CI") == null) {
enabled = false
}
}
Binary file not shown.
Loading
Loading