All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.jna.NativeLibrary Maven / Gradle / Ivy

There is a newer version: 5.14.0
Show newest version
/* Copyright (c) 2007 Wayne Meissner, All Rights Reserved
 * Copyright (c) 2007-2013 Timothy Wall, All Rights Reserved
 *
 * The contents of this file is dual-licensed under 2
 * alternative Open Source/Free licenses: LGPL 2.1 or later and
 * Apache License 2.0. (starting with JNA version 4.0.0).
 *
 * You can freely decide which license you want to apply to
 * the project.
 *
 * You may obtain a copy of the LGPL License at:
 *
 * http://www.gnu.org/licenses/licenses.html
 *
 * A copy is also included in the downloadable source code package
 * containing JNA, in file "LGPL2.1".
 *
 * You may obtain a copy of the Apache License at:
 *
 * http://www.apache.org/licenses/
 *
 * A copy is also included in the downloadable source code package
 * containing JNA, in file "AL2.0".
 */

package com.sun.jna;

import static com.sun.jna.Native.DEBUG_LOAD;
import java.io.BufferedReader;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Provides management of native library resources.  One instance of this
 * class corresponds to a single loaded native library.  May also be used
 * to map to the current process (see {@link NativeLibrary#getProcess()}).
 * 

* * Library Search Paths * A search for a given library will scan the following locations: *

    *
  1. jna.library.path User-customizable path *
  2. jna.platform.library.path Platform-specific paths *
  3. On OSX, ~/Library/Frameworks, * /Library/Frameworks, and * /System/Library/Frameworks will be searched for a framework * with a name corresponding to that requested. Absolute paths to frameworks * are also accepted, either ending at the framework name (sans ".framework") * or the full path to the framework shared library * (e.g. CoreServices.framework/CoreServices). *
  4. Context class loader classpath. Deployed native libraries may be * installed on the classpath under * ${os-prefix}/LIBRARY_FILENAME, where ${os-prefix} * is the OS/Arch prefix returned by {@link * Platform#getNativeLibraryResourcePrefix()}. If bundled in a jar file, the * resource will be extracted to jna.tmpdir for loading, and * later removed (but only if jna.nounpack is false or not set). *
* You may set the system property jna.debug_load=true to make * JNA print the steps of its library search to the console. * @author Wayne Meissner, split library loading from Function.java * @author twall */ public class NativeLibrary { private static final Logger LOG = Logger.getLogger(NativeLibrary.class.getName()); private final static Level DEBUG_LOAD_LEVEL = DEBUG_LOAD ? Level.INFO : Level.FINE; private long handle; private final String libraryName; private final String libraryPath; private final Map functions = new HashMap(); final int callFlags; private String encoding; final Map options; private static final Map> libraries = new HashMap>(); private static final Map> searchPaths = Collections.synchronizedMap(new HashMap>()); private static final List librarySearchPath = new ArrayList(); static { // Force initialization of native library if (Native.POINTER_SIZE == 0) throw new Error("Native library not initialized"); } private static String functionKey(String name, int flags, String encoding) { return name + "|" + flags + "|" + encoding; } private NativeLibrary(String libraryName, String libraryPath, long handle, Map options) { this.libraryName = getLibraryName(libraryName); this.libraryPath = libraryPath; this.handle = handle; Object option = options.get(Library.OPTION_CALLING_CONVENTION); int callingConvention = option instanceof Number ? ((Number)option).intValue() : Function.C_CONVENTION; this.callFlags = callingConvention; this.options = options; this.encoding = (String)options.get(Library.OPTION_STRING_ENCODING); if (this.encoding == null) { this.encoding = Native.getDefaultStringEncoding(); } // Special workaround for w32 kernel32.GetLastError // Short-circuit the function to use built-in GetLastError access if (Platform.isWindows() && "kernel32".equals(this.libraryName.toLowerCase())) { synchronized(functions) { Function f = new Function(this, "GetLastError", Function.ALT_CONVENTION, encoding) { @Override Object invoke(Object[] args, Class returnType, boolean b, int fixedArgs) { return Integer.valueOf(Native.getLastError()); } @Override Object invoke(Method invokingMethod, Class[] paramTypes, Class returnType, Object[] inArgs, Map options) { return Integer.valueOf(Native.getLastError()); } }; functions.put(functionKey("GetLastError", callFlags, encoding), f); } } } private static final int DEFAULT_OPEN_OPTIONS = -1; private static int openFlags(Map options) { Object opt = options.get(Library.OPTION_OPEN_FLAGS); if (opt instanceof Number) { return ((Number)opt).intValue(); } return DEFAULT_OPEN_OPTIONS; } private static NativeLibrary loadLibrary(String libraryName, Map options) { LOG.log(DEBUG_LOAD_LEVEL, "Looking for library '" + libraryName + "'"); List exceptions = new ArrayList(); boolean isAbsolutePath = new File(libraryName).isAbsolute(); List searchPath = new ArrayList(); int openFlags = openFlags(options); // Append web start path, if available. Note that this does not // attempt any library name variations String webstartPath = Native.getWebStartLibraryPath(libraryName); if (webstartPath != null) { LOG.log(DEBUG_LOAD_LEVEL, "Adding web start path " + webstartPath); searchPath.add(webstartPath); } // // Prepend any custom search paths specifically for this library // List customPaths = searchPaths.get(libraryName); if (customPaths != null) { synchronized (customPaths) { searchPath.addAll(0, customPaths); } } LOG.log(DEBUG_LOAD_LEVEL, "Adding paths from jna.library.path: " + System.getProperty("jna.library.path")); searchPath.addAll(initPaths("jna.library.path")); String libraryPath = findLibraryPath(libraryName, searchPath); long handle = 0; // // Only search user specified paths first. This will also fall back // to dlopen/LoadLibrary() since findLibraryPath returns the mapped // name if it cannot find the library. // try { LOG.log(DEBUG_LOAD_LEVEL, "Trying " + libraryPath); handle = Native.open(libraryPath, openFlags); } catch(UnsatisfiedLinkError e) { // Add the system paths back for all fallback searching LOG.log(DEBUG_LOAD_LEVEL, "Loading failed with message: " + e.getMessage()); LOG.log(DEBUG_LOAD_LEVEL, "Adding system paths: " + librarySearchPath); exceptions.add(e); searchPath.addAll(librarySearchPath); } try { if (handle == 0) { libraryPath = findLibraryPath(libraryName, searchPath); LOG.log(DEBUG_LOAD_LEVEL, "Trying " + libraryPath); handle = Native.open(libraryPath, openFlags); if (handle == 0) { throw new UnsatisfiedLinkError("Failed to load library '" + libraryName + "'"); } } } catch(UnsatisfiedLinkError ule) { LOG.log(DEBUG_LOAD_LEVEL, "Loading failed with message: " + ule.getMessage()); exceptions.add(ule); // For android, try to "preload" the library using // System.loadLibrary(), which looks into the private /data/data // path, not found in any properties if (Platform.isAndroid()) { try { LOG.log(DEBUG_LOAD_LEVEL, "Preload (via System.loadLibrary) " + libraryName); System.loadLibrary(libraryName); handle = Native.open(libraryPath, openFlags); } catch(UnsatisfiedLinkError e2) { LOG.log(DEBUG_LOAD_LEVEL, "Loading failed with message: " + e2.getMessage()); exceptions.add(e2); } } else if (Platform.isLinux() || Platform.isFreeBSD()) { // // Failed to load the library normally - try to match libfoo.so.* // LOG.log(DEBUG_LOAD_LEVEL, "Looking for version variants"); libraryPath = matchLibrary(libraryName, searchPath); if (libraryPath != null) { LOG.log(DEBUG_LOAD_LEVEL, "Trying " + libraryPath); try { handle = Native.open(libraryPath, openFlags); } catch(UnsatisfiedLinkError e2) { LOG.log(DEBUG_LOAD_LEVEL, "Loading failed with message: " + e2.getMessage()); exceptions.add(e2); } } } // Search framework libraries on OS X else if (Platform.isMac() && !libraryName.endsWith(".dylib")) { LOG.log(DEBUG_LOAD_LEVEL, "Looking for matching frameworks"); libraryPath = matchFramework(libraryName); if (libraryPath != null) { try { LOG.log(DEBUG_LOAD_LEVEL, "Trying " + libraryPath); handle = Native.open(libraryPath, openFlags); } catch(UnsatisfiedLinkError e2) { LOG.log(DEBUG_LOAD_LEVEL, "Loading failed with message: " + e2.getMessage()); exceptions.add(e2); } } } // Try the same library with a "lib" prefix else if (Platform.isWindows() && !isAbsolutePath) { LOG.log(DEBUG_LOAD_LEVEL, "Looking for lib- prefix"); libraryPath = findLibraryPath("lib" + libraryName, searchPath); if (libraryPath != null) { LOG.log(DEBUG_LOAD_LEVEL, "Trying " + libraryPath); try { handle = Native.open(libraryPath, openFlags); } catch(UnsatisfiedLinkError e2) { LOG.log(DEBUG_LOAD_LEVEL, "Loading failed with message: " + e2.getMessage()); exceptions.add(e2); } } } // As a last resort, try to extract the library from the class // path, using the current context class loader. if (handle == 0) { try { File embedded = Native.extractFromResourcePath(libraryName, (ClassLoader)options.get(Library.OPTION_CLASSLOADER)); try { handle = Native.open(embedded.getAbsolutePath(), openFlags); libraryPath = embedded.getAbsolutePath(); } finally { // Don't leave temporary files around if (Native.isUnpacked(embedded)) { Native.deleteLibrary(embedded); } } } catch(IOException e2) { LOG.log(DEBUG_LOAD_LEVEL, "Loading failed with message: " + e2.getMessage()); exceptions.add(e2); } } if (handle == 0) { StringBuilder sb = new StringBuilder(); sb.append("Unable to load library '"); sb.append(libraryName); sb.append("':"); for(Throwable t: exceptions) { sb.append("\n"); sb.append(t.getMessage()); } UnsatisfiedLinkError res = new UnsatisfiedLinkError(sb.toString()); for(Throwable t: exceptions) { addSuppressedReflected(res, t); } throw res; } } LOG.log(DEBUG_LOAD_LEVEL, "Found library '" + libraryName + "' at " + libraryPath); return new NativeLibrary(libraryName, libraryPath, handle, options); } private static Method addSuppressedMethod = null; static { try { addSuppressedMethod = Throwable.class.getMethod("addSuppressed", Throwable.class); } catch (NoSuchMethodException ex) { // This is the case for JDK < 7 } catch (SecurityException ex) { Logger.getLogger(NativeLibrary.class.getName()).log(Level.SEVERE, "Failed to initialize 'addSuppressed' method", ex); } } private static void addSuppressedReflected(Throwable target, Throwable suppressed) { if(addSuppressedMethod == null) { // Make this a NOOP on an unsupported JDK return; } try { addSuppressedMethod.invoke(target, suppressed); } catch (IllegalAccessException ex) { throw new RuntimeException("Failed to call addSuppressedMethod", ex); } catch (IllegalArgumentException ex) { throw new RuntimeException("Failed to call addSuppressedMethod", ex); } catch (InvocationTargetException ex) { throw new RuntimeException("Failed to call addSuppressedMethod", ex); } } /** Look for a matching framework (OSX) */ static String matchFramework(String libraryName) { File framework = new File(libraryName); if (framework.isAbsolute()) { if (libraryName.indexOf(".framework") != -1 && framework.exists()) { return framework.getAbsolutePath(); } framework = new File(new File(framework.getParentFile(), framework.getName() + ".framework"), framework.getName()); if (framework.exists()) { return framework.getAbsolutePath(); } } else { final String[] PREFIXES = { System.getProperty("user.home"), "", "/System" }; String suffix = libraryName.indexOf(".framework") == -1 ? libraryName + ".framework/" + libraryName : libraryName; for (int i=0;i < PREFIXES.length;i++) { String libraryPath = PREFIXES[i] + "/Library/Frameworks/" + suffix; if (new File(libraryPath).exists()) { return libraryPath; } } } return null; } private String getLibraryName(String libraryName) { String simplified = libraryName; final String BASE = "---"; String template = mapSharedLibraryName(BASE); int prefixEnd = template.indexOf(BASE); if (prefixEnd > 0 && simplified.startsWith(template.substring(0, prefixEnd))) { simplified = simplified.substring(prefixEnd); } String suffix = template.substring(prefixEnd + BASE.length()); int suffixStart = simplified.indexOf(suffix); if (suffixStart != -1) { simplified = simplified.substring(0, suffixStart); } return simplified; } /** * Returns an instance of NativeLibrary for the specified name. * The library is loaded if not already loaded. If already loaded, the * existing instance is returned.

* More than one name may map to the same NativeLibrary instance; only * a single instance will be provided for any given unique file path. * * @param libraryName The library name to load. * This can be short form (e.g. "c"), * an explicit version (e.g. "libc.so.6"), or * the full path to the library (e.g. "/lib/libc.so.6"). */ public static final NativeLibrary getInstance(String libraryName) { return getInstance(libraryName, Collections.emptyMap()); } /** * Returns an instance of NativeLibrary for the specified name. * The library is loaded if not already loaded. If already loaded, the * existing instance is returned.

* More than one name may map to the same NativeLibrary instance; only * a single instance will be provided for any given unique file path. * * @param libraryName The library name to load. * This can be short form (e.g. "c"), * an explicit version (e.g. "libc.so.6"), or * the full path to the library (e.g. "/lib/libc.so.6"). * @param classLoader The class loader to use to load the native library. * This only affects library loading when the native library is * included somewhere in the classpath, either bundled in a jar file * or as a plain file within the classpath. */ public static final NativeLibrary getInstance(String libraryName, ClassLoader classLoader) { return getInstance(libraryName, Collections.singletonMap(Library.OPTION_CLASSLOADER, classLoader)); } /** * Returns an instance of NativeLibrary for the specified name. * The library is loaded if not already loaded. If already loaded, the * existing instance is returned.

* More than one name may map to the same NativeLibrary instance; only * a single instance will be provided for any given unique file path. * * @param libraryName The library name to load. * This can be short form (e.g. "c"), * an explicit version (e.g. "libc.so.6" or * "QuickTime.framework/Versions/Current/QuickTime"), or * the full (absolute) path to the library (e.g. "/lib/libc.so.6"). * @param libraryOptions Native library options for the given library (see {@link Library}). */ public static final NativeLibrary getInstance(String libraryName, Map libraryOptions) { Map options = new HashMap(libraryOptions); if (options.get(Library.OPTION_CALLING_CONVENTION) == null) { options.put(Library.OPTION_CALLING_CONVENTION, Integer.valueOf(Function.C_CONVENTION)); } // Use current process to load libraries we know are already // loaded by the VM to ensure we get the correct version if ((Platform.isLinux() || Platform.isFreeBSD() || Platform.isAIX()) && Platform.C_LIBRARY_NAME.equals(libraryName)) { libraryName = null; } synchronized (libraries) { Reference ref = libraries.get(libraryName + options); NativeLibrary library = (ref != null) ? ref.get() : null; if (library == null) { if (libraryName == null) { library = new NativeLibrary("", null, Native.open(null, openFlags(options)), options); } else { library = loadLibrary(libraryName, options); } ref = new WeakReference(library); libraries.put(library.getName() + options, ref); File file = library.getFile(); if (file != null) { libraries.put(file.getAbsolutePath() + options, ref); libraries.put(file.getName() + options, ref); } } return library; } } /** * Returns an instance of NativeLibrary which refers to the current * process. This is useful for accessing functions which were already * mapped by some other mechanism, without having to reference or even * know the exact name of the native library. */ public static synchronized final NativeLibrary getProcess() { return getInstance(null); } /** * Returns an instance of NativeLibrary which refers to the current * process. This is useful for accessing functions which were already * mapped by some other mechanism, without having to reference or even * know the exact name of the native library. */ public static synchronized final NativeLibrary getProcess(Map options) { return getInstance(null, options); } /** * Add a path to search for the specified library, ahead of any system * paths. This is similar to setting jna.library.path, but * only extends the search path for a single library. * * @param libraryName The name of the library to use the path for * @param path The path to use when trying to load the library */ public static final void addSearchPath(String libraryName, String path) { synchronized (searchPaths) { List customPaths = searchPaths.get(libraryName); if (customPaths == null) { customPaths = Collections.synchronizedList(new ArrayList()); searchPaths.put(libraryName, customPaths); } customPaths.add(path); } } /** * Create a new {@link Function} that is linked with a native * function that follows the NativeLibrary's calling convention. * *

The allocated instance represents a pointer to the named native * function from the library. * * @param functionName * Name of the native function to be linked with * @throws UnsatisfiedLinkError if the function is not found */ public Function getFunction(String functionName) { return getFunction(functionName, callFlags); } /** * Create a new {@link Function} that is linked with a native * function that follows the NativeLibrary's calling convention. * *

The allocated instance represents a pointer to the named native * function from the library. * * @param name * Name of the native function to be linked with. Uses a * function mapper option if one was provided to * transform the name. * @param method * Method to which the native function is to be mapped * @throws UnsatisfiedLinkError if the function is not found */ Function getFunction(String name, Method method) { FunctionMapper mapper = (FunctionMapper) options.get(Library.OPTION_FUNCTION_MAPPER); if (mapper != null) { name = mapper.getFunctionName(this, method); } // If there's native method profiler prefix, strip it String prefix = System.getProperty("jna.profiler.prefix", "$$YJP$$"); if (name.startsWith(prefix)) { name = name.substring(prefix.length()); } int flags = this.callFlags; Class[] etypes = method.getExceptionTypes(); for (int i=0;i < etypes.length;i++) { if (LastErrorException.class.isAssignableFrom(etypes[i])) { flags |= Function.THROW_LAST_ERROR; } } return getFunction(name, flags); } /** * Create a new {@link Function} that is linked with a native * function that follows a given calling flags. * * @param functionName * Name of the native function to be linked with * @param callFlags * Flags affecting the function invocation * @throws UnsatisfiedLinkError if the function is not found */ public Function getFunction(String functionName, int callFlags) { return getFunction(functionName, callFlags, encoding); } /** * Create a new {@link Function} that is linked with a native * function that follows a given calling flags. * * @param functionName * Name of the native function to be linked with * @param callFlags * Flags affecting the function invocation * @param encoding * Encoding to use to convert between Java and native * strings. * @throws UnsatisfiedLinkError if the function is not found */ public Function getFunction(String functionName, int callFlags, String encoding) { if (functionName == null) { throw new NullPointerException("Function name may not be null"); } synchronized (functions) { String key = functionKey(functionName, callFlags, encoding); Function function = functions.get(key); if (function == null) { function = new Function(this, functionName, callFlags, encoding); functions.put(key, function); } return function; } } /** @return this native library instance's options. */ public Map getOptions() { return options; } /** Look up the given global variable within this library. * @param symbolName * @return Pointer representing the global variable address * @throws UnsatisfiedLinkError if the symbol is not found */ public Pointer getGlobalVariableAddress(String symbolName) { try { return new Pointer(getSymbolAddress(symbolName)); } catch(UnsatisfiedLinkError e) { throw new UnsatisfiedLinkError("Error looking up '" + symbolName + "': " + e.getMessage()); } } /** * Used by the Function class to locate a symbol * @throws UnsatisfiedLinkError if the symbol can't be found */ long getSymbolAddress(String name) { if (handle == 0) { throw new UnsatisfiedLinkError("Library has been unloaded"); } return Native.findSymbol(handle, name); } @Override public String toString() { return "Native Library <" + libraryPath + "@" + handle + ">"; } /** Returns the simple name of this library. */ public String getName() { return libraryName; } /** * Returns the file on disk corresponding to this NativeLibrary instance. * If this NativeLibrary represents the current process, this function will return null. */ public File getFile() { if (libraryPath == null) return null; return new File(libraryPath); } /** Close the library when it is no longer referenced. */ @Override protected void finalize() { dispose(); } /** Close all open native libraries. */ static void disposeAll() { Set> values; synchronized(libraries) { values = new LinkedHashSet>(libraries.values()); } for (Reference ref : values) { NativeLibrary lib = ref.get(); if (lib != null) { lib.dispose(); } } } /** Close the native library we're mapped to. */ public void dispose() { Set keys = new HashSet(); synchronized(libraries) { for (Map.Entry> e : libraries.entrySet()) { Reference ref = e.getValue(); if (ref.get() == this) { keys.add(e.getKey()); } } for (String k : keys) { libraries.remove(k); } } synchronized(this) { if (handle != 0) { Native.close(handle); handle = 0; } } } private static List initPaths(String key) { String value = System.getProperty(key, ""); if ("".equals(value)) { return Collections.emptyList(); } StringTokenizer st = new StringTokenizer(value, File.pathSeparator); List list = new ArrayList(); while (st.hasMoreTokens()) { String path = st.nextToken(); if (!"".equals(path)) { list.add(path); } } return list; } /** Use standard library search paths to find the library. */ private static String findLibraryPath(String libName, List searchPath) { // // If a full path to the library was specified, don't search for it // if (new File(libName).isAbsolute()) { return libName; } // // Get the system name for the library (e.g. libfoo.so) // String name = mapSharedLibraryName(libName); // Search in the JNA paths for it for (String path : searchPath) { File file = new File(path, name); if (file.exists()) { return file.getAbsolutePath(); } if (Platform.isMac()) { // Native libraries delivered via JNLP class loader // may require a .jnilib extension to be found if (name.endsWith(".dylib")) { file = new File(path, name.substring(0, name.lastIndexOf(".dylib")) + ".jnilib"); if (file.exists()) { return file.getAbsolutePath(); } } } } // // Default to returning the mapped library name and letting the system // search for it // return name; } /** Similar to {@link System#mapLibraryName}, except that it maps to standard shared library formats rather than specifically JNI formats. @param libName base (undecorated) name of library */ static String mapSharedLibraryName(String libName) { if (Platform.isMac()) { if (libName.startsWith("lib") && (libName.endsWith(".dylib") || libName.endsWith(".jnilib"))) { return libName; } String name = System.mapLibraryName(libName); // On MacOSX, System.mapLibraryName() returns the .jnilib extension // (the suffix for JNI libraries); ordinarily shared libraries have // a .dylib suffix if (name.endsWith(".jnilib")) { return name.substring(0, name.lastIndexOf(".jnilib")) + ".dylib"; } return name; } else if (Platform.isLinux() || Platform.isFreeBSD()) { if (isVersionedName(libName) || libName.endsWith(".so")) { // A specific version was requested - use as is for search return libName; } } else if (Platform.isAIX()) { // can be libx.a, libx.a(shr.o), libx.so if (libName.startsWith("lib")) { return libName; } } else if (Platform.isWindows()) { if (libName.endsWith(".drv") || libName.endsWith(".dll") || libName.endsWith(".ocx")) { return libName; } } return System.mapLibraryName(libName); } private static boolean isVersionedName(String name) { if (name.startsWith("lib")) { int so = name.lastIndexOf(".so."); if (so != -1 && so + 4 < name.length()) { for (int i=so+4;i < name.length();i++) { char ch = name.charAt(i); if (!Character.isDigit(ch) && ch != '.') { return false; } } return true; } } return false; } /** * matchLibrary() is very Linux specific. It is here to deal with the case * where /usr/lib/libc.so does not exist, or it is not a valid symlink to * a versioned file (e.g. /lib/libc.so.6). */ static String matchLibrary(final String libName, List searchPath) { File lib = new File(libName); if (lib.isAbsolute()) { searchPath = Arrays.asList(lib.getParent()); } FilenameFilter filter = new FilenameFilter() { @Override public boolean accept(File dir, String filename) { return (filename.startsWith("lib" + libName + ".so") || (filename.startsWith(libName + ".so") && libName.startsWith("lib"))) && isVersionedName(filename); } }; Collection matches = new LinkedList(); for (String path : searchPath) { File[] files = new File(path).listFiles(filter); if (files != null && files.length > 0) { matches.addAll(Arrays.asList(files)); } } // // Search through the results and return the highest numbered version // i.e. libc.so.6 is preferred over libc.so.5 double bestVersion = -1; String bestMatch = null; for (File f : matches) { String path = f.getAbsolutePath(); String ver = path.substring(path.lastIndexOf(".so.") + 4); double version = parseVersion(ver); if (version > bestVersion) { bestVersion = version; bestMatch = path; } } return bestMatch; } static double parseVersion(String ver) { double v = 0; double divisor = 1; int dot = ver.indexOf("."); while (ver != null) { String num; if (dot != -1) { num = ver.substring(0, dot); ver = ver.substring(dot + 1); dot = ver.indexOf("."); } else { num = ver; ver = null; } try { v += Integer.parseInt(num) / divisor; } catch(NumberFormatException e) { return 0; } divisor *= 100; } return v; } static { String webstartPath = Native.getWebStartLibraryPath("jnidispatch"); if (webstartPath != null) { librarySearchPath.add(webstartPath); } if (System.getProperty("jna.platform.library.path") == null && !Platform.isWindows()) { // Add default path lookups for unix-like systems String platformPath = ""; String sep = ""; String archPath = ""; // // Search first for an arch specific path if one exists, but always // include the generic paths if they exist. // NOTES (wmeissner): // Some older linux amd64 distros did not have /usr/lib64, and // 32bit distros only have /usr/lib. FreeBSD also only has // /usr/lib by default, with /usr/lib32 for 32bit compat. // Solaris seems to have both, but defaults to 32bit userland even // on 64bit machines, so we have to explicitly search the 64bit // one when running a 64bit JVM. // if (Platform.isLinux() || Platform.isSolaris() || Platform.isFreeBSD() || Platform.iskFreeBSD()) { // Linux & FreeBSD use /usr/lib32, solaris uses /usr/lib/32 archPath = (Platform.isSolaris() ? "/" : "") + Native.POINTER_SIZE * 8; } String[] paths = { "/usr/lib" + archPath, "/lib" + archPath, "/usr/lib", "/lib", }; // Multi-arch support on Ubuntu (and other // multi-arch distributions) // paths is scanned against real directory // so for platforms which are not multi-arch // this should continue to work. if (Platform.isLinux() || Platform.iskFreeBSD() || Platform.isGNU()) { String multiArchPath = getMultiArchPath(); // Assemble path with all possible options paths = new String[] { "/usr/lib/" + multiArchPath, "/lib/" + multiArchPath, "/usr/lib" + archPath, "/lib" + archPath, "/usr/lib", "/lib", }; } // We might be wrong with the multiArchPath above. Raspbian, // the Raspberry Pi flavor of Debian, for example, uses // uses arm-linux-gnuabihf since it's using the hard-float // ABI for armv6. Other distributions might use a different // tuple for the same thing. Query ldconfig to get the additional // library paths it knows about. if (Platform.isLinux()) { ArrayList ldPaths = getLinuxLdPaths(); // prepend the paths we already have for (int i=paths.length-1; 0 <= i; i--) { int found = ldPaths.indexOf(paths[i]); if (found != -1) { ldPaths.remove(found); } ldPaths.add(0, paths[i]); } paths = ldPaths.toArray(new String[0]); } for (int i=0;i < paths.length;i++) { File dir = new File(paths[i]); if (dir.exists() && dir.isDirectory()) { platformPath += sep + paths[i]; sep = File.pathSeparator; } } if (!"".equals(platformPath)) { System.setProperty("jna.platform.library.path", platformPath); } } librarySearchPath.addAll(initPaths("jna.platform.library.path")); } private static String getMultiArchPath() { String cpu = Platform.ARCH; String kernel = Platform.iskFreeBSD() ? "-kfreebsd" : (Platform.isGNU() ? "" : "-linux"); String libc = "-gnu"; if (Platform.isIntel()) { cpu = (Platform.is64Bit() ? "x86_64" : "i386"); } else if (Platform.isPPC()) { cpu = (Platform.is64Bit() ? "powerpc64" : "powerpc"); } else if (Platform.isARM()) { cpu = "arm"; libc = "-gnueabi"; } else if (Platform.ARCH.equals("mips64el")) { libc = "-gnuabi64"; } return cpu + kernel + libc; } /** * Get the library paths from ldconfig cache. Tested against ldconfig 2.13. */ private static ArrayList getLinuxLdPaths() { ArrayList ldPaths = new ArrayList(); BufferedReader reader = null; try { Process process = Runtime.getRuntime().exec("/sbin/ldconfig -p"); reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String buffer; while ((buffer = reader.readLine()) != null) { int startPath = buffer.indexOf(" => "); int endPath = buffer.lastIndexOf('/'); if (startPath != -1 && endPath != -1 && startPath < endPath) { String path = buffer.substring(startPath + 4, endPath); if (!ldPaths.contains(path)) { ldPaths.add(path); } } } } catch (Exception e) { } finally { if(reader != null) { try { reader.close(); } catch (IOException e) { } } } return ldPaths; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy