jnr / jnr-ffi

Java Abstracted Foreign Function Layer

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Feature Request: Check if library exists without loading it

basshelal opened this issue · comments

I mentioned this in a discussion here: #225

Would this feature be possible to add into JNR? I don't know how JNR finds and loads libraries so I'm not very literate on this matter.

The use case is if someone has their own library libfoo.so which depends on some optional libraries such as libjack.so, would it be possible to check whether libjack.so exists (ie, is loadable) without loading it such that I can notify users that libjack.so is missing without having to load my possibly large library much later on.

I tried two successful but inconvenient solutions (as mentioned in the discussion):

  1. Load the libraries with a minimal (single function) interface. JNR will load it and if it was found no exception will be thrown, else it wasn't found and a LinkageError is thrown. This actually loads the library though which can be quite expensive with large libraries but I could be wrong.
  2. Search for the library file across its default locations yourself. This is fast but could be error prone and requires the developer to tediously search through the known default paths (which differ by CPU even on the same OS). This doesn't cover any potential edge cases like possible custom library locations or something like that.

Again, I don't know if this is even possible or not but it would be a very useful addition.

Many thanks 😊

The loading logic for libraries does do some filesystem searching of its own, but it may be that it falls back on the JDK's own searching in the end rather than bailing out at that point. The logic for that is here:

https://github.com/jnr/jnr-ffi/blob/24c0aed3fa55117cef9311ab18881f135961bc2b/src/main/java/jnr/ffi/LibraryLoader.java

I am willing to entertain suggestions! Can you tell me why the current behavior is not doing what you need?

My main annoyance is that failure to locate a library will only happen at load time ie upon calling load() but there are cases where I want to know if a library will be found without loading it, because my library will depend on it but I want to load mine later.

I scoured through the code and I think I found what I was really looking for in LibraryLoader.StaticDataHolder.USER_LIBRARY_PATH.

This list seems to have everything I'm looking for, namely on Linux it adds all the paths in /etc/ld.so.conf and /etc/ld.so.conf.d/*.conf and it adds paths set by system properties in these lines here:

paths.addAll(getPropertyPaths("jnr.ffi.library.path"));
paths.addAll(getPropertyPaths("jaffl.library.path"));
// Add JNA paths for compatibility
paths.addAll(getPropertyPaths("jna.library.path"));
paths.addAll(getPropertyPaths("java.library.path"));

Those lines should probably add the default locations of libraries on Darwin and Windows but I have to check.

So a static function somewhere where callers can check if a library with a given name will be found in default paths plus optional custom paths is what I'm looking for, I drafted something below in Platform.java

// TODO basshelal need to test this, especially on Darwin & Windows!
public boolean canFindLibrary(String libraryName, List<String> libraryPaths) {
    ArrayList<String> paths = new ArrayList<>();
    if (libraryPaths != null) paths.addAll(libraryPaths);
    paths.addAll(LibraryLoader.StaticDataHolder.USER_LIBRARY_PATH);
    // below is probably incorrect!
    String found = Platform.getNativePlatform().locateLibrary(libraryName, paths);
    return found != null;
}

The above would need to increase access to LibraryLoader.StaticDataHolder.USER_LIBRARY_PATH from private to package.

I'll experiment some more and write some tests for this before I open a PR, but let me know if I'm completely off base so I don't waste time.

Cheers

Yes this is exactly what I was hoping for! I think it would be a good addition to add the filesystem searching as a public API.