System.loadLibrary and CLinker.lookup exception

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Wed Apr 27 08:35:31 UTC 2022


Late to this thread.

Just wanted to provide some background here.

The way to search library symbols in Panama is via a SymbolLookup.

So, in SymbolLookup you will find (e.g. in the preview version of the 
API), different ways to obtain a lookup and get started:

1) loader lookup: this searches for symbols in all libraries loaded with 
System.load/loadLibrary _by the current class loader_. Does not allow 
for same library to be loaded in multiple loaders.
2) libraryLookup(Path/String): this loads a library, searches symbols in 
it. When the associated scope is closed, the library is unloaded. Allows 
same library to be loaded in multiple loaders.
3) system lookup - this is currently exposed by CLinker itself, which 
implements SymbolLookup. The idea behind this being an instance method 
in CLinker is that different linkers might expose different "standard" 
libraries.

I think the confusion in this thread, as pointed out by Radoslaw is 
caused by the fact that (3) is defined in a slightly asymmetric way - 
e.g. it is not a factory in SymbolLookup. Being an instance method in 
CLinker, it seems like it can cause developers to completely overlook 
SymbolLookup altogether. I'll think about this (we did some back and 
forth on this, also related to the naming of methods in the CLinker 
class itself, which are now resolved).

As to why we have multiple ways to lookup symbols (e.g. compared to 
Python) the reason is that Panama is not the first mechanism to 
introduce a concept of library loading in the JDK. Before Panama there 
was JNI - with its own library loading mechanics. The methods in (1) 
allow an application written using JNI loading mechanism to migrate to 
use the CLinker instead. Of course if you are writing code from scatch, 
and just need a dlopen replacement in Java, you should just look at (2).

Maurizio


On 26/04/2022 11:39, Jack Andrews wrote:
> hi - i'm getting used to FFI in JDK 18. any help with the following problem
> is much appreciated.
>
> I have a C function `kinit` in libk.so:
> $ nm -D ./libk.so |grep kinit
> 00000000000296f0 T kinit
>
> $ java --version
> openjdk 18.0.1 2022-04-19
> OpenJDK Runtime Environment (build 18.0.1+10-24)
> OpenJDK 64-Bit Server VM (build 18.0.1+10-24, mixed mode, sharing)
>
> $ cat Example.java
> import jdk.incubator.foreign.*;
> import java.lang.invoke.*;
> import static jdk.incubator.foreign.ValueLayout.*;
>
> public class Example {
>
>      static CLinker LINKER = CLinker.systemCLinker();
>
>      public static void main(String[] args) throws Throwable {
>          System.loadLibrary("k");
>          kinit();
>      }
>
>      public static void kinit() throws Throwable {
>          MethodHandle kinit = LINKER.downcallHandle(
>    /* LINE 16 */ LINKER.lookup("kinit").get(),
>                  FunctionDescriptor.of(JAVA_INT)
>          );
>
>          {
>              int r = (int) kinit.invoke();
>              System.out.println(r);
>          }
>      }
> }
>
> my code appears to load libk.so, but fails to find kinit:
>
> $ LD_LIBRARY_PATH=. java --add-modules jdk.incubator.foreign
> --enable-native-access=ALL-UNNAMED Example.java
> WARNING: Using incubator modules: jdk.incubator.foreign
> warning: using incubating module(s): jdk.incubator.foreign
> 1 warning
> Exception in thread "main" java.util.NoSuchElementException: No value
> present
> at java.base/java.util.Optional.get(Optional.java:143)
> at Example.kinit(Example.java:16)
> at Example.main(Example.java:11)
>
> best,
> jack


More information about the panama-dev mailing list