Attempt to load versioned shared objects in Java

Since TensorFlow 1.14.0, libtensorflow_framework.so has been packaged as
a versioned shared object. This change attempts to support that naming
scheme in the Java NativeLibrary loader.

If libtensorflow_framework.so is not present and a major version number
can be determined, the loader will attempt to find
libtensorflow_framework.so.<majorVersion>, where <majorVersion> is
determined from the manifest of the JAR from which the NativeLibrary
class was loaded. On darwin, the loader will look for
libtensorflow_framework.<majorVersion>.so.

PiperOrigin-RevId: 260749010
This commit is contained in:
James Ring 2019-07-30 10:46:16 -07:00 committed by TensorFlower Gardener
parent af916f80c0
commit a4a4057748

View File

@ -65,7 +65,7 @@ final class NativeLibrary {
NativeLibrary.class.getClassLoader().getResourceAsStream(jniResourceName); NativeLibrary.class.getClassLoader().getResourceAsStream(jniResourceName);
// Extract the JNI's dependency // Extract the JNI's dependency
final String frameworkLibName = final String frameworkLibName =
maybeAdjustForMacOS(System.mapLibraryName("tensorflow_framework")); getVersionedLibraryName(System.mapLibraryName("tensorflow_framework"));
final String frameworkResourceName = makeResourceName(frameworkLibName); final String frameworkResourceName = makeResourceName(frameworkLibName);
log("frameworkResourceName: " + frameworkResourceName); log("frameworkResourceName: " + frameworkResourceName);
final InputStream frameworkResource = final InputStream frameworkResource =
@ -126,22 +126,66 @@ final class NativeLibrary {
} }
} }
private static String maybeAdjustForMacOS(String libFilename) { private static boolean resourceExists(String baseName) {
if (!System.getProperty("os.name").contains("OS X")) { return NativeLibrary.class.getClassLoader().getResource(makeResourceName(baseName)) != null;
}
private static String getVersionedLibraryName(String libFilename) {
// If the resource exists as an unversioned file, return that.
if (resourceExists(libFilename)) {
return libFilename; return libFilename;
} }
// This is macOS, and the TensorFlow release process might have setup dependencies on
// libtensorflow_framework.so instead of libtensorflow_framework.dylib. Adjust for that. final String versionName = getMajorVersionNumber();
final ClassLoader cl = NativeLibrary.class.getClassLoader();
if (cl.getResource(makeResourceName(libFilename)) != null) { // If we're on darwin, the versioned libraries look like blah.1.dylib.
final String darwinSuffix = ".dylib";
if (libFilename.endsWith(darwinSuffix)) {
final String prefix = libFilename.substring(0, libFilename.length() - darwinSuffix.length());
if (versionName != null) {
final String darwinVersionedLibrary = prefix + "." + versionName + darwinSuffix;
if (resourceExists(darwinVersionedLibrary)) {
return darwinVersionedLibrary;
}
} else {
// If we're here, we're on darwin, but we couldn't figure out the major version number. We
// already tried the library name without any changes, but let's do one final try for the
// library with a .so suffix.
final String darwinSoName = prefix + ".so";
if (resourceExists(darwinSoName)) {
return darwinSoName;
}
}
} else if (libFilename.endsWith(".so")) {
// Libraries ending in ".so" are versioned like "libfoo.so.1", so try that.
final String versionedSoName = libFilename + "." + versionName;
if (versionName != null && resourceExists(versionedSoName)) {
return versionedSoName;
}
}
// Otherwise, we've got no idea.
return libFilename; return libFilename;
} }
// liftensorflow_framework.dylib not found, try libtensorflow_framework.so
final String suffix = ".dylib"; /**
if (!libFilename.endsWith(suffix)) { * Returns the major version number of this TensorFlow Java API, or {@code null} if it cannot be
return libFilename; * determined.
*/
private static String getMajorVersionNumber() {
String version = NativeLibrary.class.getPackage().getImplementationVersion();
// expecting a string like 1.14.0, we want to get the first '1'.
int dotIndex;
if (version == null || (dotIndex = version.indexOf('.')) == -1) {
return null;
}
String majorVersion = version.substring(0, dotIndex);
try {
Integer.parseInt(majorVersion);
return majorVersion;
} catch (NumberFormatException unused) {
return null;
} }
return libFilename.substring(0, libFilename.length() - suffix.length()) + ".so";
} }
private static String extractResource( private static String extractResource(