I’ve made it to step 4 in this guide, but for some...
# kotlin-native
j
I’ve made it to step 4 in this guide, but for some reason my Kotlin code is unable to recognise the
libcurl.*
import? Even though I have the libcurl.def in the correct nativeInterop sub folder under
src
?
a
Hello @jmillner_ ! To make this import available, your project have to produce bindings first. If it was not done automatically, you should try to execute interop task from the Gradle. In the GitHub hands-on project(https://github.com/kotlin-hands-on/intro-kotlin-native) there is
cinteropLibcurlMacos
, for example. Then KLIB should be created somewhere like
/build/classes/kotlin/macos/main/kotlin-hands-on-intro-kotlin-native-cinterop-libcurl.klib
. Also, I’d recommend to use more recent version of Kotlin, the one from the guide can be outdated a bit.
👍 1
j
Hi @Artyom Degtyarev [JB] I’ve still been having some trouble unfortunately. I’ve downloaded the following example from Hadi https://github.com/kotlin-hands-on/intro-kotlin-native which is the complete solution. I import it into Intellij and get met with the following error? Even though the build was a success?
message has been deleted
Although actually, regardless of the IDE showing alot of unrecognisable issues, the over-arching build did work and produced a working binary for my mac. Do you know where I might be going wrong inside the IDE?
a
This Github project uses an older version of the
kotlin-multiplatform
plugin(see [here](https://github.com/kotlin-hands-on/intro-kotlin-native/blob/d32de232e8ca3fe0ce31f01eb98ed229c78cd07a/build.gradle#L2 )). Currently, the latest is the 1.3.61 and is also presented in the IDEA’s Kotlin plugin. And this gap may be responsible for your problem. Kotlin bindings are always packed as the Kotlin libraries, a.k.a KLIB(see https://kotlinlang.org/docs/reference/native/libraries.html). This format isn’t stable yet, and therefore newer library readers cannot open older libs correctly. But as far as compilation uses the project-specified version of the compiler, it is producing the correct binary. Just try to update the script version, and tell if it won’t help.
j
Artyom! Thank you for your time and patience! I successfully built my first Raspberry Pi Binary last night! It was very simple, but worked! I wasn't quite able to get the curl example running though, as I suspect the linkerOpts aren't right for linuxArm32 target. What do you recommend for learning more about the cinterop? I would love to continue this, and I plan to do a brief lightening talk on Kotlin Native and my local Kotlin User Group
🎉 1
a
Glad to see, that everything worked for you! I would recommend you to read these two articles from the kotlinlang.org (https://kotlinlang.org/docs/tutorials/native/dynamic-libraries.html https://kotlinlang.org/docs/reference/native/c_interop.html). Also, some useful information can be found in the GitHub issues(https://github.com/JetBrains/kotlin-native/issues) . And, of course, feel free to ask here 🙂
🙏 1
j
Hi again Artyom 👋 I’m having trouble locating some information on how I specify multiple targets in Groovy? I have the following structure:
Copy code
plugins {
    id 'kotlin-multiplatform' version '1.3.61'
}

repositories {
    mavenCentral()
    jcenter()
}

kotlin {
    macosX64("test") {
        binaries {
            executable {
                entryPoint "test.main"
            }
        }
        compilations.main {
            cinterops {
                curl
            }
        }
    }
}
Which works great on MacOS, but I’d like to target both MacOS and Linux
I found this directly on KotlinLang: https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html#supported-platforms but I’m worried I’ll end up duplicating some of my groovy, is there an option to supply targets to the above in some form of parameters?
a
Hello again, @jmillner_! The problem here is a result of two unfortunate things:
cinterops
block is specified per compilation, and the compilation block is per-target in itself. That’s why sharing cinterops content cannot be shared so easy. But, there are some tricks can be done, for example, make everything depend on a host OS kind(see https://github.com/JetBrains/kotlin-native/blob/master/samples/libcurl/build.gradle.kts).
j
Hi Artyom! Thanks again for your further help! Thats been great and got me abit further! So I implemented the build.gradle.kts file as you showed above and it worked for MacOS only. I also spun up a Ubuntu VM to try out the linux compilation and that almost works but I'm getting an odd error and I think my gradle setup might not be quite right. I'm alittle unsure if I'm duplicating something here as my curl.def file looks like this:
Copy code
headers = curl/curl.h
headerFilter = curl/*
linkerOpts.osx = -L/usr/local/include -lcurl 
linkerOpts.linux = -L/usr/include/x86_64-linux-gnu/curl -lcurl
And by build.gradle.kts looks like this:
Copy code
val hostTarget = when {
        hostOs.contains("Mac OS X") -> macosX64("lkug")
        hostOs.contains("Linux") -> linuxX64("lkug")
        else -> throw GradleException("Host OS '$hostOs' is not supported in Kotlin/Native $project.")
    }

    hostTarget.apply {
        binaries {
            executable {
                entryPoint = "lkug.main"
                runTask?.args("<https://www.jetbrains.com/>")
            }
        }
        compilations["main"].cinterops {
            val curl by creating {
                when (preset) {
                    presets["macosX64"] -> includeDirs.headerFilterOnly("/usr/local/include")
                    presets["linuxX64"] -> includeDirs.headerFilterOnly("/usr/include/x86_64-linux-gnu")
                }
            }
        }

        mavenPublication {
            pom {
                withXml {
                    val root = asNode()
                    root.appendNode("name", "libcurl interop library")
                    root.appendNode("description", "A library providing interoperability with host libcurl")
                }
            }
        }
    }
The problem I'm having though is that when I try and build my project on a linux host, I receive an error message like
Unable to find library -lcurl
My understanding is that the linkerOpts need to point to where the header files exist, so that it can point to the headers and create the kotlin binding? When checking my linux host, the destinations that I'm providing do point to the directory where
curl.h
lives
a
I think you shouldn’t add another
/curl
in the end of your
linkerOpts
. You already specified your header as
curl/curl.h
.
j
This may be a silly question but I'm afraid I have to ask it, what does the
-lcurl
represent? Is that a reference to the binary on my machine? My understanding is that the
-L
is
-L/path/to/c/header/files
?
So that for the linkerOpts, you pass the header files and a reference to the physical binary?
k
First you have to know some basics compile C and using libraries etc. before getting into kotlin-native native. library directories -Lmy-lib-dir/ if relevant library names -laa and -lbb (when the libaa.so depends upon libbb.so, in that order)
j
Yeah @Kavan I think this is where I'm lacking majorly. I don't have much C background at all and purely attempting to have a go and see where I can get to 🙂
Can you recommend anything to get started?
I'll definitely continue with my efforts thus far on my little project itself, but I'm alittle lost as to where to look for some recommended reading
In my example above though it still leaves me abit puzzled as based on your info there @Kavan I should be correctly pointing to my library directories with -L (Header file locations). But how does
-lcurl
know where to look for curl? Is it based on the PATH?
k
-lcurl point to libcurl.so installed on system so it doesn't require location path
j
Seems to suggest then that libcurl.so isn't available on my linux system then?
(Please excuse my naivety, I'm starting out fresh with Kotlin Native - having only prior experience in backend web systems on the JVM)
k
It look for file (example in Linux /usr/lib64/libcurl.so.version)
Are you on Linux or Mac ?
j
I work on Mac locally and I can successfully build a MacOS binary - the problem is when I try and build the project on an ubuntu machine
(Digitial ocean ubuntu droplet - for ease)
k
Linker options path change on different OS
j
Yeah so I have that set in my curl.def file:
Copy code
headers = curl/curl.h
headerFilter = curl/*
linkerOpts.osx = -L/usr/local/include -lcurl
linkerOpts.linux = -L/usr/include/x86_64-linux-gnu -lcurl
k
message has been deleted
I don't know about windows
j
Ah so I see you provide three arguments there, whereas I've only got the two 🤔
Yeah I've removed windows as I don't plan on building it for windows
Unfortunately I can't access my Digi ocean machine from work, but will definitely look to see if /usr/lib64 exists on my machine
What are the contents inside your lib64 folder? The .so files?
(Again nooby questions, please bare with me 🙂 - Also thank you very much for your time!)
k
message has been deleted
You can see curl
j
AH HA- I suspect this is the cause of my problem then @Kavan I'm not providing that location
Although I'm little unsure how it works it out on macos, as the only linkerOpts I provide to are:
Copy code
linkerOpts.osx = -L/usr/local/include -lcurl
as
/usr/local/include
contains
/curl
and in there is all the header files for curl
k
Yes
I added that in includeDirs in gradle. So I didn't add in .def file
j
Ah interesting, can you share an example @Kavan? I think I've got a similar setup in my build.gradle.kts:
Copy code
hostTarget.apply {
        binaries {
            executable {
                entryPoint = "lkug.main"
                runTask?.args("<https://www.jetbrains.com/>")
            }
        }
        compilations["main"].cinterops {
            val curl by creating {
                when (preset) {
                    presets["macosX64"] -> includeDirs.headerFilterOnly("/usr/local/include")
                    presets["linuxX64"] -> includeDirs.headerFilterOnly("/usr/include/x86_64-linux-gnu")
                }
            }
        }
However I throw in there the same location for the header files, but it still works?
k
Wait I'm on Linux. I will show you my gradle.kts
j
🙏 thank you!
k
Unable to find library error because of libcurl-dev not installed
Debian based libcurl-devel. Other platforms libcurl-dev
Make sure
/usr/include/curl
folder exist
j
So I seem to have got abit further now. But I’m getting a strange error during the linkDebugExecutable stage (When trying to compile a linuxX64 version):
ld.lld: error: undefined symbol: curl_easy_strerror
This error seems to repeat for a handful of curl related methods
Alittle bit at a loss as to what this error may be - it appears I’ve linked up the correct options to cinterop as that stage passes
Could it perhaps be the version of curl I’m trying to bind?
Weirdly when I switch the target to be macosX64 the build runs fine and produces a MacOS binary
For reference this is my curl.def file:
Copy code
headers = curl/curl.h
compilerOpts.osx = -I/usr/local/Cellar/curl/7.68.0/include <- Header Locations
compilerOpts.linux = -I/usr/local/Cellar/curl/7.68.0/include <- Header Locations
linkerOpts.osx = -L/usr/local/Cellar/curl/7.68.0/lib -lcurl <- Library Locations
linkerOpts.linux = -L/usr/local/Cellar/curl/7.68.0/lib -lcurl <- Library Locations
My next attempt is to try and find the header locations & lib locations on a linux machine and try to run a build on there
Not sure what I’m missing to be able to cross compile from MacOS to linux
The reason I have them the same for now is to try and understand what the tooling is doing on my Mac
SUCCESS UPDATE: I successfully managed to build the binary on a Linux machine!! Unfortunately I’ve had to leave my machine for evening plans, but will follow up wit what I did to get it working shortly!