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.Arrays;
38import java.util.Iterator;
40import java.util.StringTokenizer;
42import jogamp.common.os.BionicDynamicLinker32bitImpl;
43import jogamp.common.os.BionicDynamicLinker64BitImpl;
44import jogamp.common.os.MacOSXDynamicLinkerImpl;
45import jogamp.common.os.PlatformPropsImpl;
46import jogamp.common.os.PosixDynamicLinkerImpl;
47import jogamp.common.os.WindowsDynamicLinkerImpl;
49import com.jogamp.common.ExceptionUtils;
50import com.jogamp.common.util.ArrayHashSet;
51import com.jogamp.common.util.IOUtil;
52import com.jogamp.common.util.SecurityUtil;
53import com.jogamp.common.util.cache.TempJarCache;
113 private static final String[] prefixes;
114 private static final String[] suffixes;
115 private static final boolean isOSX;
116 private static String sys_env_lib_path_varname;
120 switch (PlatformPropsImpl.OS_TYPE) {
122 prefixes =
new String[] {
"" };
123 suffixes =
new String[] {
".dll" };
124 sys_env_lib_path_varname =
"PATH";
130 prefixes =
new String[] {
"lib" };
131 suffixes =
new String[] {
".dylib" };
132 sys_env_lib_path_varname =
"DYLD_LIBRARY_PATH";
144 prefixes =
new String[] {
"lib" };
145 suffixes =
new String[] {
".so" };
146 sys_env_lib_path_varname =
"LD_LIBRARY_PATH";
192 private LibPath(
final String _path,
final boolean _isAbsolute,
final boolean _addToSearchPath,
final String _searchPathPrepend) {
197 fixedHashCode = calcHashCode();
199 private int calcHashCode() {
201 int hash =
path.hashCode();
205 hash = ((hash << 5) - hash) + (
isAbsolute? 1 : 0);
209 private final int fixedHashCode;
238 private long libraryHandle;
241 private final LibPath libraryPath;
244 private final String nativeLibraryPath;
246 private final boolean global;
250 this.dynLink = dynLink;
251 this.libraryHandle = libraryHandle;
252 this.libraryPath = libraryPath;
254 this.global = global;
256 System.err.println(
"NativeLibrary.open(): Successfully loaded: " +
this);
262 final String nlp_s =
null != nativeLibraryPath ?
", native '"+nativeLibraryPath+
"'" :
"";
263 return "NativeLibrary[" + dynLink.getClass().getSimpleName() +
", path[given '" + libraryPath +
"'"+nlp_s+
"], 0x" +
264 Long.toHexString(libraryHandle) +
", global " + global +
"]";
281 public String run() {
291 public String run() {
292 return System.getProperty(
"jogamp.primary.library.path");
298 private static final String getJavaLibrarySystemPaths() {
301 public String run() {
302 final String p = System.getProperty(
"sun.boot.library.path");
303 if(
null != p && !p.isEmpty()) {
311 private static final String getJavaLibraryUserPaths() {
312 return SecurityUtil.doPrivileged(
new PrivilegedAction<String>() {
314 public String run() {
315 final String p = System.getProperty(
"java.library.path");
316 if(
null != p && !p.isEmpty()) {
325 private static final String getJavaCurrentWorkingDir() {
326 return SecurityUtil.doPrivileged(
new PrivilegedAction<String>() {
328 public String run() {
329 return System.getProperty(
"user.dir");
356 final boolean searchOSSystemPath,
357 final boolean searchSystemPathFirst,
358 final ClassLoader loader,
final boolean global)
throws SecurityException {
359 return open(libName, libName, libName, searchOSSystemPath, searchSystemPathFirst, loader, global,
null);
385 final boolean searchOSSystemPath,
386 final boolean searchSystemPathFirst,
387 final ClassLoader loader,
final boolean global,
final String symbolName)
throws SecurityException {
388 return open(libName, libName, libName, searchOSSystemPath, searchSystemPathFirst, loader, global, symbolName);
425 final String unixLibName,
426 final String macOSXLibName,
427 final boolean searchOSSystemPath,
428 final boolean searchSystemPathFirst,
429 final ClassLoader loader,
final boolean global,
final String symbolName)
throws SecurityException {
433 searchOSSystemPath, searchSystemPathFirst,
440 for (
final Iterator<LibPath> iter = possiblePaths.iterator(); iter.hasNext(); ) {
441 final LibPath path = iter.next();
443 System.err.println(
"NativeLibrary.open(global "+global+
"): Trying to load " + path);
453 }
catch (
final Throwable t1) {
458 return new NativeLibrary(dynLink, res, path, global, symbolName);
461 System.err.println(
"NativeLibrary.open: Caught "+t.getClass().getSimpleName()+
": "+t.getMessage());
466 }
catch (
final Throwable t2) { errstr=
null; }
467 System.err.println(
"NativeLibrary.open: Last error "+errstr);
475 System.err.println(
"NativeLibrary.open(global "+global+
"): Did not succeed in loading (" + windowsLibName +
", " + unixLibName +
", " + macOSXLibName +
")");
495 if ( 0 == libraryHandle ) {
496 throw new RuntimeException(
"Library is not open");
503 if ( 0 == libraryHandle ) {
504 throw new RuntimeException(
"Library is not open");
506 return 0 != dynLink.
lookupSymbol(libraryHandle, funcName);
518 static DynamicLinker getDynamicLinker() {
519 final DynamicLinker dynLink;
520 switch (PlatformPropsImpl.OS_TYPE) {
522 dynLink =
new WindowsDynamicLinkerImpl();
527 dynLink =
new MacOSXDynamicLinkerImpl();
531 if( PlatformPropsImpl.CPU_ARCH.is32Bit ) {
532 dynLink =
new BionicDynamicLinker32bitImpl();
534 dynLink =
new BionicDynamicLinker64BitImpl();
539 dynLink =
new PosixDynamicLinkerImpl();
549 return libraryHandle;
553 public final boolean isOpen() {
return 0 != libraryHandle; }
557 return libraryPath.
path;
567 return nativeLibraryPath;
574 public final void close() throws SecurityException {
576 System.err.println(
"NativeLibrary.close(): closing " +
this);
578 if ( 0 == libraryHandle ) {
579 throw new RuntimeException(
"Library already closed");
581 final long handle = libraryHandle;
583 dynLink.closeLibrary(handle,
DEBUG);
585 System.err.println(
"NativeLibrary.close(): Successfully closed " +
this);
600 final String libBaseName;
603 }
catch (
final URISyntaxException uriEx) {
604 throw new IllegalArgumentException(uriEx);
606 final String libBaseNameLC = isLowerCaseAlready ? libBaseName : libBaseName.toLowerCase();
608 for(
int i=0; i<prefixes.length && 0 > prefixIdx; i++) {
609 if (libBaseNameLC.startsWith(prefixes[i])) {
613 if( 0 <= prefixIdx ) {
614 for(
int i=0; i<suffixes.length; i++) {
615 if (libBaseNameLC.endsWith(suffixes[i])) {
616 final int s = prefixes[prefixIdx].length();
617 final int e = suffixes[i].length();
618 return libBaseName.substring(s, libBaseName.length()-e);
629 final String unixLibName,
630 final String macOSXLibName,
631 final ClassLoader loader) {
640 final String unixLibName,
641 final String macOSXLibName,
642 final boolean searchSystemPathFirst,
643 final ClassLoader loader) {
645 true , searchSystemPathFirst,
650 final String unixLibName,
651 final String macOSXLibName,
652 final boolean searchOSSystemPath,
653 final boolean searchSystemPathFirst,
654 final ClassLoader loader) {
656 final String libName = selectName(windowsLibName, unixLibName, macOSXLibName);
657 if (libName ==
null || libName.isEmpty()) {
659 System.err.println(
"NativeLibrary.enumerateLibraryPaths: empty, no libName selected");
664 System.err.println(
"NativeLibrary.enumerateLibraryPaths: libName '"+libName+
"'");
668 final File file =
new File(libName);
669 if (file.isAbsolute()) {
672 cfile = file.getCanonicalFile();
673 }
catch (
final IOException e) {
674 System.err.println(
"NativeLibrary.enumerateLibraryPaths: absolute path: Exception "+e.getMessage()+
", from path '"+libName+
"'");
677 if( cfile.exists() ) {
678 final LibPath lp = LibPath.createExtra(cfile.getPath(), cfile.getParent());
679 if( paths.
add(lp) ) {
681 System.err.println(
"NativeLibrary.enumerateLibraryPaths: absolute path: Done, found '"+lp+
"'");
688 final String[] baseNames = buildNames(libName);
690 System.err.println(
"NativeLibrary.enumerateLibraryPaths: baseNames: "+Arrays.toString(baseNames));
696 if( searchSystemPathFirst ) {
697 if( searchOSSystemPath ) {
698 addOSSystemLibraryPaths(libName, baseNames, paths);
700 addClassLoaderPaths(libName, paths, loader);
701 addMultiLibPathsLibraries(
"sun.boot.library", getJavaLibrarySystemPaths(), libName, baseNames, paths,
true);
705 addMultiLibPathsLibraries(
"java.library", getJavaLibraryUserPaths(), libName, baseNames, paths,
true);
708 final String userDir = getJavaCurrentWorkingDir();
709 if(
null != userDir && !userDir.isEmpty()) {
710 addCanonicalPaths(
"add.user.dir.std", userDir, baseNames, paths,
true);
714 addCanonicalPaths(
"add.user.dir.fat", userDir+File.separator+
"natives"+File.separator+PlatformPropsImpl.os_and_arch, baseNames, paths,
true);
717 if( !searchSystemPathFirst ) {
718 addMultiLibPathsLibraries(
"sun.boot.library", getJavaLibrarySystemPaths(), libName, baseNames, paths,
true);
719 addClassLoaderPaths(libName, paths, loader);
720 if( searchOSSystemPath ) {
721 addOSSystemLibraryPaths(libName, baseNames, paths);
726 System.err.println(
"NativeLibrary.enumerateLibraryPaths: done: "+paths.
toString());
732 private static final void addOSSystemLibraryPaths(
final String libName,
final String[] baseNames,
final List<LibPath> paths) {
737 for (
int i = 0; i < baseNames.length; i++) {
738 final LibPath lp = LibPath.createRelative(baseNames[i]);
739 if( paths.add( lp ) ) {
741 System.err.println(
"NativeLibrary.enumerateLibraryPaths: add.ssp_default: " + lp);
748 addCanonicalPaths(
"add.ssp_1st_macos_old",
"/Library/Frameworks/" + libName +
".framework", baseNames, paths,
false);
750 addCanonicalPaths(
"add.ssp_1st_macos_cur",
"/System/Library/Frameworks/" + libName +
".framework", baseNames, paths,
false);
754 private static final void addClassLoaderPaths(
final String libName,
final List<LibPath> paths,
final ClassLoader loader) {
757 final String clPath =
findLibrary(libName, loader);
758 if (clPath !=
null) {
759 final LibPath lp = LibPath.createAbsolute(clPath);
760 if( paths.add( lp ) ) {
762 System.err.println(
"NativeLibrary.enumerateLibraryPaths: add.clp: "+clPath);
767 private static final void addMultiLibPathsLibraries(
final String
id,
final String multidirs,
final String libName,
final String[] baseNames,
final List<LibPath> paths,
768 final boolean addToSearchPath)
770 if(
null == multidirs || multidirs.isEmpty() ) {
774 final StringTokenizer tokenizer =
new StringTokenizer(multidirs, File.pathSeparator);
775 while (tokenizer.hasMoreTokens()) {
776 addAbstractPaths(
"add."+
id+
".path_"+count, tokenizer.nextToken(), baseNames, paths, addToSearchPath);
781 private static final void addAbstractPaths(
final String cause,
final String parent,
final String[] baseNames,
final List<LibPath> paths,
final boolean addToSearchPath) {
782 if(
null == parent || parent.isEmpty() ) {
785 addCanonicalPaths(cause,
new File(parent), baseNames, paths, addToSearchPath);
787 private static final void addCanonicalPaths(
final String cause,
final String parent,
final String[] baseNames,
final List<LibPath> paths,
final boolean addToSearchPath) {
788 if(
null == parent || parent.isEmpty() ) {
791 addCanonicalPaths(cause,
new File(parent), baseNames, paths, addToSearchPath);
793 private static final void addCanonicalPaths(
final String cause,
final File can_parent,
final String[] baseNames,
final List<LibPath> paths,
final boolean addToSearchPath) {
794 for (
int j = 0; j < baseNames.length; j++) {
795 final String ps = can_parent.getPath() + File.separator + baseNames[j];
798 fps =
new File(ps).getCanonicalFile();
799 }
catch (
final IOException e) {
800 System.err.println(
"NativeLibrary.addCanonicalPaths: "+cause+
": Exception "+e.getMessage()+
", from path '"+ps+
"'");
804 final LibPath p = addToSearchPath ? LibPath.createExtra(fps.getPath(), fps.getParent()) : LibPath.createAbsolute(fps.getPath());
807 System.err.println(
"NativeLibrary.addCanonicalPaths: "+cause+
": Added "+p+
", from path '"+ps+
"'");
814 private static final String selectName(
final String windowsLibName,
815 final String unixLibName,
816 final String macOSXLibName) {
817 switch (PlatformPropsImpl.OS_TYPE) {
819 return windowsLibName;
823 return macOSXLibName;
830 private static final String[] buildNames(
final String libName) {
834 final String libBaseNameLC;
836 libBaseNameLC = IOUtil.getBasename(libName).toLowerCase();
837 }
catch (
final URISyntaxException uriEx) {
838 throw new IllegalArgumentException(uriEx);
842 for(
int i=0; i<prefixes.length && 0 > prefixIdx; i++) {
843 if (libBaseNameLC.startsWith(prefixes[i])) {
847 if( 0 <= prefixIdx ) {
848 for(
int i=0; i<suffixes.length; i++) {
849 if (libBaseNameLC.endsWith(suffixes[i])) {
850 return new String[] { libName };
854 for(
int i=0; i<suffixes.length && 0 > suffixIdx; i++) {
855 suffixIdx = libBaseNameLC.indexOf(suffixes[i]);
858 if (suffixIdx >= 0) {
860 for (
int i = suffixIdx + suffixes[0].length();
861 i < libName.length();
863 final char c = libName.charAt(i);
864 if (!(c ==
'.' || (c >=
'0' && c <=
'9'))) {
870 return new String[] { libName };
875 final String[] res =
new String[prefixes.length * suffixes.length + ( isOSX ? 1 : 0 )];
877 for (
int i = 0; i < prefixes.length; i++) {
878 for (
int j = 0; j < suffixes.length; j++) {
879 res[idx++] = prefixes[i] + libName + suffixes[j];
884 res[idx++] = libName;
889 private static boolean initializedFindLibraryMethod =
false;
890 private static Method findLibraryMethod =
null;
891 private static final String findLibraryImpl(
final String libName,
final ClassLoader loader) {
892 if( PlatformPropsImpl.JAVA_9 ) {
895 if (loader ==
null) {
898 if (!initializedFindLibraryMethod) {
899 SecurityUtil.doPrivileged(
new PrivilegedAction<Object>() {
901 public Object run() {
903 findLibraryMethod = ClassLoader.class.getDeclaredMethod(
"findLibrary",
904 new Class[] { String.class });
905 findLibraryMethod.setAccessible(
true);
906 }
catch (
final Exception e) {
909 initializedFindLibraryMethod =
true;
914 if (findLibraryMethod !=
null) {
916 return SecurityUtil.doPrivileged(
new PrivilegedAction<String>() {
918 public String run() {
920 return (String) findLibraryMethod.invoke(loader,
new Object[] { libName });
921 }
catch (
final Exception e) {
922 throw new RuntimeException(e);
926 }
catch (
final Exception e) {
935 public static final String
findLibrary(
final String libName,
final ClassLoader loader) {
940 System.err.println(
"NativeLibrary.findLibrary(<"+libName+
">) (TempJarCache): "+res);
944 res = findLibraryImpl(libName, loader);
946 System.err.println(
"NativeLibrary.findLibrary(<"+libName+
">, "+loader+
") (CL): "+res);
static void dumpStack(final PrintStream out)
Native Library Path Specification.
final String searchPathPrepend
Search path prepend directories, separated by OS File#pathSeparator.
final String path
Relative or absolute library path.
static LibPath createRelative(final String p)
Returns new instance with relative path in system linker search path.
static LibPath createAbsolute(final String p)
Returns new instance with absolute path in system linker search path.
final boolean isAbsolute
True if path is an absolute path.
boolean equals(final Object o)
final boolean addToSearchPath
True if directory of absolute library path shall be added to the linker search path.
static LibPath createExtra(final String p, final String searchPathPrepend)
Returns new instance with absolute path not in system linker search path.
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 NativeLibrary open(final String libName, final boolean searchOSSystemPath, 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.
static final List< LibPath > 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 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.
final long getLibraryHandle()
Retrieves the low-level library handle from this NativeLibrary object.
static final String getSystemEnvLibraryPaths()
Returns a system paths separated with File#pathSeparator, from the getSystemEnvLibraryPathVarname() v...
final String getNativeLibraryPath()
Returns the native library path of the opened native getLibraryHandle(), maybe null if not supported ...
final LibPath getLibPath()
Retrieves the path under which this library was opened.
static final NativeLibrary open(final String windowsLibName, final String unixLibName, final String macOSXLibName, final boolean searchOSSystemPath, 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 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...
final void close()
Closes this native library.
static final List< LibPath > 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...
static final NativeLibrary open(final String libName, final boolean searchOSSystemPath, 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 String getJogAmpPrimaryLibraryPaths()
Returns JogAmp's primary library path jogamp.primary.library.path separated with File#pathSeparator.
final void releaseAllLinkPermission()
static final String findLibrary(final String libName, final ClassLoader loader)
Hashed ArrayList implementation of the List and Collection interface.
final ArrayList< E > getData()
Returns this object ordered ArrayList.
static final float DEFAULT_LOAD_FACTOR
Default load factor: {@value}.
final boolean add(final E element)
Add element at the end of this list, if it is not contained yet.
static final int DEFAULT_INITIAL_CAPACITY
The default initial capacity: {@value}.
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.
long openLibraryLocal(LibPath libpath, boolean debug)
If a SecurityManager is installed, user needs link permissions for the named library.
void releaseAllLinkPermission()
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(LibPath libpath, 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