Cross Platform Native Library with Shared Objects

Hey everyone

Can anyone point me to some documentation or examples on how I can properly create a multiplatform library using Kotlin Multiplatform targeting multiple Native targets? I struggle a bit to make really a library which others could consume in their Kotlin/Native projects.

My planned chain looks like this:

AlphaSkia Native Libs -> AlphaSkia Kotlin/Native Lib --(maven)-> AlphaTab Kotlin/Native Shared Lib
- libalphaskia.dll       - alphaSkia.klib                        - alphaTab.dll 
- libalphaskia.lib       - libalphaskia.dll                      - alphaTab.lib
- libalphaskia.so        - libalphaskia.lib                      - alphaTab.so
- libalphaskia.dylib     - libalphaskia.so                       - alphaTab.dylib
                         - libalphaskia.dylib                    - iOS CocoaPod

AlphaSkia is a cross technology, platform and CPU architecture Skia wrapper. This library I want to put now into a Kotlin/Native wrapper an publish it to Maven Central as package.

AlphaTab is my actual end-customer library which consumes AlphaSkia as rendering backend. This library I want to build then into native shared libraries and packages for devs to use in their apps. Windows/Linux I mainly want for Testing purposes while the ultimate goal is to target macOS/iOS/iPadOS in my library.

My main questions currently are:

  1. Can I build and bundle mutliple Kotlin/Native targets into one package or do I need to create an individual Kotlin/Native Maven package for each target? I would like to build the binaries on a Matrix in GitHub Actions and the publish all items together in one package to consume.
  2. AlphaSkia is a shared library. How can I embed all the files requried for linking to the package so they are available for AlphaTab?

I looked through following docs but could not find answers to my questions:

The docs somehow ignore the fact that you cannot compile all targets on the same machine but have to deal with a sequence of build and packaging steps. There also seem to be the assumption that you should only work with static libs as dependencies and shared library dependencies are not touched.

Thanks and Kind Regards
Daniel

I think I might have found a partial solution for problem 2:

The staticLibraries feature seem to also work for share libraries. I prefer setting the options through Gradle over adding them to the .def file but basically I do:

val libDir = "path to target specific libs (OS, architecture etc)"
val lib = "target specific lib name for linker"
val libFilesToInclude = arrayOf("lib", "files", "to", "include")
binaries {
    sharedLib {
        baseName = "alphaskia"
        linkerOpts += arrayOf("-L${libDir.canonicalPath.replace('\\', '/')}", "-l${lib}")
    }
}
compilations["main"].cinterops {
    val alphaSkia by creating {
        includeDirs(rootProject.projectDir.resolve("../../wrapper/include"))
        // include the lib files in the klib 
        extraOpts("-libraryPath", libDir)
        for(included in libFilesToInclude ) {
            extraOpts("-staticLibrary", included)
        }
    }
}

The extraOpts allow me to embed the required library files for linking (.so on linux, .dylib on macOS, .dll and .lib on Windows). There also seem to be some hidden magic for the linkerOpts because in my consumer project I don’t need any linkerOpts.

Unfortunately in my consumer project the Shared Libraries are not yet copied to the output directory (e.g. beside the test.exe).

This raises a new question 3:

  1. Is there a way to extract the shared libraries beside the compile outputs?