Hello, I have an issue with cinterop trying to com...
# kotlin-native
m
Hello, I have an issue with cinterop trying to compile in macos for a linux (X, arm) target. It fails on
compileNativeMainKotlinMetadata
:
Copy code
e: file:///Users/myuser/Projects/demo/src/nativeMain/Main.kt:12:8 Unresolved reference: libpq
In summary: Linux machine (x64): • linuxX64 • linuxArm64 (I think it's supposed to work) Macos machine (arm64): • macosX64 • macosArm64 • linuxX64 • linuxArm64 Not sure why linuxX64 works on Linux machine but not Macos. Appreciate if someone could provide help or even a way to debug this issue (not sure where to start).
Currently defining the cinterop like this:
Copy code
macosArm64 {
        val main by compilations.getting
        val libpq by main.cinterops.creating {
            defFile(project.file("src/nativeInterop/cinterop/libpq.def"))
        }
    }
l
Did you copy headers into your project, or are you using system headers? If you're using system headers, they may not be in the same place or compatible on other compilation hosts.
m
Not too sure what the difference between those two options is.. This is my current .def file:
Copy code
headers = libpq-fe.h
headerFilter = *
package = libpq

compilerOpts = -I/opt/homebrew/opt/libpq/include -I/usr/local/opt/libpq/include
linkerOpts = -L/opt/homebrew/opt/libpq/lib -L/usr/local/opt/libpq/lib -lpq
Ok, so made some progress. This flag seems to fix
compileNativeMainKotlinMetadata
for all targets, but I don't fully understand what it does:
Copy code
kotlin.mpp.enableCInteropCommonization=true
However, it now fails for
linkDebugTestLinuxX64
:
Copy code
ld.lld: error: undefined symbol: PQsetdbLogin
>>> referenced by out
>>>               /private/var/folders/dg/z7k2610n0vd0qgqzc7v17pxr0000gn/T/konan_temp16050745230498861662/test.kexe.o:(libpq_PQsetdbLogin_wrapper5)
>>> did you mean: _PQsetdbLogin
>>> defined in: /usr/local/opt/libpq/lib/libpq.a
So: macosArm64 , macosX64 , linuxArm64 , linuxX64 . For reference, I also had to stop using the same
libpq.def
for all targets, since
macosX64
was failing on
linkDebugTestMacosX64
because it was finding the arm64 version of
libpq
first:
Copy code
ld: symbol(s) not found for architecture x86_64
So now arm64 .def points to arm64 libpq installation, and x64 .def points to x64 libpq installation.
Turns out
libpq
homebrew version for macosX64 isn't compatible with linuxX64, even though the arm64 ones are. Compiling successfully for all 4 targets now. Problem is, having a different
.def
file (i.e., link paths) for each target isn't suitable for this project, because it is a library. So I still have to find a way to have the same
.def
for all targets, and be able to build this in my machine and in a pipeline.
l
I believe you can use <setting>.<target> to specify per target. For example:
Copy code
linkerOpts.linuxX64 = ...
linkerOpts.macosArm64 = ...
...
I usually create a folder in my project called prebuilts, with per-target headers and binaries. This allows the project to be built on other targets without worrying about headers being compatible.
👀 1
m
If you have an example with prebuilts I'd appreciate it. Otherwise, <setting>.<target> looks good. Cheers Landry 👍
l
I don't think I have any public examples of this. I used it on an internal project at a previous job. The basic gist is to create prebuilts/linuxX64/headers or prebuilts/macosX64/binaries, etc (you can choose whether targets or header/binary are the first differentiator). Copy the binary and header from each platform into the proper build folder. The defs should direct to these folders.
m
Awesome, thanks for the tips 🙏