Skip to content

feat(codegen): native Kotlin/JNI generator + Android example over the C ABI#60

Draft
Ivansete-status wants to merge 3 commits into
ffi-native-typed-returnsfrom
android-example
Draft

feat(codegen): native Kotlin/JNI generator + Android example over the C ABI#60
Ivansete-status wants to merge 3 commits into
ffi-native-typed-returnsfrom
android-example

Conversation

@Ivansete-status

Copy link
Copy Markdown
Collaborator

Adds an Android example consuming the timer library's native (zero-
serialization) C ABI from Kotlin via JNI. Based on the native-FFI stack (#58) so
it can use typed struct returns.

What

  • examples/timer/android/ — an Android library module with an idiomatic Kotlin
    TimerNode class.
  • jni/my_timer_jni.c — a JNI shim that turns each Kotlin external fun into a
    blocking call into the native ABI and reads the typed EchoResponse struct out
    of the result callback.
  • build-libs.sh cross-compiles, per ABI (arm64-v8a + x86_64), both
    libmy_timer.so (the Nim library) and libmy_timer_jni.so (the bridge) into
    src/main/jniLibs/, which Gradle packages automatically. An instrumented test
    covers create / version / echo.

Validation

Native build verified for both ABIs: correct aarch64/x86_64 ELF, the 4
Java_org_logos_mytimer_* symbols exported, and libmy_timer_jni.so correctly
NEEDS libmy_timer.so. (Kotlin/Gradle layer runs on a device/emulator.)

Separate PR, as requested. Sibling to the iOS example PR; both target the stack
tip and retarget to master once it lands.

🤖 Generated with Claude Code

An Android library module wrapping the timer library's native ABI behind an
idiomatic Kotlin `TimerNode` class via a JNI shim. `build-libs.sh` cross-compiles
two native libraries per ABI (arm64-v8a + x86_64) into src/main/jniLibs/:
libmy_timer.so (the Nim library) and libmy_timer_jni.so (the JNI bridge, which
NEEDs the former). The shim turns each Kotlin `external fun` into a blocking call
and reads the typed EchoResponse struct out of the result callback.

Gradle packages everything under jniLibs/ automatically; an instrumented test
covers create/version/echo on a device/emulator. Native build validated for
both ABIs (correct aarch64/x86_64 ELF, JNI symbols exported, libmy_timer.so
linked).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Ivansete-status
Ivansete-status force-pushed the ffi-native-typed-returns branch from 1060340 to c000a84 Compare May 31, 2026 16:38
@Ivansete-status
Ivansete-status marked this pull request as draft June 1, 2026 07:34
Ivansete-status and others added 2 commits June 13, 2026 16:54
Adds ffi/codegen/kotlin.nim, wired into the targetLang dispatch and exposed
as the `genbindings_kotlin` nimble task. From the same metadata it emits both
artifacts an Android consumer needs over the native (zero-serialization) C
ABI from c.nim: an idiomatic Kotlin AutoCloseable wrapper and the JNI shim
that bridges it.

Callback-shape selection is per proc (ack / string / struct), and the JNI
shim blocks on a condvar until the FFI-thread callback fires so the Kotlin
side stays synchronous. An all-string struct return crosses as a String[]
that the wrapper repacks into a data class — matching the validated example.

Procs needing seq/Option params, multiple struct params, or a non-string
struct return are skipped with a logged notice so the generated code always
compiles. That marshaling, events, and async are the next increments.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…pper

Regenerates the wrapper (MyTimerNode.kt) and JNI shim (my_timer_jni.c) via
`nimble genbindings_kotlin`, removing the hand-written sources, and points
the instrumented test at the derived MyTimerNode class.

Validated by cross-compiling both ABIs with the NDK: arm64-v8a + x86_64 build
clean, the four Java_org_logos_mytimer_MyTimerNode_* symbols are exported, and
libmy_timer_jni.so correctly NEEDS libmy_timer.so. (The Kotlin/Gradle layer
still runs on a device/emulator.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Ivansete-status Ivansete-status changed the title docs(examples): Android (Kotlin/JNI) example over the native C ABI feat(codegen): native Kotlin/JNI generator + Android example over the C ABI Jun 13, 2026
@Ivansete-status

Copy link
Copy Markdown
Collaborator Author

Expanded scope: this PR now also adds the Kotlin/JNI generator that produces the wrapper, not just the hand-written example (mirrors what #59 did for Swift).

  • ffi/codegen/kotlin.nim — from one set of {.ffi.} metadata it emits both artifacts: the idiomatic Kotlin AutoCloseable wrapper (MyTimerNode.kt) and the JNI shim (my_timer_jni.c). Wired into the targetLang dispatch + a genbindings_kotlin nimble task.
  • The hand-written TimerNode.kt / my_timer_jni.c are replaced by generated output; the instrumented test points at the derived MyTimerNode.
  • Callback-shape selection (ack / string / struct) is per proc; the shim blocks on a condvar until the FFI-thread callback fires. An all-string struct return crosses as a String[] repacked into a data class.
  • Procs needing seq/Option params, multiple struct params, or a non-string struct return (complex, schedule) are skipped with a logged notice so the generated code always compiles — that marshaling, events, and async are the next increments.

Validated by cross-compiling both ABIs with the NDK: arm64-v8a + x86_64 build clean, the four Java_org_logos_mytimer_MyTimerNode_* symbols are exported, and libmy_timer_jni.so correctly NEEDS libmy_timer.so.

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant