
Bridges application code with native libraries, offering a unified API to call native functions, manage foreign instances and pointer lifecycles, and handle Wire protobuf messages.
Ferrus Nexus KMP is a Kotlin Multiplatform library for bridging Kotlin code with native libraries (focusing on library authors). It provides a shared API for calling native functions, creating foreign instances, and working with Wire message types across JVM and native targets.
Add the dependency to your project:
implementation("io.github.ignaciodelatorrearias:ferrus-nexus:0.0.1")import io.github.ignaciodelatorrearias.ferrusnexus.FerrusNexus
val nexus = FerrusNexus(
library = "my_native_library",
errorAdapter = YourErrorMessage.ADAPTER,
errorManagerFunction = { status: int, error: YourErrorMessage ->
// handle errors
},
freeBufferFunction = my_native_library_h::free_buffer
)
nexus.function(my_native_library_h::some_function)import io.github.ignaciodelatorrearias.ferrusnexus.executablePath
import io.github.ignaciodelatorrearias.ferrusnexus.FerrusNexus
val name = when (Platform.osFamily) {
OsFamily.UNKNOWN -> throw Error("Unknown Platform")
OsFamily.MACOSX -> throw Error("Unsupported Platform")
OsFamily.IOS -> throw Error("Unsupported Platform")
OsFamily.LINUX -> "libmy_native_library.so"
OsFamily.WINDOWS -> "my_native_library.dll"
OsFamily.ANDROID -> throw Error("Unsupported Platform")
OsFamily.WASM -> throw Error("Unsupported Platform")
OsFamily.TVOS -> throw Error("Unsupported Platform")
OsFamily.WATCHOS -> throw Error("Unsupported Platform")
}
val nexus = FerrusNexus(
executablePath / name,
errorAdapter = YourErrorMessage.ADAPTER,
errorManagerFunction = { status: int, error: YourErrorMessage ->
// handle errors
},
"free_buffer"
)
nexus.function("some_function")
// Optionally if you consider using implicit dynamic linking and cinterops functionality.
val nexus = FerrusNexus(
errorAdapter = YourErrorMessage.ADAPTER,
errorManagerFunction = { status: int, error: YourErrorMessage ->
// handle errors
},
::free_buffer
)
nexus.function(::some_function)Kotlin/native doesn't implement a way to use dynamic libraries, but it does implement a way to use static ones.
We could use some trickery to pass the native library files to the linker, forcing implicit linking.
linkerOpts.mingw_x64 = -Lnatives/x86_64-windows/ -lmy_native_library.dll
linkerOpts.linux_x64 = -Lnatives/x86_64-linux-gnu/ -lmy_native_library -rpath "$ORIGIN:."
However for library authors this creates a problem, because users need to be aware of how cinterops works and what files would they need configure to pass to the linker.
Ferrus Nexus offers a way to use explicit linking and do some non-configuration-intensive trickery.
A typical .def file:
headers = my_native_library.h
package = com.example.my_native_library
compilerOpts = -Imy_native_library/
staticLibraries.mingw_x64 = my_native_library.dll
libraryPaths.mingw_x64 = natives/x86_64-windows/
staticLibraries.linux = libmy_native_library.so
libraryPaths.linux_x64 = natives/x86_64-linux-gnu/
libraryPaths.linux_arm64 = natives/aarch64-linux-gnu/
This only helps to include the .dll/.so inside the .klib.
The client of the library only needs to add:
plugins {
...
id("io.github.ignaciodelatorrearias.ferrus-nexus-extract") version "0.0.1"
}This plugin only extracts the dynamic libraries from the .klib and places it alongside the executable for the corresponding platform.
This project is licensed under the Apache License 2.0.
Ferrus Nexus KMP is a Kotlin Multiplatform library for bridging Kotlin code with native libraries (focusing on library authors). It provides a shared API for calling native functions, creating foreign instances, and working with Wire message types across JVM and native targets.
Add the dependency to your project:
implementation("io.github.ignaciodelatorrearias:ferrus-nexus:0.0.1")import io.github.ignaciodelatorrearias.ferrusnexus.FerrusNexus
val nexus = FerrusNexus(
library = "my_native_library",
errorAdapter = YourErrorMessage.ADAPTER,
errorManagerFunction = { status: int, error: YourErrorMessage ->
// handle errors
},
freeBufferFunction = my_native_library_h::free_buffer
)
nexus.function(my_native_library_h::some_function)import io.github.ignaciodelatorrearias.ferrusnexus.executablePath
import io.github.ignaciodelatorrearias.ferrusnexus.FerrusNexus
val name = when (Platform.osFamily) {
OsFamily.UNKNOWN -> throw Error("Unknown Platform")
OsFamily.MACOSX -> throw Error("Unsupported Platform")
OsFamily.IOS -> throw Error("Unsupported Platform")
OsFamily.LINUX -> "libmy_native_library.so"
OsFamily.WINDOWS -> "my_native_library.dll"
OsFamily.ANDROID -> throw Error("Unsupported Platform")
OsFamily.WASM -> throw Error("Unsupported Platform")
OsFamily.TVOS -> throw Error("Unsupported Platform")
OsFamily.WATCHOS -> throw Error("Unsupported Platform")
}
val nexus = FerrusNexus(
executablePath / name,
errorAdapter = YourErrorMessage.ADAPTER,
errorManagerFunction = { status: int, error: YourErrorMessage ->
// handle errors
},
"free_buffer"
)
nexus.function("some_function")
// Optionally if you consider using implicit dynamic linking and cinterops functionality.
val nexus = FerrusNexus(
errorAdapter = YourErrorMessage.ADAPTER,
errorManagerFunction = { status: int, error: YourErrorMessage ->
// handle errors
},
::free_buffer
)
nexus.function(::some_function)Kotlin/native doesn't implement a way to use dynamic libraries, but it does implement a way to use static ones.
We could use some trickery to pass the native library files to the linker, forcing implicit linking.
linkerOpts.mingw_x64 = -Lnatives/x86_64-windows/ -lmy_native_library.dll
linkerOpts.linux_x64 = -Lnatives/x86_64-linux-gnu/ -lmy_native_library -rpath "$ORIGIN:."
However for library authors this creates a problem, because users need to be aware of how cinterops works and what files would they need configure to pass to the linker.
Ferrus Nexus offers a way to use explicit linking and do some non-configuration-intensive trickery.
A typical .def file:
headers = my_native_library.h
package = com.example.my_native_library
compilerOpts = -Imy_native_library/
staticLibraries.mingw_x64 = my_native_library.dll
libraryPaths.mingw_x64 = natives/x86_64-windows/
staticLibraries.linux = libmy_native_library.so
libraryPaths.linux_x64 = natives/x86_64-linux-gnu/
libraryPaths.linux_arm64 = natives/aarch64-linux-gnu/
This only helps to include the .dll/.so inside the .klib.
The client of the library only needs to add:
plugins {
...
id("io.github.ignaciodelatorrearias.ferrus-nexus-extract") version "0.0.1"
}This plugin only extracts the dynamic libraries from the .klib and places it alongside the executable for the corresponding platform.
This project is licensed under the Apache License 2.0.