Fork me on GitHub
#graalvm
<
2024-05-19
>
Ingy döt Net01:05:43

Has anyone here written (or seen) a native-image compiled thing that loads a shared library?

1
phronmophobic04:05:11

I can't seem to find the documentation for ffi calls that I used to use. Maybe it's been deprecated. Anyway, I'm pretty sure they support JNI and JNA. See https://www.graalvm.org/latest/reference-manual/native-image/native-code-interoperability/ more info.

borkdude06:05:45

Spire is another example

👍 1
Ingy döt Net22:05:54

https://github.com/epiccastle/spire/blob/3ff1a18a843f56a2a3b0aa646cc3dd8e6ca3891d/graal-configs/resource-config.json#L4 looks like what I need to solve:

Native library (home/ingy/src/yamlscript/rapidyaml/native/librapidyaml.so.0.6.0) not found in resource path ()

phronmophobic22:05:38

Does that work?

Ingy döt Net22:05:34

I'll let you know 🙂

Ingy döt Net22:05:56

~/src/yamlscript rapidyaml $ LD_LIBRARY_PATH=$PWD/rapidyaml/native YS_PARSER=rapidyaml ./ys/bin/ys -e 'say: 42'
Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library '/home/ingy/src/yamlscript/rapidyaml/native/librapidyaml.so.0.6.0':
com.sun.jna.Native.open(Ljava/lang/String;I)J [symbol: Java_com_sun_jna_Native_open or Java_com_sun_jna_Native_open__Ljava_lang_String_2I]
com.sun.jna.Native.open(Ljava/lang/String;I)J [symbol: Java_com_sun_jna_Native_open or Java_com_sun_jna_Native_open__Ljava_lang_String_2I]
Native library (home/ingy/src/yamlscript/rapidyaml/native/librapidyaml.so.0.6.0) not found in resource path ()
        at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:325)
is my current failure.

Ingy döt Net22:05:36

./ys/bin/ys is native-image

phronmophobic22:05:30

for building a native executable, it seems like you would want to build a static library and statically link it.

Ingy döt Net22:05:07

I'm not sure about that... If I can load stuff dynamically then it's possible to build libraries using Java classes that are not backed into bb or ys...

phronmophobic22:05:12

does librapidyaml have other shared dependencies?

phronmophobic22:05:18

you can go that route, where librapidyaml is required to be installed by the user

☝️ 1
Ingy döt Net22:05:23

no. for librapidyaml doing it staticly is probably better. but exploring the dynamic option right now

Ingy döt Net22:05:23

I can make it part of the various YS install methods

phronmophobic22:05:43

in this particular case, it seems like librapidyaml is not "installed" correctly

Ingy döt Net22:05:38

yeah but I think you need to tell native-image where that is exactly

phronmophobic22:05:06

No, it just needs to be on the load path.

Ingy döt Net22:05:19

you can see above that I set LD_LIBRARY_PATH

phronmophobic22:05:55

right and it did load librapidyaml, which probably has a dependency on /home/ingy/src/yamlscript/rapidyaml/native/librapidyaml.so.0.6.0

phronmophobic22:05:18

I can't remember the exact terminology, but it has something to with some combination of rpath and install name

Ingy döt Net22:05:06

hmm, am I misunderstanding the error? not sure what you mean by > right and it did load librapidyaml, which probably has a dependency on /home/ingy/src/yamlscript/rapidyaml/native/librapidyaml.so.0.6.0

phronmophobic22:05:39

I'm assuming you did (Native/loadLibrary "rapidyaml") or similar?

phronmophobic22:05:59

what does otool -L /home/ingy/src/yamlscript/rapidyaml/native/librapidyaml.dylib say?

Ingy döt Net22:05:38

is that a mac thing?

phronmophobic22:05:43

although, I think there's a similar thing on linux

phronmophobic22:05:58

but with slightly different tools and names.

Ingy döt Net22:05:57

last message got messed up.

Ingy döt Net22:05:16

You should get the same result on a mac with:

git clone --branch=rapidyaml  && cd yamlscript && make -C ys build && LD_LIBRARY_PATH=$PWD/rapidyaml/native YS_PARSER=rapidyaml ./ys/bin/ys -e 'say: 42'
I'll ssh into my seattle mini and try

Ingy döt Net23:05:02

rapidyaml not building on mac for me

Ingy döt Net23:05:18

I need to meet people for dinner

Ingy döt Net23:05:25

will try more after

jpmag00:05:39

I was pushing for packaging the library in the jar archive. IIUC, that's the proper way to ship; eg https://stackoverflow.com/questions/2937406/how-to-bundle-a-native-library-and-a-jni-library-inside-a-jar?rq=1

phronmophobic00:05:57

Are you distributing a jar or an executable built with native image?

Ingy döt Net17:05:36

@U7RJTCH6J from my mac

% otool -L rapidyaml/native/librapidyaml.dylib.0.6.0 
rapidyaml/native/librapidyaml.dylib.0.6.0:
	@rpath/librapidyaml.dylib (compatibility version 0.0.0, current version 0.0.0)
	/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1600.157.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1336.61.1)

phronmophobic17:05:41

Are you loading that specific version?

phronmophobic17:05:10

> I'm assuming you did (Native/loadLibrary "rapidyaml") or similar?

phronmophobic17:05:41

when you load the library, are you just passing the name "rapidyaml" or a specific version of rapidyaml?

phronmophobic17:05:12

what is otool -L rapidyaml/native/librapidyaml.dylib?

phronmophobic17:05:11

My guess is you're loading library without specifying a version (which is typical) and librapidyaml.dylib references librapidyaml.dylib.0.6.0 which can't be found.

Ingy döt Net17:05:41

note, this all works when using it as a JVM jar

Ingy döt Net17:05:25

just not as a native-image file

phronmophobic17:05:17

so you are loading a specific version

Ingy döt Net17:05:24

% YS_PARSER=rapidyaml ./ys/bin/ys -pe 42
Error: java.lang.RuntimeException: Shared library file librapidyaml.dylib.0.6.0 not found
{:eval ["42"], :debug-stage {}, :print true, :mode "code"}

Ingy döt Net17:05:54

that is the native-image (on the mac)

phronmophobic17:05:48

You should be able to print out the paths it searched and figure out where it's currently looking and where it's not looking that you would expect it to look.

Ingy döt Net17:05:47

2 failures with rapidyaml, but different when DYLD_LIBRARY_PATH set

Ingy döt Net17:05:52

wasn't expecting that

Ingy döt Net17:05:43

I'll try printing the path in the code you linked to

phronmophobic17:05:10

So it looks like you’ve written your own code for finding and loading libraries, which also uses jna’s code for finding and loading libraries.

phronmophobic17:05:22

I'm not sure about windows, but I think linux and osx require shared libs to be actual files on the file system. JNA has its own thing for extracting libs to a temp folder. It relies on resources at specific paths.

phronmophobic17:05:59

So you can probably include it as a resource, but you have to put it in the right subdirectory of the resource path.

Ingy döt Net17:05:14

where is that resource path?

phronmophobic17:05:45

I don't remember off the top of my head.

borkdude18:05:07

> I'm not sure about windows, but I think linux and osx require shared libs to be actual files on the file system. spire packages the shared libs in the native-image but writes them out to disk on startup

Ingy döt Net19:05:57

Interesting. Thanks for that.

Ingy döt Net04:05:47

@U7RJTCH6J this is a bit embarrassing but I've come full circle back to your original message in the thread. Google just led me to https://github.com/phronmophobic/jna-native-image :face_with_rolling_eyes: I'm out of tuits for the night but I think I can put that to good use in the morning. TBH, I don't think I would have understood enough about all this to try it when you first posted...

Ingy döt Net04:05:15

I've studied and experimented enough to feel pretty comfortable with the Java and JNA. I was coming to the conclusion that native-image needed the right persuasions here and that led me back to you.

phronmophobic04:05:31

that example expects that the library can be found through JNA natural library lookup. If you want to distribute a shared library, you'll have to either have it preinstalled where JNA expects or extract it somewhere that JNA can find it.

phronmophobic04:05:25

There are a lot of cool native libraries. Once everything is setup, it's pretty easy to use them from clojure, but the setup itself is unfortunately very complicated given the various platforms and tools.

phronmophobic18:05:08

oh, I guess cos isn't available in libc on linux. you can either use another libc function or change it to load libm instead.

Ingy döt Net18:05:08

I'll add a check for mac and load the right lib

Ingy döt Net18:05:30

if you like the PR

Ingy döt Net18:05:37

+ ./target/jna
cosine of 42 is -0.39998531498835127
🙂

jpmag18:05:21

yeah, cos is frequently on libm.so, and that would require explicit linking

phronmophobic18:05:52

ideally, there would be a function in libc that is easy to test and is included on both mac and linux

Ingy döt Net18:05:17

@U7RJTCH6J do you think you can make that code work with Native/load instead of NativeLibrary/getInstance ? That's what I'm really trying to figure out...

Ingy döt Net18:05:48

I like your very small example repo 🙂

phronmophobic18:05:50

probably. why do you want that?

phronmophobic18:05:11

If you've already loaded the library, you can just use NativeLibrary/getProcess instead of get instance.

Ingy döt Net18:05:43

Because that is what I have working fine with the JVM... I rewrote https://github.com/yaml/yamlscript/blob/rapidyaml/rapidyaml/src/main/java/org/rapidyaml/LibRapidyaml.java#L74-L96 to be much clearer and separate the code path for JVM (works) from native-image (does not work)

Ingy döt Net18:05:35

> f you've already loaded the library, you can just use NativeLibrary/getProcess instead of get instance. Problem is I can't load the library yet with a native image: https://gist.github.com/ingydotnet/0363ad5c0647d35169b6cbd45dede8f6

Ingy döt Net19:05:32

@U7RJTCH6J We are at the point where we'd like to add print debugging near https://github.com/java-native-access/jna/blob/master/src/com/sun/jna/NativeLibrary.java#L325 Do you know how one would do that? I can't find that jar on my system 😞

Ingy döt Net19:05:00

And if I did, wouldn't know how to edit a jar source...

Ingy döt Net19:05:16

Any help would be greatly appreciated

Ingy döt Net19:05:02

ha! we were just starting to look into logging (like 10 secs ago)