How would I compile C/++ code to statically link a...
# kotlin-native
m
How would I compile C/++ code to statically link against with the gradle plugin?
n
https://kotlinlang.org/docs/curl.html#generate-bindings you provide the .h file in the cinterop .def file as well as linker flags the sample project linked on there got most relevant info also i guess you need to configure your output to be a staticLibrary
Copy code
binaries { staticLib {  } }
or such in your native target
m
That doesn't seem to compile the library I'm building against though, and with the way kotlin freezes objects I can't just implement it in kotlin/native. To be specific, the library source files (.c, .cpp and .h) are in
<project root>/lib/libname/
, and my current def file (in
<project root>/src/nativeInterop/cinterop/libname.def
):
Copy code
headers = lib/libname/libname.h
package = libname
compilerOpts.linux = -Ilib/libname
linkerOpts.linux = -L lib/libname -l libname
But it doesn't seem to compile the library's source files, nor does it generate the defs because apparently the lib folder is not copied to the tempdir where kotlin native compiles from.
n
yeah as far as i understand this you need to compile the library beforehand.. maybe you can setup a gradle task that runs the correct clang or gcc command ?
b
There's official cpp support in gradle
m
So how would I implement that in gradle? Here's my current build.gradle.kts:
Copy code
plugins {
    kotlin("multiplatform") version "1.5.20"
    `cpp-library`
}

group = "com.martmists"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
}

val hostOs = System.getProperty("os.name")
val isMingwX64 = hostOs.startsWith("Windows")

(properties["libraries"]!! as String).split(",").forEach {
    library {
        baseName.set(it)

        linkage.set(listOf(Linkage.SHARED))

        source.from(file("include/$it/"))
        privateHeaders.from(file("include/$it/"))
        publicHeaders.from(file("include/$it/"))

        binaries.configureEach(CppSharedLibrary::class.java) {
            if (this.isOptimized) {
                // release
                // Set output dir to `<project root>/lib/$it/`
                // Ideally this is release when kotlin is building/running release
                //  and debug when kotlin is building/running debug
            }
        }
    }
}


kotlin {
    val nativeTarget = when {
        hostOs == "Mac OS X" -> macosX64("native")
        hostOs == "Linux" -> linuxX64("native")
        isMingwX64 -> mingwX64("native")
        else -> throw GradleException("Host OS is not supported in Kotlin/Native.")
    }

    nativeTarget.apply {
        val main by compilations.getting
        val portaudio by main.cinterops.creating
        // Errors because it can't find the library when only source is copied
        // I can't hardcode this because others also work on this and have
        // this repo on a different path
        // val bs2b by main.cinterops.creating


        binaries {
            sharedLib {
                baseName = if (isMingwX64) "libkaudio" else "kaudio"
            }

            executable {
                entryPoint = "kaudio.main"
            }
        }
    }

    sourceSets {
        val nativeMain by getting
    }
}
b
I'd move cpp stuff into a separate module
m
How would I do that? (I have practically zero knowledge of gradle and getting stuff to work is usually hours of copy-pasting ^^)
b
Then you can interact with it from any other module via
project(":my-cpp-module")
m
I always just use the templates people provide for projects because even the slightest change in gradle will usually break 5 other things
b
I'd strongly recommend reading through the docs to understand what's happening. Templates are great when you understand them, otherwise you lock yourself in to the unknown.
💯 1
âž• 1
m
I tried moving it to a different module, and so far I've noticed three things: • relative paths in .def still don't work • even when specifying
Copy code
tasks.named("build") {
    dependsOn(":libraries:bs2b:build")
    mustRunAfter(":libraries:bs2b:build")
}
kotlin seems to compile at the same time as cpp, meaning it won't build because the shared library will be missing • Kotlin will fail to build with
Copy code
* What went wrong:
A problem was found with the configuration of task ':stripSymbolsRelease' (type 'StripSymbols').
  - In plugin 'org.gradle.nativeplatform.plugins.NativeComponentModelPlugin' type 'org.gradle.nativeplatform.tasks.StripSymbols' property 'binaryFile' specifies file '/home/mart/git/kaudio/build/lib/main/release/libkaudio.so' which doesn't exist.
b
You need to add cpp compile tasks to kotlin compile task dependencies so gradle could figure out the proper order
m
that's why I added the dependsOn and mustRunAfter in the build. if I try :`compileKotlinNative`, I get
Copy code
* What went wrong:
Task with name ':compileKotlinNative' not found in root project 'kaudio'.
despite previous tasks saying
Copy code
> Task :compileKotlinNative
...
n
The def files don't support relative paths, only absolute paths are accepted. This is one of the Kotlin Native limitations with C interop and linking (not Gradle related). In order to use absolute paths they need to be done at the Gradle build file level. Below is an example:
Copy code
// ...
cinterops.create("paho_mqtt") {
                extraOpts("-libraryPath", "${System.getProperty("user.home")}/paho_mqtt_c-1.3.7/lib")
            }
// ...