Dynamic loading of the .DLLs - hitting a snag

Hey, guys.

I’m trying to dynamically load the libs for jOGL in code so as not to require a -classpath/-Djava.library.path command line issue.

This is the function as I have it right now:

/** Load the appropriate libraries for the JOGL bindings.
* @param iOS An operating system constant (see above in GameFrame.java) /
public static void loadGL(int iOS)
{
try
{
URL urlJOGL = (new File(Tools.GetRelativePath(null) + Tools.GetFileSeparator() + “jogl.jar”)).toURL();
URL[] urls = { urlJOGL };
new URLClassLoader(urls);
}
catch (MalformedURLException exc) { /
TODO: Log */ }

    String strJOGL = Tools.GetRelativePath("org.slage.ui.jogl.");
    switch (iOS)
    {
        case WIN32:                
            System.load(strJOGL + "jogl.dll");
            System.load(strJOGL + "jogl_cg.dll");                
            break;
        case LINUX:
            System.load(strJOGL + "libjogl.so");
            System.load(strJOGL + "libjogl_cg.so");
            break;
        case MACOSX:
            System.load(strJOGL + "libjogl.jnlib");
            System.load(strJOGL + "libjogl_cg.jnlib");
            break;
        case SOLARIS_SPARC:
            System.load(strJOGL + "libjogl_solsparc.so");
            break;
        case SOLARIS_X86:
            System.load(strJOGL + "libjogl_solx86.so");
            break;
    }       

}

Note: I renamed the solaris .so files so they would all have unique filenames; not sure if this will be an issue or not.

When I run this code, I get a message box from java.exe that tells me “A required DLL, jawt.dll, is not found…” etc. I checked my JRE and JDK directories; sure enough, it’s there. I also ran another AWT/Swing app to verify that it’s working. So, something in my code has to be causing this issue.

Does anyone have any suggestions on how to fix the problem, or another method for solving the dynamic loading quandary? ???

See the NativeLibLoader in the JOGL workspace. We’ve found it necessary to preload JAWT on most platforms to work around problems with that DLL not being in the user’s PATH.

I see that it’s trying to load it, but I don’t know what to do about the fact that it’s failing.

The manual loading of the JAWT via System.loadLibrary(“jawt”) doesn’t fail. It works around the fact that loading JOGL (which depends on JAWT) doesn’t work on most platforms unless the JAWT has been dynamically loaded first.

OK… I did this:


  static 
    {         
        // First, load in the JOGL.jar file 
        try
        {
            URL urlJOGL = (new File(Tools.GetRelativePath(null) + Tools.GetFileSeparator() + "jogl.jar")).toURL();
            URL[] urls = { urlJOGL };
            new URLClassLoader(urls);
        }
        catch (MalformedURLException exc) 
        { 
            // TODO: Log 
            System.err.println("MalformedURLException while loading jogl.jar"); 
        }                                
  
        // Manually load AWT to work around the problem with it not finding it 
        System.loadLibrary("awt");
        System.loadLibrary("jawt");
        
        
        // Now, load the .dll/.so files for the OpenGL C bindings 
        String strOS = Tools.GetOS();
        String strJOGL = Tools.GetRelativePath("org.slage.ui.jogl.");
        
        if (strOS.startsWith("Windows"))
        {
            System.load(strJOGL + "jogl.dll");
            System.load(strJOGL + "jogl_cg.dll");                
        }        
        if (strOS.startsWith("Mac OS X"))
        {
              System.load(strJOGL + "libjogl.jnlib");
              System.load(strJOGL + "libjogl_cg.jnlib");        
        }        
    }

I’m now getting a new error box:

“The procedure entry point cgNextParameter_depr_1_1 could not be loaded in the dynamic link library cg.dll.”

I’ve tried System.loadLibrary(“cg”); and it doesn’t help at all.

Any suggestions?

What version of Cg are you using? It looks like those functions were present in the 1.3 release of Cg and are absent in the current 1.4 release.

We would probably have to release another version of JOGL to bring it up to date with Cg 1.4. I’m a little reluctant to do that right now because it is becoming a maintenance problem preventing us from doing work on the JSR-231 APIs. Can you find a copy of the Cg 1.3 runtime?

As it stands, I have Cg 1.4 installed, but I’m not using Cg at all in this or any other project. I just installed it to play around with it one day. If I need Cg in order to make jOGL work, I’ll get whatever version is needed, but if I don’t plan on using Cg, could I just disable it or uninstall the runtime?

Yes, you can disable it – just don’t load the jogl_cg native library. You’ll get an UnsatisfiedLinkError if you later try to use Cg routines. We’ll upgrade JOGL to Cg 1.4 in the JSR-231 source tree.

Well, we’re getting closer.

Taking out the Cg stuff, I now can’t get the .jar file to dynamically load before it tries to create a subclass of its contents, so it’s throwing a NoClassDefFound. As it stands, the following code is in a static {} block in the class where main() is executed.


        try
        {
            URL urlJOGL = (new File(Tools.GetRelativePath(null) + Tools.GetFileSeparator() + "jogl.jar")).toURL();
            URL[] urls = { urlJOGL };
            new URLClassLoader(urls);
        }
        catch (MalformedURLException exc) 

So, trying to see what would happen, I commented this part out and then loaded the .jar using the -classpath command line option. When I did, I’m now getting an UnsatisfiedLink because awt.dll is already loaded. This is where I’m loading the .dll files:


// Manually load AWT to work around the problem with it not finding it         
        System.loadLibrary("awt");
        System.loadLibrary("jawt");        
        
        // Now, load the .dll/.so files for the OpenGL C bindings 
        String strOS = Tools.GetOS();
        String strJOGL = Tools.GetRelativePath("org.slage.ui.jogl.");
        
        if (strOS.startsWith("Windows"))
        {
            System.load(strJOGL + "jogl.dll");
            if (bLoadCg)
                System.load(strJOGL + "jogl_cg.dll");                
        }        
        if (strOS.startsWith("Mac OS X"))
        {
              System.load(strJOGL + "libjogl.jnlib");
              if (bLoadCg)
                System.load(strJOGL + "libjogl_cg.jnlib");        
        }        

You only told me to loadLibrary on jawt.dll, but when I did, I started getting error boxes that it couldn’t find awt.dll either, and adding that line stopped those boxes. Presumably, I now have to find a way to tell the JVM not to load AWT again.

Sorry to be such a pain.

Please post stack traces for some of the exceptions you’re seeing. I suspect the NoClassDefFoundError is occurring because of the delegation path of your class loaders. If you make a subordinate class loader to load JOGL and are trying to load classes which reference JOGL then those classes must be loaded from the same loader or a subordinate loader of the other one, because otherwise the “current” class loader (the one which your subordinate loader will delegate to by default) won’t know how to find the JOGL classes. Class loader delegation occurs up to the parent loader, not down to the child loader.

You need to call Toolkit.getDefaultToolkit() before trying to manually System.loadLibrary(“jawt”). Do not call loadLibrary(“awt”). It is loaded by the boot loader and loading it manually will break the JDK’s internal loading of it as you’ve found.

OK. Ignoring the jar for a minute (I can handle the classloader later…), I’m getting UnsatisfiedLinks on jogl.dll when I try to dynamically load it, now. Here’s the code:


  // this is called from a static initializer block in the class where main() is 
  public static void loadOpenGL()
    {         
        // Manually load AWT to work around the problem with error boxes coming up claiming it's not found. 
        // Apparently AWT has to be loaded -before- jogl's .dll files or all Hell breaks loose.
        java.awt.Toolkit.getDefaultToolkit();
        System.loadLibrary("jawt");                         
          
        // Now, load the .dll/.so files for the OpenGL C bindings 
        String strOS = Tools.GetOS();
        String strJOGL = Tools.GetRelativePath("lib") + Tools.GetFileSeparator();                
        
        if (strOS.startsWith("Windows"))
        {                        
            System.load(strJOGL + "jogl.dll");            
            
            if (bLoadCg)
                System.load(strJOGL + "jogl_cg.dll");                
        }        
        if (strOS.startsWith("Mac OS"))
        {
              System.load(strJOGL + "libjogl.jnlib");
              if (bLoadCg)
                System.load(strJOGL + "libjogl_cg.jnlib");        
        }                
        if (strOS.startsWith("Linux"))
        {
                System.load(strJOGL + "libjogl.so");
                if (bLoadCg)
                    System.load(strJOGL + "libjogl_cg.so");
        }
        if (strOS.startsWith("Solaris"))
        {
               String strArch = System.getProperty("os.arch");
               if (strArch.equalsIgnoreCase("sparc"))
               {
                   System.load(strJOGL + "libjogl_solsparc.so");
               }
               if (strArch.equalsIgnoreCase("x86"))
               {
                   System.load(strJOGL + "libjogl_solx86.so");
               }
        }
    }


And this is the exception trace I get:


Exception in thread "main" java.lang.UnsatisfiedLinkError: no jogl in java.library.path
        at java.lang.ClassLoader.loadLibrary(Unknown Source)
        at java.lang.Runtime.loadLibrary0(Unknown Source)
        at java.lang.System.loadLibrary(Unknown Source)
        at net.java.games.jogl.impl.NativeLibLoader$1.run(NativeLibLoader.java:72)
        at java.security.AccessController.doPrivileged(Native Method)
        at net.java.games.jogl.impl.NativeLibLoader.load(NativeLibLoader.java:58)
        at net.java.games.jogl.impl.GLContext.<clinit>(GLContext.java:52)
        at net.java.games.jogl.impl.windows.WindowsGLContextFactory.createGLContext(WindowsGLContextFactory.java:147)
        at net.java.games.jogl.GLCanvas.<init>(GLCanvas.java:72)
        at net.java.games.jogl.GLDrawableFactory.createGLCanvas(GLDrawableFactory.java:150)
        at net.java.games.jogl.GLDrawableFactory.createGLCanvas(GLDrawableFactory.java:118)
        at net.java.games.jogl.GLDrawableFactory.createGLCanvas(GLDrawableFactory.java:85)
        at org.slage.ui.GameFrame.<init>(GameFrame.java:84)
        at org.slage.SLAGE.initialize(SLAGE.java:94)
        at org.slage.tests.ImageTest.main(ImageTest.java:41)

All I want to do is get the dlls and jars loading in such a way as to prevent a lot of command line switches. It seems that I shouldn’t be the first person to have wanted to do this - what am I missing here?

Calling net.java.games.jogl.impl.NativeLibLoader.disableLoading() before doing any JOGL-related operations will avoid the exception above.

In the past two years there has only been one other request to do something similar to what you’re doing (which is why the enableLoading/disableLoading methods are exposed). I think most people are deploying JOGL apps with Java Web Start which takes care of this automatically. During development it isn’t difficult to write some simple wrapper scripts which set up either the PATH/LD_LIBRARY_PATH/CLASSPATH environment variables or -Djava.library.path/-classpath.

That did it! Once I get the .jar loading situation handled with a classloader, I’m all set.

You really are a ‘ninja’, Ken. Thanks much.

HI, i am also interested in dynamically loading those libs.
Want to use this for my engine. Tried this many times but no.
Will there maybe a built-in LibLoader in JSR-231 or standart loader?

Feel free to file a Request for Enhancement using the JOGL Issue Tracker.

Can you tell me what the Tools class is.

Consider it done:

https://jogl.dev.java.net/issues/show_bug.cgi?id=171
https://jogl.dev.java.net/issues/show_bug.cgi?id=172

It’s just a bunch of static utilities I wrote. Nothing major.

Here’s a version of the code, which now works, with the Tools calls replaced with straight java:


/** Static initialization  - load libraries */
      /** Ensure we load GL on startup. This is a replacement for the command-line switches
     *  -Djava.library.path=.
     *
     *  @param bLoadCg if 'true', load Cg libraries
     */
    public static void loadOpenGL(boolean bLoadCg)
    {         
        // workaround to allow our loader to do its job
        // see http://192.18.37.44/forums/index.php?topic=10262.0;topicseen
        net.java.games.jogl.impl.NativeLibLoader.disableLoading();
        
        // Manually load AWT to work around the problem with error boxes coming up claiming it's not found. 
        // Apparently AWT has to be loaded -before- jogl's .dll files or all Hell breaks loose.
        java.awt.Toolkit.getDefaultToolkit();
        System.loadLibrary("jawt");        
        
        // Now, load the .dll/.so files for the OpenGL C bindings 
        String strOS = System.getProperty("os.name");
        String strJOGL = System.getProperty("user.dir") + System.getProperty("file.separator") + "lib" + 
                System.getProperty("file.separator");
        
        if (strOS.startsWith("Windows"))
        {                        
            System.load(strJOGL + "jogl.dll");            
            
            if (bLoadCg)
                System.load(strJOGL + "jogl_cg.dll");                
        }        
        if (strOS.startsWith("Mac OS"))
        {
              System.load(strJOGL + "libjogl.jnlib");
              if (bLoadCg)
                System.load(strJOGL + "libjogl_cg.jnlib");        
        }                
        if (strOS.startsWith("Linux"))
        {
                System.load(strJOGL + "libjogl.so");
                if (bLoadCg)
                    System.load(strJOGL + "libjogl_cg.so");
        }
        if (strOS.startsWith("Solaris"))
        {
               String strArch = System.getProperty("os.arch");
               if (strArch.equalsIgnoreCase("sparc"))
               {
                   System.load(strJOGL + "libjogl_solsparc.so");
               }
               if (strArch.equalsIgnoreCase("x86"))
               {
                   System.load(strJOGL + "libjogl_solx86.so");
               }
        }
    }
  

Could this line of tought be extended so that the .so and .dll libs are loaded directly from a .jar ? And would it be possible to bake cg.dll (The Cg runtime) inside the .jar aswell ?

// Tomas :slight_smile:

It is not possible to System.load() a shared object directly from within a jar file. At a minimum it would have to be unpacked on to the local disk.