30package com.jogamp.common.os;
33import java.io.IOException;
34import java.lang.reflect.Method;
35import java.net.URISyntaxException;
36import java.security.PrivilegedAction;
37import java.util.ArrayList;
38import java.util.Arrays;
39import java.util.Iterator;
41import java.util.StringTokenizer;
43import jogamp.common.os.BionicDynamicLinker32bitImpl;
44import jogamp.common.os.BionicDynamicLinker64BitImpl;
45import jogamp.common.os.MacOSXDynamicLinkerImpl;
46import jogamp.common.os.PlatformPropsImpl;
47import jogamp.common.os.PosixDynamicLinkerImpl;
48import jogamp.common.os.WindowsDynamicLinkerImpl;
50import com.jogamp.common.ExceptionUtils;
51import com.jogamp.common.util.IOUtil;
52import com.jogamp.common.util.SecurityUtil;
53import com.jogamp.common.util.cache.TempJarCache;
69 private static final String[] prefixes;
70 private static final String[] suffixes;
71 private static final boolean isOSX;
72 private static String sys_env_lib_path_varname;
76 switch (PlatformPropsImpl.OS_TYPE) {
78 prefixes =
new String[] {
"" };
79 suffixes =
new String[] {
".dll" };
80 sys_env_lib_path_varname =
"PATH";
86 prefixes =
new String[] {
"lib" };
87 suffixes =
new String[] {
".dylib" };
88 sys_env_lib_path_varname =
"DYLD_LIBRARY_PATH";
100 prefixes =
new String[] {
"lib" };
101 suffixes =
new String[] {
".so" };
102 sys_env_lib_path_varname =
"LD_LIBRARY_PATH";
113 private long libraryHandle;
116 private final String libraryPath;
119 private final String nativeLibraryPath;
121 private final boolean global;
124 private NativeLibrary(
final DynamicLinker dynLink,
final long libraryHandle,
final String libraryPath,
final boolean global,
final String symbolName) {
125 this.dynLink = dynLink;
126 this.libraryHandle = libraryHandle;
127 this.libraryPath = libraryPath;
129 this.global = global;
131 System.err.println(
"NativeLibrary.open(): Successfully loaded: " +
this);
137 final String nlp_s =
null != nativeLibraryPath ?
", native '"+nativeLibraryPath+
"'" :
"";
138 return "NativeLibrary[" + dynLink.getClass().getSimpleName() +
", path[given '" + libraryPath +
"'"+nlp_s+
"], 0x" +
139 Long.toHexString(libraryHandle) +
", global " + global +
"]";
157 public String run() {
161 final List<String> res =
new ArrayList<String>();
162 if(
null != paths && paths.length() > 0 ) {
163 final StringTokenizer st =
new StringTokenizer(paths, File.pathSeparator);
164 while (st.hasMoreTokens()) {
165 res.add(st.nextToken());
193 final boolean searchSystemPath,
194 final boolean searchSystemPathFirst,
195 final ClassLoader loader,
final boolean global)
throws SecurityException {
196 return open(libName, libName, libName, searchSystemPath, searchSystemPathFirst, loader, global,
null);
222 final boolean searchSystemPath,
223 final boolean searchSystemPathFirst,
224 final ClassLoader loader,
final boolean global,
final String symbolName)
throws SecurityException {
225 return open(libName, libName, libName, searchSystemPath, searchSystemPathFirst, loader, global, symbolName);
262 final String unixLibName,
263 final String macOSXLibName,
264 final boolean searchSystemPath,
265 final boolean searchSystemPathFirst,
266 final ClassLoader loader,
final boolean global,
final String symbolName)
throws SecurityException {
270 searchSystemPath, searchSystemPathFirst,
277 for (
final Iterator<String> iter = possiblePaths.iterator(); iter.hasNext(); ) {
278 final String path = iter.next();
280 System.err.println(
"NativeLibrary.open(global "+global+
"): Trying to load " + path);
290 }
catch (
final Throwable t1) {
295 return new NativeLibrary(dynLink, res, path, global, symbolName);
298 System.err.println(
"NativeLibrary.open: Caught "+t.getClass().getSimpleName()+
": "+t.getMessage());
303 }
catch (
final Throwable t2) { errstr=
null; }
304 System.err.println(
"NativeLibrary.open: Last error "+errstr);
312 System.err.println(
"NativeLibrary.open(global "+global+
"): Did not succeed in loading (" + windowsLibName +
", " + unixLibName +
", " + macOSXLibName +
")");
332 if ( 0 == libraryHandle ) {
333 throw new RuntimeException(
"Library is not open");
340 if ( 0 == libraryHandle ) {
341 throw new RuntimeException(
"Library is not open");
343 return 0 != dynLink.
lookupSymbol(libraryHandle, funcName);
355 static DynamicLinker getDynamicLinker() {
356 final DynamicLinker dynLink;
357 switch (PlatformPropsImpl.OS_TYPE) {
359 dynLink =
new WindowsDynamicLinkerImpl();
364 dynLink =
new MacOSXDynamicLinkerImpl();
368 if( PlatformPropsImpl.CPU_ARCH.is32Bit ) {
369 dynLink =
new BionicDynamicLinker32bitImpl();
371 dynLink =
new BionicDynamicLinker64BitImpl();
376 dynLink =
new PosixDynamicLinkerImpl();
386 return libraryHandle;
390 public final boolean isOpen() {
return 0 != libraryHandle; }
399 return nativeLibraryPath;
406 public final void close() throws SecurityException {
408 System.err.println(
"NativeLibrary.close(): closing " +
this);
410 if ( 0 == libraryHandle ) {
411 throw new RuntimeException(
"Library already closed");
413 final long handle = libraryHandle;
415 dynLink.closeLibrary(handle,
DEBUG);
417 System.err.println(
"NativeLibrary.close(): Successfully closed " +
this);
432 final String libBaseName;
435 }
catch (
final URISyntaxException uriEx) {
436 throw new IllegalArgumentException(uriEx);
438 final String libBaseNameLC = isLowerCaseAlready ? libBaseName : libBaseName.toLowerCase();
440 for(
int i=0; i<prefixes.length && 0 > prefixIdx; i++) {
441 if (libBaseNameLC.startsWith(prefixes[i])) {
445 if( 0 <= prefixIdx ) {
446 for(
int i=0; i<suffixes.length; i++) {
447 if (libBaseNameLC.endsWith(suffixes[i])) {
448 final int s = prefixes[prefixIdx].length();
449 final int e = suffixes[i].length();
450 return libBaseName.substring(s, libBaseName.length()-e);
461 final String unixLibName,
462 final String macOSXLibName,
463 final ClassLoader loader) {
472 final String unixLibName,
473 final String macOSXLibName,
474 final boolean searchSystemPathFirst,
475 final ClassLoader loader) {
477 true , searchSystemPathFirst,
481 final String unixLibName,
482 final String macOSXLibName,
483 final boolean searchSystemPath,
484 final boolean searchSystemPathFirst,
485 final ClassLoader loader) {
486 final List<String> paths =
new ArrayList<String>();
487 final String libName = selectName(windowsLibName, unixLibName, macOSXLibName);
488 if (libName ==
null) {
490 System.err.println(
"NativeLibrary.enumerateLibraryPaths: empty, no libName selected");
495 System.err.println(
"NativeLibrary.enumerateLibraryPaths: libName '"+libName+
"'");
499 final File file =
new File(libName);
500 if (file.isAbsolute()) {
503 System.err.println(
"NativeLibrary.enumerateLibraryPaths: done, absolute path found '"+libName+
"'");
508 final String[] baseNames = buildNames(libName);
510 System.err.println(
"NativeLibrary.enumerateLibraryPaths: baseNames: "+Arrays.toString(baseNames));
513 if( searchSystemPath && searchSystemPathFirst ) {
518 for(
final String sysLibPath : sysLibPaths) {
519 addRelPaths(
"add.ssp_path_"+count, sysLibPath, baseNames, paths);
524 for (
int i = 0; i < baseNames.length; i++) {
526 System.err.println(
"NativeLibrary.enumerateLibraryPaths: add.ssp_default: "+baseNames[i]);
528 paths.add(baseNames[i]);
533 addAbsPaths(
"add.ssp_1st_macos_old",
"/Library/Frameworks/" + libName +
".framework", baseNames, paths);
535 addAbsPaths(
"add.ssp_1st_macos_cur",
"/System/Library/Frameworks/" + libName +
".framework", baseNames, paths);
541 final String clPath =
findLibrary(libName, loader);
542 if (clPath !=
null) {
544 System.err.println(
"NativeLibrary.enumerateLibraryPaths: add.clp: "+clPath);
550 final String[] javaLibraryPaths =
551 SecurityUtil.doPrivileged(
new PrivilegedAction<String[]>() {
553 public String[] run() {
555 final String usrPath = System.getProperty(
"java.library.path");
556 if(
null != usrPath) {
559 final String sysPath;
560 if( searchSystemPath ) {
561 sysPath = System.getProperty(
"sun.boot.library.path");
562 if(
null != sysPath) {
568 final String[] res =
new String[count];
570 if(
null != sysPath && searchSystemPathFirst ) {
573 if(
null != usrPath) {
576 if(
null != sysPath && !searchSystemPathFirst ) {
582 if (
null != javaLibraryPaths ) {
584 for(
int i=0; i < javaLibraryPaths.length; i++ ) {
585 final StringTokenizer tokenizer =
new StringTokenizer(javaLibraryPaths[i], File.pathSeparator);
586 while (tokenizer.hasMoreTokens()) {
587 addRelPaths(
"add.java.library.path_"+count, tokenizer.nextToken(), baseNames, paths);
594 final String userDir =
595 SecurityUtil.doPrivileged(
new PrivilegedAction<String>() {
597 public String run() {
598 return System.getProperty(
"user.dir");
601 addAbsPaths(
"add.user.dir.std", userDir, baseNames, paths);
605 addAbsPaths(
"add.user.dir.fat", userDir+File.separator+
"natives"+File.separator+PlatformPropsImpl.os_and_arch, baseNames, paths);
607 if( searchSystemPath && !searchSystemPathFirst ) {
612 for(
final String sysLibPath : sysLibPaths) {
613 addRelPaths(
"add.ssp_path_"+count, sysLibPath, baseNames, paths);
618 for (
int i = 0; i < baseNames.length; i++) {
620 System.err.println(
"NativeLibrary.enumerateLibraryPaths: add.ssp_default: "+baseNames[i]);
622 paths.add(baseNames[i]);
627 addAbsPaths(
"add.ssp_lst_macos_old",
"/Library/Frameworks/" + libName +
".Framework", baseNames, paths);
629 addAbsPaths(
"add.ssp_lst_macos_cur",
"/System/Library/Frameworks/" + libName +
".Framework", baseNames, paths);
633 System.err.println(
"NativeLibrary.enumerateLibraryPaths: done: "+paths.toString());
639 private static final String selectName(
final String windowsLibName,
640 final String unixLibName,
641 final String macOSXLibName) {
642 switch (PlatformPropsImpl.OS_TYPE) {
644 return windowsLibName;
648 return macOSXLibName;
655 private static final String[] buildNames(
final String libName) {
659 final String libBaseNameLC;
661 libBaseNameLC = IOUtil.getBasename(libName).toLowerCase();
662 }
catch (
final URISyntaxException uriEx) {
663 throw new IllegalArgumentException(uriEx);
667 for(
int i=0; i<prefixes.length && 0 > prefixIdx; i++) {
668 if (libBaseNameLC.startsWith(prefixes[i])) {
672 if( 0 <= prefixIdx ) {
673 for(
int i=0; i<suffixes.length; i++) {
674 if (libBaseNameLC.endsWith(suffixes[i])) {
675 return new String[] { libName };
679 for(
int i=0; i<suffixes.length && 0 > suffixIdx; i++) {
680 suffixIdx = libBaseNameLC.indexOf(suffixes[i]);
683 if (suffixIdx >= 0) {
685 for (
int i = suffixIdx + suffixes[0].length();
686 i < libName.length();
688 final char c = libName.charAt(i);
689 if (!(c ==
'.' || (c >=
'0' && c <=
'9'))) {
695 return new String[] { libName };
700 final String[] res =
new String[prefixes.length * suffixes.length + ( isOSX ? 1 : 0 )];
702 for (
int i = 0; i < prefixes.length; i++) {
703 for (
int j = 0; j < suffixes.length; j++) {
704 res[idx++] = prefixes[i] + libName + suffixes[j];
709 res[idx++] = libName;
714 private static final void addRelPaths(
final String cause,
final String path,
final String[] baseNames,
final List<String> paths) {
715 final String abs_path;
717 final File fpath =
new File(path);
718 abs_path = fpath.getCanonicalPath();
719 }
catch(
final IOException ioe ) {
721 System.err.println(
"NativeLibrary.enumerateLibraryPaths: "+cause+
": Exception "+ioe.getMessage()+
", from path "+path);
725 addAbsPaths(cause, abs_path, baseNames, paths);
727 private static final void addAbsPaths(
final String cause,
final String abs_path,
final String[] baseNames,
final List<String> paths) {
728 for (
int j = 0; j < baseNames.length; j++) {
729 final String p = abs_path + File.separator + baseNames[j];
731 System.err.println(
"NativeLibrary.enumerateLibraryPaths: "+cause+
": "+p+
", from path "+abs_path);
737 private static boolean initializedFindLibraryMethod =
false;
738 private static Method findLibraryMethod =
null;
739 private static final String findLibraryImpl(
final String libName,
final ClassLoader loader) {
740 if( PlatformPropsImpl.JAVA_9 ) {
743 if (loader ==
null) {
746 if (!initializedFindLibraryMethod) {
747 SecurityUtil.doPrivileged(
new PrivilegedAction<Object>() {
749 public Object run() {
751 findLibraryMethod = ClassLoader.class.getDeclaredMethod(
"findLibrary",
752 new Class[] { String.class });
753 findLibraryMethod.setAccessible(
true);
754 }
catch (
final Exception e) {
757 initializedFindLibraryMethod =
true;
762 if (findLibraryMethod !=
null) {
764 return SecurityUtil.doPrivileged(
new PrivilegedAction<String>() {
766 public String run() {
768 return (String) findLibraryMethod.invoke(loader,
new Object[] { libName });
769 }
catch (
final Exception e) {
770 throw new RuntimeException(e);
774 }
catch (
final Exception e) {
783 public static final String
findLibrary(
final String libName,
final ClassLoader loader) {
788 System.err.println(
"NativeLibrary.findLibrary(<"+libName+
">) (TempJarCache): "+res);
792 res = findLibraryImpl(libName, loader);
794 System.err.println(
"NativeLibrary.findLibrary(<"+libName+
">, "+loader+
") (CL): "+res);
static void dumpStack(final PrintStream out)
Provides low-level, relatively platform-independent access to shared ("native") libraries.
final void claimAllLinkPermission()
final String getLibraryPath()
Retrieves the path under which this library was opened.
static final String isValidNativeLibraryName(final String libName, final boolean isLowerCaseAlready)
Comparison of prefix and suffix of the given libName's basename is performed case insensitive
final boolean isFunctionAvailable(final String funcName)
Queries whether function 'funcName' is available.
static final List< String > enumerateLibraryPaths(final String windowsLibName, final String unixLibName, final String macOSXLibName, final boolean searchSystemPathFirst, final ClassLoader loader)
Given the base library names (no prefixes/suffixes) for the various platforms, enumerate the possible...
final boolean isOpen()
Returns true if library is loaded and open, otherwise false.
final long dynamicLookupFunctionGlobal(final String funcName)
Looks up the given function name in all loaded libraries.
static final NativeLibrary open(final String windowsLibName, final String unixLibName, final String macOSXLibName, final boolean searchSystemPath, final boolean searchSystemPathFirst, final ClassLoader loader, final boolean global, final String symbolName)
Opens the given native library, assuming it has the given base names (no "lib" prefix or "....
final long getLibraryHandle()
Retrieves the low-level library handle from this NativeLibrary object.
final String getNativeLibraryPath()
Returns the native library path of the opened native getLibraryHandle(), maybe null if not supported ...
static final NativeLibrary open(final String libName, final boolean searchSystemPath, final boolean searchSystemPathFirst, final ClassLoader loader, final boolean global)
Opens the given native library, assuming it has the same base name on all platforms.
static final NativeLibrary open(final String libName, final boolean searchSystemPath, final boolean searchSystemPathFirst, final ClassLoader loader, final boolean global, final String symbolName)
Opens the given native library, assuming it has the same base name on all platforms.
final long dynamicLookupFunction(final String funcName)
Returns the function handle for function 'funcName'.
static final String getSystemEnvLibraryPathVarname()
Returns the system's environment variable name used for the dynamic linker to resolve library locatio...
static final List< String > enumerateLibraryPaths(final String windowsLibName, final String unixLibName, final String macOSXLibName, final ClassLoader loader)
Given the base library names (no prefixes/suffixes) for the various platforms, enumerate the possible...
final void close()
Closes this native library.
final void releaseAllLinkPermission()
static final String findLibrary(final String libName, final ClassLoader loader)
static final List< String > getSystemEnvLibraryPaths()
Returns a list of system paths, from the getSystemEnvLibraryPathVarname() variable.
static String getBasename(String fname)
Returns the basename of the given fname w/o directory part.
static< T > T doPrivileged(final PrivilegedAction< T > o)
Call wrapper for java.security.AccessController#doPrivileged(PrivilegedAction).
Static Jar file cache handler using an underlying instance of TempFileCache, see getTempFileCache().
static boolean isInitialized(final boolean forExecutables)
static synchronized final String findLibrary(final String libName)
If isInitialized(true) is false due to lack of executable support only, this method always returns fa...
Low level secure dynamic linker access.
void releaseAllLinkPermission()
long openLibraryLocal(String pathname, boolean debug)
If a SecurityManager is installed, user needs link permissions for the named library.
long lookupSymbolGlobal(String symbolName)
If a SecurityManager is installed, user needs link permissions for all libraries, i....
void claimAllLinkPermission()
String getLastError()
Returns a string containing the last error.
String lookupLibraryPathname(long libraryHandle, String symbolName)
Security checks are implicit by previous call of openLibraryLocal(String, boolean) or openLibraryGlob...
long openLibraryGlobal(String pathname, boolean debug)
If a SecurityManager is installed, user needs link permissions for the named library.
long lookupSymbol(long libraryHandle, String symbolName)
Security checks are implicit by previous call of openLibraryLocal(String, boolean) or openLibraryGlob...
Interface callers may use ProcAddressHelper's reset helper method to install function pointers into a...
static final boolean DEBUG