diff options
author | Sven Gothel <[email protected]> | 2010-06-10 06:13:06 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2010-06-10 06:13:06 +0200 |
commit | 555091d37a9a44fb7c35479ddecfee358a559e90 (patch) | |
tree | 350a3b9b7f55db85dcf3a808f0249bcd0ab32a74 /src/java/com/jogamp/common/os | |
parent | 710d86d31cd278583ee3d74b36595f4148a72133 (diff) |
Adding DynamicLibraryBundle utility to bundle Tool and JNI native library loading and lookup
Add JNILibLoaderBase.loadLibrary(String libname, boolean ignoreError);
DynamicLibraryBundle provides Tool and JNI native library loading and lookup
New classes:
com.jogamp.common.os.DynamicLibraryBundle
com.jogamp.common.os.DynamicLibraryBundleInfo
com.jogamp.common.util.MiscUtils.java
Change: DEBUG/VERBOSE properties 'gluegen' -> 'jogamp'
Diffstat (limited to 'src/java/com/jogamp/common/os')
4 files changed, 407 insertions, 3 deletions
diff --git a/src/java/com/jogamp/common/os/DynamicLibraryBundle.java b/src/java/com/jogamp/common/os/DynamicLibraryBundle.java new file mode 100755 index 0000000..8e138ef --- /dev/null +++ b/src/java/com/jogamp/common/os/DynamicLibraryBundle.java @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2010, Sven Gothel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Sven Gothel nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Sven Gothel BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jogamp.common.os; + +import java.util.*; +import java.security.*; + +import com.jogamp.common.jvm.JNILibLoaderBase; +import com.jogamp.common.util.MiscUtils; + +/** + * Provides bundling of:<br> + * <ul> + * <li>The to-be-glued native library, eg OpenGL32.dll. From hereon this is referred as the Tool.</li> + * <li>The JNI glue-code native library, eg jogl_desktop.dll. From heron this is referred as the Glue</li> + * </ul><br> + * An instance provides a complete {@link com.jogamp.common.os.DynamicLookupHelper} + * to {@link com.jogamp.gluegen.runtime.ProcAddressTable#reset(com.jogamp.common.os.DynamicLookupHelper lookup)} + * the {@link com.jogamp.gluegen.runtime.ProcAddressTable}.<br> + * At construction, it loads the Tool native library, loads Glue native library via + * {@link com.jogamp.common.os.DynamicLibraryBundleInfo#loadJNILibrary()} + * and resolves the optional Tool's <pre>GetProcAddress</pre> using {@link com.jogamp.common.os.DynamicLibraryBundleInfo#getToolGetProcAddressFuncNameList()}. + */ +public class DynamicLibraryBundle implements DynamicLookupHelper { + protected static final boolean DEBUG = NativeLibrary.DEBUG; + protected static final boolean DEBUG_LOOKUP = NativeLibrary.DEBUG_LOOKUP; + + private DynamicLibraryBundleInfo info; + + private List/*<List<String>>*/ toolLibNames; + private boolean[] toolLibLoaded; + private int toolLibLoadedNumber; + protected List/*<NativeLibrary>*/ nativeLibraries; + + private List/*<String>*/ glueLibNames; + private boolean[] glueLibLoaded; + private int glueLibLoadedNumber; + + private long toolGetProcAddressHandle; + private HashSet toolGetProcAddressFuncNameSet; + private List toolGetProcAddressFuncNameList; + + public DynamicLibraryBundle(DynamicLibraryBundleInfo info) { + if(null==info) { + throw new RuntimeException("Null DynamicLibraryBundleInfo"); + } + this.info = info; + if(DEBUG) { + System.out.println("DynamicLibraryBundle.init start with: "+info.getClass().getName()); + } + nativeLibraries = new ArrayList(); + toolLibNames = info.getToolLibNames(); + glueLibNames = info.getGlueLibNames(); + loadLibraries(); + toolGetProcAddressFuncNameList = info.getToolGetProcAddressFuncNameList(); + if(null!=toolGetProcAddressFuncNameList) { + toolGetProcAddressFuncNameSet = new HashSet(toolGetProcAddressFuncNameList); + toolGetProcAddressHandle = getToolGetProcAddressHandle(); + } else { + toolGetProcAddressFuncNameSet = new HashSet(); + toolGetProcAddressHandle = 0; + } + if(DEBUG) { + System.out.println("DynamicLibraryBundle.init Summary: "+info.getClass().getName()); + System.out.println(" toolGetProcAddressFuncNameList: "+MiscUtils.toString(toolGetProcAddressFuncNameList)); + System.out.println(" Tool Lib Names : "+MiscUtils.toString(toolLibNames)); + System.out.println(" Tool Lib Loaded: "+getToolLibLoadedNumber()+"/"+getToolLibNumber()+", complete "+isToolLibComplete()); + System.out.println(" Glue Lib Names : "+MiscUtils.toString(glueLibNames)); + System.out.println(" Glue Lib Loaded: "+getGlueLibLoadedNumber()+"/"+getGlueLibNumber()+", complete "+isGlueLibComplete()); + System.out.println(" All Complete: "+isLibComplete()); + } + } + + public final boolean isLibComplete() { + return isToolLibComplete() && isGlueLibComplete() ; + } + + public final int getToolLibNumber() { + return toolLibNames.size(); + } + + public final int getToolLibLoadedNumber() { + return toolLibLoadedNumber; + } + + public final boolean isToolLibComplete() { + return getToolLibNumber() == getToolLibLoadedNumber(); + } + + public final boolean isToolLibLoaded() { + return 0 < toolLibLoadedNumber; + } + + public final boolean isToolLibLoaded(int i) { + if(0 <= i && i < toolLibLoaded.length) { + return toolLibLoaded[i]; + } + return false; + } + + public final int getGlueLibNumber() { + return glueLibNames.size(); + } + + public final int getGlueLibLoadedNumber() { + return glueLibLoadedNumber; + } + + public final boolean isGlueLibComplete() { + return getGlueLibNumber() == getGlueLibLoadedNumber(); + } + + public final boolean isGlueLibLoaded(int i) { + if(0 <= i && i < glueLibLoaded.length) { + return glueLibLoaded[i]; + } + return false; + } + + public final DynamicLibraryBundleInfo getBundleInfo() { return info; } + + protected long getToolGetProcAddressHandle() { + if(!isToolLibLoaded()) { + return 0; + } + long aptr = 0; + for(Iterator iter=toolGetProcAddressFuncNameList.iterator(); 0==aptr && iter.hasNext(); ) { + String name = (String) iter.next(); + aptr = dynamicLookupFunctionOnLibs(name); + if(DEBUG) { + System.out.println("getToolGetProcAddressHandle: "+name+" -> 0x"+Long.toHexString(aptr)); + } + } + return aptr; + } + + protected NativeLibrary loadFirstAvailable(List/*<String>*/ libNames, ClassLoader loader, boolean global) { + for (Iterator iter = libNames.iterator(); iter.hasNext(); ) { + NativeLibrary lib = NativeLibrary.open((String) iter.next(), loader, global); + if (lib != null) { + return lib; + } + } + return null; + } + + private void loadLibraries() { + if( null == toolLibNames || toolLibNames.size() == 0) { + if(DEBUG) { + System.out.println("No Tool native library names given"); + } + return; + } + + if( null == glueLibNames || glueLibNames.size() == 0 ) { + if(DEBUG) { + System.out.println("No Glue native library names given"); + } + return; + } + + toolLibLoadedNumber = 0; + int i; + toolLibLoaded = new boolean[toolLibNames.size()]; + for(i=0; i<toolLibNames.size(); i++) { + toolLibLoaded[i] = false; + } + + glueLibLoaded = new boolean[glueLibNames.size()]; + for(i=0; i<glueLibNames.size(); i++) { + glueLibLoaded[i] = false; + } + + ClassLoader loader = getClass().getClassLoader(); + NativeLibrary lib = null; + + i=0; + for(Iterator iter = toolLibNames.iterator(); iter.hasNext(); i++) { + Object listObj = iter.next(); + List/*<String>*/ libNames = null; + if(listObj instanceof List) { + libNames = (List) listObj; + } else if(listObj instanceof String) { + libNames = new ArrayList(); + libNames.add((String)listObj); + } else { + throw new RuntimeException("List element "+i+" must be either a List or String: "+MiscUtils.toString(toolLibNames)); + } + if( null != libNames && libNames.size() > 0 ) { + lib = loadFirstAvailable(libNames, loader, info.shallLinkGlobal()); + if ( null == lib ) { + if(DEBUG) { + System.out.println("Unable to load any Tool library of: "+MiscUtils.toString(libNames)); + } + } else { + nativeLibraries.add(lib); + toolLibLoaded[i]=true; + toolLibLoadedNumber++; + if(DEBUG) { + System.out.println("Loaded Tool library: "+lib); + } + } + } + } + if( !isToolLibLoaded() ) { + if(DEBUG) { + System.out.println("No Tool libraries loaded"); + } + return; + } + + glueLibLoadedNumber = 0; + i=0; + for(Iterator iter = glueLibNames.iterator(); iter.hasNext(); i++) { + String libName = (String) iter.next(); + boolean ignoreError = true; + boolean res; + try { + res = GlueJNILibLoaderBase.loadLibrary(libName, ignoreError); + if(DEBUG && !res) { + System.out.println("Info: Could not load JNI/Glue library: "+libName); + } + } catch (UnsatisfiedLinkError e) { + res = false; + if(DEBUG) { + System.out.println("Unable to load JNI/Glue library: "+libName); + e.printStackTrace(); + } + } + glueLibLoaded[i] = res; + if(res) { + glueLibLoadedNumber++; + } + } + } + + private long dynamicLookupFunctionOnLibs(String funcName) { + if(!isToolLibLoaded() || null==funcName) { + if(DEBUG_LOOKUP && !isToolLibLoaded()) { + System.err.println("Lookup-Native: <" + funcName + "> ** FAILED ** Tool native library not loaded"); + } + return 0; + } + long addr = 0; + NativeLibrary lib = null; + + if(info.shallLookupGlobal()) { + // Try a global symbol lookup first .. + addr = NativeLibrary.dynamicLookupFunctionGlobal(funcName); + } + // Look up this function name in all known libraries + for (Iterator iter = nativeLibraries.iterator(); 0==addr && iter.hasNext(); ) { + lib = (NativeLibrary) iter.next(); + addr = lib.dynamicLookupFunction(funcName); + } + if(DEBUG_LOOKUP) { + String libName = ( null == lib ) ? "GLOBAL" : lib.toString(); + if(0!=addr) { + System.err.println("Lookup-Native: <" + funcName + "> 0x" + Long.toHexString(addr) + " in lib " + libName ); + } else { + System.err.println("Lookup-Native: <" + funcName + "> ** FAILED ** in libs " + MiscUtils.toString(nativeLibraries)); + } + } + return addr; + } + + public long dynamicLookupFunction(String funcName) { + if(!isToolLibLoaded() || null==funcName) { + if(DEBUG_LOOKUP && !isToolLibLoaded()) { + System.err.println("Lookup: <" + funcName + "> ** FAILED ** Tool native library not loaded"); + } + return 0; + } + + if(toolGetProcAddressFuncNameSet.contains(funcName)) { + return toolGetProcAddressHandle; + } + + long addr = 0; + + if(0 != toolGetProcAddressHandle) { + addr = info.toolDynamicLookupFunction(toolGetProcAddressHandle, funcName); + if(DEBUG_LOOKUP) { + if(0!=addr) { + System.err.println("Lookup-Tool: <"+funcName+"> 0x"+Long.toHexString(addr)); + } + } + } + if(0==addr) { + addr = dynamicLookupFunctionOnLibs(funcName); + } + return addr; + } + + /** Inherit access */ + static class GlueJNILibLoaderBase extends JNILibLoaderBase { + protected static synchronized boolean loadLibrary(String libname, boolean ignoreError) { + return JNILibLoaderBase.loadLibrary(libname, ignoreError); + } + } +} + diff --git a/src/java/com/jogamp/common/os/DynamicLibraryBundleInfo.java b/src/java/com/jogamp/common/os/DynamicLibraryBundleInfo.java new file mode 100644 index 0000000..37ca538 --- /dev/null +++ b/src/java/com/jogamp/common/os/DynamicLibraryBundleInfo.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2010, Sven Gothel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Sven Gothel nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Sven Gothel BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jogamp.common.os; + +import java.util.*; +import java.security.*; + +public interface DynamicLibraryBundleInfo { + public static final boolean DEBUG = DynamicLibraryBundle.DEBUG; + + /** @return a list of Tool library names or alternative library name lists.<br> + * <ul> + * <li>GL/GLU example Unix: [ [ "libGL.so.1", "libGL.so", "GL" ], [ "libGLU.so", "GLU" ] ] </li> + * <li>GL/GLU example Windows: [ "OpenGL32", "GLU32" ] </li> + * <li>Cg/CgGL example: [ [ "libCg.so", "Cg" ], [ "libCgGL.so", "CgGL" ] ] </li> + * </pre> + */ + public List getToolLibNames(); + + /** @return a list of Glue library names.<br> + * <ul> + * <li>GL: [ "nativewindow_x11", "jogl_gl2es12", "jogl_desktop" ] </li> + * <li>NEWT: [ "nativewindow_x11", "newt" ] </li> + * <li>Cg: [ "nativewindow_x11", "jogl_cg" ] </li> + * </ul><br> + * Only the last entry is crucial, ie all other are optional preload dependencies and may generate errors, + * which are ignored. + */ + public List/*<String>*/ getGlueLibNames(); + + /** May return the native libraries <pre>GetProcAddressFunc</pre> names, the first found function is being used.<br> + * This could be eg: <pre> glXGetProcAddressARB, glXGetProcAddressARB </pre>.<br> + * If your Tool does not has this facility, just return null. + */ + public List getToolGetProcAddressFuncNameList() ; + + /** May implement the lookup function using the Tools facility.<br> + * The actual function pointer is provided to allow proper bootstrapping of the ProcAddressTable.<br> + */ + public long toolDynamicLookupFunction(long toolGetProcAddressHandle, String funcName); + + /** @return true if the native library symbols shall be made available for symbol resolution of subsequently loaded libraries. */ + public boolean shallLinkGlobal(); + + /** @return true if the dynamic symbol lookup shall happen system wide, over all loaded libraries. Otherwise only the loaded native libraries are used for lookup, which shall be the default. */ + public boolean shallLookupGlobal(); + +} + + diff --git a/src/java/com/jogamp/common/os/NativeLibrary.java b/src/java/com/jogamp/common/os/NativeLibrary.java index 897e240..97aabae 100755 --- a/src/java/com/jogamp/common/os/NativeLibrary.java +++ b/src/java/com/jogamp/common/os/NativeLibrary.java @@ -62,7 +62,8 @@ public class NativeLibrary implements DynamicLookupHelper { private static final int WINDOWS = 1; private static final int UNIX = 2; private static final int MACOSX = 3; - private static boolean DEBUG; + protected static boolean DEBUG; + protected static boolean DEBUG_LOOKUP; private static int platform; private static DynamicLinker dynLink; private static String[] prefixes; @@ -81,7 +82,8 @@ public class NativeLibrary implements DynamicLookupHelper { platform = UNIX; } - DEBUG = (System.getProperty("gluegen.debug.NativeLibrary") != null); + DEBUG = (System.getProperty("jogamp.debug.NativeLibrary") != null); + DEBUG_LOOKUP = (System.getProperty("jogamp.debug.NativeLibrary.Lookup") != null); return null; } diff --git a/src/java/com/jogamp/common/os/WindowsDynamicLinkerImpl.java b/src/java/com/jogamp/common/os/WindowsDynamicLinkerImpl.java index 935f386..7bbfe23 100755 --- a/src/java/com/jogamp/common/os/WindowsDynamicLinkerImpl.java +++ b/src/java/com/jogamp/common/os/WindowsDynamicLinkerImpl.java @@ -11,7 +11,7 @@ public class WindowsDynamicLinkerImpl implements DynamicLinker { static { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { - DEBUG = (System.getProperty("gluegen.debug.NativeLibrary") != null); + DEBUG = (System.getProperty("jogamp.debug.NativeLibrary") != null); return null; } }); |