[jvm-packages] Fixing the NativeLibLoader on Java 9+ (#4351)
The old NativeLibLoader had a short-circuit load path which modified java.library.path and attempted to load the xgboost library from outside the jar first, falling back to loading the library from inside the jar. This path is a no-op every time when using XGBoost outside of it's source tree. Additionally it triggers an illegal reflective access warning in the module system in 9, 10, and 11. On Java 12 the ClassLoader fields are not accessible via reflection (separately from the illegal reflective acces warning), and so it fails in a way that isn't caught by the code which falls back to loading the library from inside the jar. This commit removes that code path and always loads the xgboost library from inside the jar file as it's a valid technique across multiple JVM implementations and works with all versions of Java.
This commit is contained in:
parent
956e73f183
commit
a448a8320c
@ -30,14 +30,19 @@ class NativeLibLoader {
|
|||||||
private static final Log logger = LogFactory.getLog(NativeLibLoader.class);
|
private static final Log logger = LogFactory.getLog(NativeLibLoader.class);
|
||||||
|
|
||||||
private static boolean initialized = false;
|
private static boolean initialized = false;
|
||||||
private static final String nativePath = "../../lib/";
|
|
||||||
private static final String nativeResourcePath = "/lib/";
|
private static final String nativeResourcePath = "/lib/";
|
||||||
private static final String[] libNames = new String[]{"xgboost4j"};
|
private static final String[] libNames = new String[]{"xgboost4j"};
|
||||||
|
|
||||||
static synchronized void initXGBoost() throws IOException {
|
static synchronized void initXGBoost() throws IOException {
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
for (String libName : libNames) {
|
for (String libName : libNames) {
|
||||||
smartLoad(libName);
|
try {
|
||||||
|
String libraryFromJar = nativeResourcePath + System.mapLibraryName(libName);
|
||||||
|
loadLibraryFromJar(libraryFromJar);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
logger.error("failed to load " + libName + " library from jar");
|
||||||
|
throw ioe;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
initialized = true;
|
initialized = true;
|
||||||
}
|
}
|
||||||
@ -135,54 +140,4 @@ class NativeLibLoader {
|
|||||||
return temp.getAbsolutePath();
|
return temp.getAbsolutePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* load native library, this method will first try to load library from java.library.path, then
|
|
||||||
* try to load library in jar package.
|
|
||||||
*
|
|
||||||
* @param libName library path
|
|
||||||
* @throws IOException exception
|
|
||||||
*/
|
|
||||||
private static void smartLoad(String libName) throws IOException {
|
|
||||||
addNativeDir(nativePath);
|
|
||||||
try {
|
|
||||||
System.loadLibrary(libName);
|
|
||||||
} catch (UnsatisfiedLinkError e) {
|
|
||||||
try {
|
|
||||||
String libraryFromJar = nativeResourcePath + System.mapLibraryName(libName);
|
|
||||||
loadLibraryFromJar(libraryFromJar);
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
logger.error("failed to load library from both native path and jar");
|
|
||||||
throw ioe;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add libPath to java.library.path, then native library in libPath would be load properly
|
|
||||||
*
|
|
||||||
* @param libPath library path
|
|
||||||
* @throws IOException exception
|
|
||||||
*/
|
|
||||||
private static void addNativeDir(String libPath) throws IOException {
|
|
||||||
try {
|
|
||||||
Field field = ClassLoader.class.getDeclaredField("usr_paths");
|
|
||||||
field.setAccessible(true);
|
|
||||||
String[] paths = (String[]) field.get(null);
|
|
||||||
for (String path : paths) {
|
|
||||||
if (libPath.equals(path)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String[] tmp = new String[paths.length + 1];
|
|
||||||
System.arraycopy(paths, 0, tmp, 0, paths.length);
|
|
||||||
tmp[paths.length] = libPath;
|
|
||||||
field.set(null, tmp);
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
logger.error(e.getMessage());
|
|
||||||
throw new IOException("Failed to get permissions to set library path");
|
|
||||||
} catch (NoSuchFieldException e) {
|
|
||||||
logger.error(e.getMessage());
|
|
||||||
throw new IOException("Failed to get field handle to set library path");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user