gdx-jnigen
gdx-jnigen copied to clipboard
fix: Ensure to load resource with global class loader
Description
When gdx-jnigen-loader
is put on the module path (to be loaded as an automatically named module in JPMS), it cannot load any libraries in a separate JAR anymore. This patch contains a simple fix to hopefully make things work when gdx-jnigen-loader
is used as a named module.
Explanation
After Java 9, all classes are put within some modules. There are three kinds of modules:
- Unnamed modules: where classes from class path are put.
- Automatic modules: where classes from module path are put when the JAR doesn't explicitly declare a module.
- Explicitly declared modules.
With JPMS, Class#getResource
by default loads resources only
from the current module, making SharedLibraryLoader
malfunction,
whose purpose is to load libraries from other JARs (modules). In contrast, ClassLoader#getResource
tries to find resources from all loaded modules, which should be used instead to allow using jnigen
as an automatic module.
Reproducing Steps
Preparations
$ # The jnigen loader JAR
$ wget https://repo1.maven.org/maven2/com/badlogicgames/gdx/gdx-jnigen-loader/2.5.1/gdx-jnigen-loader-2.5.1.jar
$ # A JAR containing binaries built with jnigen
$ wget https://repo1.maven.org/maven2/party/iroiro/luajava/lua54-platform/3.5.0/lua54-platform-3.5.0-natives-desktop.jar
A Working Example
$ jshell --class-path lua54-platform-3.5.0-natives-desktop.jar:gdx-jnigen-loader-2.5.1.jar
jshell> import com.badlogic.gdx.utils.SharedLibraryLoader;
jshell> var loader = new SharedLibraryLoader();
jshell> loader.load("lua54");
jshell> // Library loaded with no exception thrown
A Failing One
$ jshell --module-path lua54-platform-3.5.0-natives-desktop.jar:gdx-jnigen-loader-2.5.1.jar --add-module gdx.jnigen.loader
jshell> import com.badlogic.gdx.utils.SharedLibraryLoader;
jshell> var loader = new SharedLibraryLoader();
jshell> loader.load("lua54");
| Exception com.badlogic.gdx.utils.SharedLibraryLoadRuntimeException: Couldn't load shared library 'liblua5464.so' for target: Linux, x86, 64-bit
| at SharedLibraryLoader.load (SharedLibraryLoader.java:174)
| at (#4:1)
| Caused by: com.badlogic.gdx.utils.SharedLibraryLoadRuntimeException: Unable to read file for extraction: liblua5464.so
| at SharedLibraryLoader.readFile (SharedLibraryLoader.java:183)
| at SharedLibraryLoader.loadFile (SharedLibraryLoader.java:339)
| at SharedLibraryLoader.load (SharedLibraryLoader.java:170)
| ...
Hi, thank you for the detailed description!
When reading up on the docs of ClassLoader#getResource
, I noticed the following:
Resources in named modules are subject to the encapsulation rules specified by Module.getResourceAsStream. Additionally, and except for the special case where the resource has a name ending with ".class", this method will only find resources in packages of named modules when the package is opened unconditionally (even if the caller of this method is in the same module as the resource).
(https://download.java.net/java/early_access/panama/docs/api/java.base/java/lang/ClassLoader.html)
I'm not really familiar with java modules, so I'm not sure about the implication of this. But I think we should be unaffected, since all resources are in the root directory?
I couldn't find any info on resources in root directories of modules, but they indeed seem opened when testing with the following setup.
+- module-info.java -> exports only b.c
+- b/
| +- c/
| | +- C.class
| | \- C.txt -> accessible
| |
| +- B.class
| \- B.txt -> inaccessible
|
\- A.txt -> accessible!!
But I don't think it will be a problem anyway. The JAR generated by the Ant pack-native
task does not contain module-info.java
, which means the JAR for binaries will never be an explicitly declared module, unless the user manually rebundles. (The other two categories, i.e., unnamed modules and automatic modules, simply open every package.)