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";
190 private LibPath(
final String _path,
final boolean _isAbsolute,
final boolean _addToSearchPath,
final String _searchPathPrepend) {
200 int hash =
path.hashCode();
204 hash = ((hash << 5) - hash) + (
isAbsolute? 1 : 0);
233 private long libraryHandle;
236 private final LibPath libraryPath;
239 private final String nativeLibraryPath;
241 private final boolean global;
245 this.dynLink = dynLink;
246 this.libraryHandle = libraryHandle;
247 this.libraryPath = libraryPath;
249 this.global = global;
251 System.err.println(
"NativeLibrary.open(): Successfully loaded: " +
this);
257 final String nlp_s =
null != nativeLibraryPath ?
", native '"+nativeLibraryPath+
"'" :
"";
258 return "NativeLibrary[" + dynLink.getClass().getSimpleName() +
", path[given '" + libraryPath +
"'"+nlp_s+
"], 0x" +
259 Long.toHexString(libraryHandle) +
", global " + global +
"]";
276 public String run() {
286 public String run() {
287 return System.getProperty(
"jogamp.primary.library.path");
293 private static final String getJavaLibrarySystemPaths() {
296 public String run() {
297 final String p = System.getProperty(
"sun.boot.library.path");
298 if(
null != p && !p.isEmpty()) {
306 private static final String getJavaLibraryUserPaths() {
307 return SecurityUtil.doPrivileged(
new PrivilegedAction<String>() {
309 public String run() {
310 final String p = System.getProperty(
"java.library.path");
311 if(
null != p && !p.isEmpty()) {
320 private static final String getJavaCurrentWorkingDir() {
321 return SecurityUtil.doPrivileged(
new PrivilegedAction<String>() {
323 public String run() {
324 return System.getProperty(
"user.dir");
351 final boolean searchOSSystemPath,
352 final boolean searchSystemPathFirst,
353 final ClassLoader loader,
final boolean global)
throws SecurityException {
354 return open(libName, libName, libName, searchOSSystemPath, searchSystemPathFirst, loader, global,
null);
380 final boolean searchOSSystemPath,
381 final boolean searchSystemPathFirst,
382 final ClassLoader loader,
final boolean global,
final String symbolName)
throws SecurityException {
383 return open(libName, libName, libName, searchOSSystemPath, searchSystemPathFirst, loader, global, symbolName);
420 final String unixLibName,
421 final String macOSXLibName,
422 final boolean searchOSSystemPath,
423 final boolean searchSystemPathFirst,
424 final ClassLoader loader,
final boolean global,
final String symbolName)
throws SecurityException {
428 searchOSSystemPath, searchSystemPathFirst,
435 for (
final Iterator<LibPath> iter = possiblePaths.iterator(); iter.hasNext(); ) {
436 final LibPath path = iter.next();
438 System.err.println(
"NativeLibrary.open(global "+global+
"): Trying to load " + path);
448 }
catch (
final Throwable t1) {
453 return new NativeLibrary(dynLink, res, path, global, symbolName);
456 System.err.println(
"NativeLibrary.open: Caught "+t.getClass().getSimpleName()+
": "+t.getMessage());
461 }
catch (
final Throwable t2) { errstr=
null; }
462 System.err.println(
"NativeLibrary.open: Last error "+errstr);
470 System.err.println(
"NativeLibrary.open(global "+global+
"): Did not succeed in loading (" + windowsLibName +
", " + unixLibName +
", " + macOSXLibName +
")");
490 if ( 0 == libraryHandle ) {
491 throw new RuntimeException(
"Library is not open");
498 if ( 0 == libraryHandle ) {
499 throw new RuntimeException(
"Library is not open");
501 return 0 != dynLink.
lookupSymbol(libraryHandle, funcName);
513 static DynamicLinker getDynamicLinker() {
514 final DynamicLinker dynLink;
515 switch (PlatformPropsImpl.OS_TYPE) {
517 dynLink =
new WindowsDynamicLinkerImpl();
522 dynLink =
new MacOSXDynamicLinkerImpl();
526 if( PlatformPropsImpl.CPU_ARCH.is32Bit ) {
527 dynLink =
new BionicDynamicLinker32bitImpl();
529 dynLink =
new BionicDynamicLinker64BitImpl();
534 dynLink =
new PosixDynamicLinkerImpl();
544 return libraryHandle;
548 public final boolean isOpen() {
return 0 != libraryHandle; }
552 return libraryPath.
path;
562 return nativeLibraryPath;
569 public final void close() throws SecurityException {
571 System.err.println(
"NativeLibrary.close(): closing " +
this);
573 if ( 0 == libraryHandle ) {
574 throw new RuntimeException(
"Library already closed");
576 final long handle = libraryHandle;
578 dynLink.closeLibrary(handle,
DEBUG);
580 System.err.println(
"NativeLibrary.close(): Successfully closed " +
this);
595 final String libBaseName;
598 }
catch (
final URISyntaxException uriEx) {
599 throw new IllegalArgumentException(uriEx);
601 final String libBaseNameLC = isLowerCaseAlready ? libBaseName : libBaseName.toLowerCase();
603 for(
int i=0; i<prefixes.length && 0 > prefixIdx; i++) {
604 if (libBaseNameLC.startsWith(prefixes[i])) {
608 if( 0 <= prefixIdx ) {
609 for(
int i=0; i<suffixes.length; i++) {
610 if (libBaseNameLC.endsWith(suffixes[i])) {
611 final int s = prefixes[prefixIdx].length();
612 final int e = suffixes[i].length();
613 return libBaseName.substring(s, libBaseName.length()-e);
624 final String unixLibName,
625 final String macOSXLibName,
626 final ClassLoader loader) {
635 final String unixLibName,
636 final String macOSXLibName,
637 final boolean searchSystemPathFirst,
638 final ClassLoader loader) {
640 true , searchSystemPathFirst,
645 final String unixLibName,
646 final String macOSXLibName,
647 final boolean searchOSSystemPath,
648 final boolean searchSystemPathFirst,
649 final ClassLoader loader) {
651 final String libName = selectName(windowsLibName, unixLibName, macOSXLibName);
652 if (libName ==
null || libName.isEmpty()) {
654 System.err.println(
"NativeLibrary.enumerateLibraryPaths: empty, no libName selected");
659 System.err.println(
"NativeLibrary.enumerateLibraryPaths: libName '"+libName+
"'");
663 final File file =
new File(libName);
664 if (file.isAbsolute()) {
667 cfile = file.getCanonicalFile();
668 }
catch (
final IOException e) {
669 System.err.println(
"NativeLibrary.enumerateLibraryPaths: absolute path: Exception "+e.getMessage()+
", from path '"+libName+
"'");
672 if( cfile.exists() ) {
673 final LibPath lp = LibPath.createExtra(cfile.getPath(), cfile.getParent());
674 if( paths.
add(lp) ) {
676 System.err.println(
"NativeLibrary.enumerateLibraryPaths: absolute path: Done, found '"+lp+
"'");
683 final String[] baseNames = buildNames(libName);
685 System.err.println(
"NativeLibrary.enumerateLibraryPaths: baseNames: "+Arrays.toString(baseNames));
691 if( searchSystemPathFirst ) {
692 if( searchOSSystemPath ) {
693 addOSSystemLibraryPaths(libName, baseNames, paths);
695 addClassLoaderPaths(libName, paths, loader);
696 addMultiLibPathsLibraries(
"sun.boot.library", getJavaLibrarySystemPaths(), libName, baseNames, paths,
true);
700 addMultiLibPathsLibraries(
"java.library", getJavaLibraryUserPaths(), libName, baseNames, paths,
true);
703 final String userDir = getJavaCurrentWorkingDir();
704 if(
null != userDir && !userDir.isEmpty()) {
705 addCanonicalPaths(
"add.user.dir.std", userDir, baseNames, paths,
true);
709 addCanonicalPaths(
"add.user.dir.fat", userDir+File.separator+
"natives"+File.separator+PlatformPropsImpl.os_and_arch, baseNames, paths,
true);
712 if( !searchSystemPathFirst ) {
713 addMultiLibPathsLibraries(
"sun.boot.library", getJavaLibrarySystemPaths(), libName, baseNames, paths,
true);
714 addClassLoaderPaths(libName, paths, loader);
715 if( searchOSSystemPath ) {
716 addOSSystemLibraryPaths(libName, baseNames, paths);
721 System.err.println(
"NativeLibrary.enumerateLibraryPaths: done: "+paths.
toString());
727 private static final void addOSSystemLibraryPaths(
final String libName,
final String[] baseNames,
final List<LibPath> paths) {
732 for (
int i = 0; i < baseNames.length; i++) {
733 final LibPath lp = LibPath.createRelative(baseNames[i]);
734 if( paths.add( lp ) ) {
736 System.err.println(
"NativeLibrary.enumerateLibraryPaths: add.ssp_default: " + lp);
743 addCanonicalPaths(
"add.ssp_1st_macos_old",
"/Library/Frameworks/" + libName +
".framework", baseNames, paths,
false);
745 addCanonicalPaths(
"add.ssp_1st_macos_cur",
"/System/Library/Frameworks/" + libName +
".framework", baseNames, paths,
false);
749 private static final void addClassLoaderPaths(
final String libName,
final List<LibPath> paths,
final ClassLoader loader) {
752 final String clPath =
findLibrary(libName, loader);
753 if (clPath !=
null) {
754 final LibPath lp = LibPath.createAbsolute(clPath);
755 if( paths.add( lp ) ) {
757 System.err.println(
"NativeLibrary.enumerateLibraryPaths: add.clp: "+clPath);
762 private static final void addMultiLibPathsLibraries(
final String
id,
final String multidirs,
final String libName,
final String[] baseNames,
final List<LibPath> paths,
763 final boolean addToSearchPath)
765 if(
null == multidirs || multidirs.isEmpty() ) {
769 final StringTokenizer tokenizer =
new StringTokenizer(multidirs, File.pathSeparator);
770 while (tokenizer.hasMoreTokens()) {
771 addAbstractPaths(
"add."+
id+
".path_"+count, tokenizer.nextToken(), baseNames, paths, addToSearchPath);
776 private static final void addAbstractPaths(
final String cause,
final String parent,
final String[] baseNames,
final List<LibPath> paths,
final boolean addToSearchPath) {
777 if(
null == parent || parent.isEmpty() ) {
780 addCanonicalPaths(cause,
new File(parent), baseNames, paths, addToSearchPath);
782 private static final void addCanonicalPaths(
final String cause,
final String parent,
final String[] baseNames,
final List<LibPath> paths,
final boolean addToSearchPath) {
783 if(
null == parent || parent.isEmpty() ) {
786 addCanonicalPaths(cause,
new File(parent), baseNames, paths, addToSearchPath);
788 private static final void addCanonicalPaths(
final String cause,
final File can_parent,
final String[] baseNames,
final List<LibPath> paths,
final boolean addToSearchPath) {
789 for (
int j = 0; j < baseNames.length; j++) {
790 final String ps = can_parent.getPath() + File.separator + baseNames[j];
793 fps =
new File(ps).getCanonicalFile();
794 }
catch (
final IOException e) {
795 System.err.println(
"NativeLibrary.addCanonicalPaths: "+cause+
": Exception "+e.getMessage()+
", from path '"+ps+
"'");
799 final LibPath p = addToSearchPath ? LibPath.createExtra(fps.getPath(), fps.getParent()) : LibPath.createAbsolute(fps.getPath());
802 System.err.println(
"NativeLibrary.addCanonicalPaths: "+cause+
": Added "+p+
", from path '"+ps+
"'");
809 private static final String selectName(
final String windowsLibName,
810 final String unixLibName,
811 final String macOSXLibName) {
812 switch (PlatformPropsImpl.OS_TYPE) {
814 return windowsLibName;
818 return macOSXLibName;
825 private static final String[] buildNames(
final String libName) {
829 final String libBaseNameLC;
831 libBaseNameLC = IOUtil.getBasename(libName).toLowerCase();
832 }
catch (
final URISyntaxException uriEx) {
833 throw new IllegalArgumentException(uriEx);
837 for(
int i=0; i<prefixes.length && 0 > prefixIdx; i++) {
838 if (libBaseNameLC.startsWith(prefixes[i])) {
842 if( 0 <= prefixIdx ) {
843 for(
int i=0; i<suffixes.length; i++) {
844 if (libBaseNameLC.endsWith(suffixes[i])) {
845 return new String[] { libName };
849 for(
int i=0; i<suffixes.length && 0 > suffixIdx; i++) {
850 suffixIdx = libBaseNameLC.indexOf(suffixes[i]);
853 if (suffixIdx >= 0) {
855 for (
int i = suffixIdx + suffixes[0].length();
856 i < libName.length();
858 final char c = libName.charAt(i);
859 if (!(c ==
'.' || (c >=
'0' && c <=
'9'))) {
865 return new String[] { libName };
870 final String[] res =
new String[prefixes.length * suffixes.length + ( isOSX ? 1 : 0 )];
872 for (
int i = 0; i < prefixes.length; i++) {
873 for (
int j = 0; j < suffixes.length; j++) {
874 res[idx++] = prefixes[i] + libName + suffixes[j];
879 res[idx++] = libName;
884 private static boolean initializedFindLibraryMethod =
false;
885 private static Method findLibraryMethod =
null;
886 private static final String findLibraryImpl(
final String libName,
final ClassLoader loader) {
887 if( PlatformPropsImpl.JAVA_9 ) {
890 if (loader ==
null) {
893 if (!initializedFindLibraryMethod) {
894 SecurityUtil.doPrivileged(
new PrivilegedAction<Object>() {
896 public Object run() {
898 findLibraryMethod = ClassLoader.class.getDeclaredMethod(
"findLibrary",
899 new Class[] { String.class });
900 findLibraryMethod.setAccessible(
true);
901 }
catch (
final Exception e) {
904 initializedFindLibraryMethod =
true;
909 if (findLibraryMethod !=
null) {
911 return SecurityUtil.doPrivileged(
new PrivilegedAction<String>() {
913 public String run() {
915 return (String) findLibraryMethod.invoke(loader,
new Object[] { libName });
916 }
catch (
final Exception e) {
917 throw new RuntimeException(e);
921 }
catch (
final Exception e) {
930 public static final String
findLibrary(
final String libName,
final ClassLoader loader) {
935 System.err.println(
"NativeLibrary.findLibrary(<"+libName+
">) (TempJarCache): "+res);
939 res = findLibraryImpl(libName, loader);
941 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