pondělí 2. listopadu 2009

Ubuntu 9.10 64bit and custom 32bit JDK and Eclipse 3.5 pwned

In this short HOWTO, I recap installation of 32bit JDK and Eclipse on 64bit linux platform. Nowadays 64bit linux distribution is not something special. Everything works fine, until is we want 32bit JDK on it - for me, I have one linux developer folder spread out to other team members, why force anybody to use 64bit at all.

OK. We have freshy new Ubuntu 9.10 amd64 with custom 32bit JDK downloaded from Sun. Why Ubuntu supports only 32bit JRE and not JDK???

Shorty mentioned, full how-to may be found here

  1. download JDK from java.sun.com
  2. unzip in /usr/lib/jvm
  3. good behaviour is create symlink pointed to /usr/lib/jvm/java -> /usr/lib/jvm/jdk1.6.0_16
  4. create /etc/profile.d/setup-dev-env.sh, which is setted up for every user, for console and graphical work
  5. export JAVA_HOME=/usr/lib/jvm/java 
    export JDK_HOME=$JAVA_HOME
    
  6. optionally, you may re-write custom create-jvm-alternative script, which sets up additional envirnonment variables and fonts, browser plugins (which on 64bit firefox doen't work of course).

    You are familiar with
    update-java-alternatives -l #list of all alternatives
    update-java-alternatives -s jdk1.6.0_16 #sets to particular one
    
    but its not necessary if you change eclipse.ini file to point -vm argument to your java installation.
    -startup
    plugins/org.eclipse.equinox.launcher_1.0.200.v20090520.jar
    --launcher.library
    plugins/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.200.v20090520
    -product
    org.eclipse.epp.package.jee.product
    -showsplash
    org.eclipse.platform
    --launcher.XXMaxPermSize
    512m
    -vm
    /usr/lib/jvm/java/bin/java
    -vmargs
    -Dosgi.requiredJavaVersion=1.5
    -XX:MaxPermSize=512m
    -Xms80m
    -Xmx768m
    
OK. We have 32bit JDK installed, 32bit Eclipse installed. On Ubuntu 9.10, there is one problem with GTK2 and workaround for bug "Eclipse buttons in Ubuntu 9.10" is known.

We must create custom eclipse launcher, OK.
#!/bin/sh
export GDK_NATIVE_WINDOWS=1
/optdev/eclipse-3.5/eclipse
Everything works well, except internal SWT browser widget, you may found this exceptions on error console in eclipse or like this in Aptana IDE
(Build 1.5.0.25497) [ERROR] Unable to determine current running state of Aptana Studio
org.eclipse.swt.SWTError: No more handles [MOZILLA_FIVE_HOME='/usr/lib/xulrunner-1.9.1.4'] (java.lang.UnsatisfiedLinkError: no swt-mozilla-gtk-3550 or swt-mozilla-gtk in swt.library.path, java.library.path or the jar file)
    at org.eclipse.swt.SWT.error(SWT.java:3910)
    at org.eclipse.swt.browser.Mozilla.create(Mozilla.java:514)
    at org.eclipse.swt.browser.Browser.(Browser.java:119)
    at com.aptana.ide.documentation.views.TutorialView.createPartControl(TutorialView.java:59)
    at org.eclipse.ui.internal.ViewReference.createPartHelper(ViewReference.java:367)
    at org.eclipse.ui.internal.ViewReference.createPart(ViewReference.java:226)
    at org.eclipse.ui.internal.WorkbenchPartReference.getPart(WorkbenchPartReference.java:595)
    at org.eclipse.ui.internal.PartPane.setVisible(PartPane.java:313)
    at org.eclipse.ui.internal.ViewPane.setVisible(ViewPane.java:529)
    at org.eclipse.ui.internal.presentations.PresentablePart.setVisible(PresentablePart.java:180)
    at org.eclipse.ui.internal.presentations.util.PresentablePartFolder.select(PresentablePartFolder.java:270)
    at org.eclipse.ui.internal.presentations.util.LeftToRightTabOrder.select(LeftToRightTabOrder.java:65)
    at org.eclipse.ui.internal.presentations.util.TabbedStackPresentation.selectPart(TabbedStackPresentation.java:473)
    at org.eclipse.ui.internal.PartStack.refreshPresentationSelection(PartStack.java:1256)
    at org.eclipse.ui.internal.PartStack.setSelection(PartStack.java:1209)
    at org.eclipse.ui.internal.PartStack.showPart(PartStack.java:1608)
    at org.eclipse.ui.internal.PartStack.createControl(PartStack.java:649)
    at org.eclipse.ui.internal.PartStack.createControl(PartStack.java:576)
    at org.eclipse.ui.internal.PartSashContainer.createControl(PartSashContainer.java:568)
    at org.eclipse.ui.internal.PerspectiveHelper.activate(PerspectiveHelper.java:272)
    at org.eclipse.ui.internal.Perspective.onActivate(Perspective.java:981)
    at org.eclipse.ui.internal.WorkbenchPage.onActivate(WorkbenchPage.java:2626)
    at org.eclipse.ui.internal.WorkbenchWindow$27.run(WorkbenchWindow.java:2964)
    at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:70)
    at org.eclipse.ui.internal.WorkbenchWindow.setActivePage(WorkbenchWindow.java:2945)
    at org.eclipse.ui.internal.WorkbenchWindow.busyOpenPage(WorkbenchWindow.java:760)
    at org.eclipse.ui.internal.Workbench$21.runWithException(Workbench.java:1045)
    at org.eclipse.ui.internal.StartupThreading$StartupRunnable.run(StartupThreading.java:31)
    at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35)
    at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:134)
    at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:3468)
    at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3115)
    at org.eclipse.ui.application.WorkbenchAdvisor.openWindows(WorkbenchAdvisor.java:803)
    at org.eclipse.ui.internal.Workbench$28.runWithException(Workbench.java:1384)
    at org.eclipse.ui.internal.StartupThreading$StartupRunnable.run(StartupThreading.java:31)
    at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35)
    at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:134)
    at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:3468)
    at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3115)
    at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2316)
    at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2221)
    at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:500)
    at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
    at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:493)
    at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
    at com.aptana.ide.rcp.IDEApplication.start(IDEApplication.java:121)
    at com.aptana.ide.desktop.integration.Application.start(Application.java:56)
    at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:194)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:368)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:559)
    at org.eclipse.equinox.launcher.Main.basicRun(Main.java:514)
    at org.eclipse.equinox.launcher.Main.run(Main.java:1311)
Caused by: java.lang.UnsatisfiedLinkError: no swt-mozilla-gtk-3550 or swt-mozilla-gtk in swt.library.path, java.library.path or the jar file
    at org.eclipse.swt.internal.Library.loadLibrary(Library.java:254)
    at org.eclipse.swt.internal.Library.loadLibrary(Library.java:159)
    at org.eclipse.swt.browser.Mozilla.create(Mozilla.java:499)
    ... 57 more
What to do to solve this strange problem? And this is thing what this article is about :)
  1. First of all, there is magical script called getlibs on Debian and ubuntu, by which you may download 32bit libraries needed by some executable. Install it, it will be invaluable in next steps.
  2. Cleverer may noticed that /usr/lib/xulrunner-1.9.1.4 is not xulrunner you need.

    Download 32bit one by getlibs and set up environmental variable MOZILLA_FIVE_HOME.

    getlibs -i xulrunner-1.9.1.4
    export MOZILLA_FIVE_HOME=/usr/lib32/xulrunner-1.9.1.4
  3. Unfortunately it's not all, we need swt-mozilla-gtk-3550 in 32bits, older version is in 64bit package libswt-mozilla-gtk-3.4-jni, but there is not something like libswt-mozilla-gtk-3.5-jni in 32 or 64bits. So we must download it manually - all -3550.so files - from eclipse subversion repository to /usr/lib32/jni folder
  4. Next thing I had to made, was looking to org.eclipse.swt.browser.Mozilla source code, what is trying to load. I created sample test class, where I simulated eclipse classloader loading behaviour.

    public class Main {
        private static final String JAVA_LIBRARY_PATH = "java.library.path";
    
        public static void main(String[] args) {
            String property = System.getProperty(JAVA_LIBRARY_PATH);
            System.out.println("Original java.library.path=" + property);
            try {
                System.loadLibrary("swt-mozilla-gtk-3550");
            } catch (UnsatisfiedLinkError e) {
                System.err.println("hacking attempt exception :)");
                e.printStackTrace();
            }
        }
    }
    
  5. Executing this piece of code, I figured this out (each time executed getlibs and created symlink to point somewhere in java.library.path). We must download these 32bit libraries to relieve of dependency hell.
    getlibs -l libxcb-atom.so.1
    getlibs -l libxcb-event.so.1
    getlibs -l libxcb-aux.so.0
    getlibs -l libstartup-notification-1.so.0
    getlibs -l libhunspell-1.2.so.0
    getlibs -l libxpcom.so
    
  6. Last but not least is set up environmental variable LD_LIBRARY_PATH to be pointed to 32bit libs. So final /etc/profile.d/setup-dev-env.sh will be:
    export JAVA_HOME=/usr/lib/jvm/java 
    export JDK_HOME=$JAVA_HOME
    export MOZILLA_FIVE_HOME=/usr/lib32/xulrunner-1.9.1.4/
    
    And final eclipse eclipse executable will be (because of this variables are cleared somehow in ubuntu after executing profile script):
    #!/bin/sh
    export GDK_NATIVE_WINDOWS=1
    export LD_LIBRARY_PATH=/usr/lib32/jni:/usr/lib32
    /optdev/eclipse-3.5/eclipse
    
  7. And vuala. We have working custom Eclipse 32bit installation on 32bit JDK and 64bit linux with 32bit xulrunner and his dependencies. We have working SWT browser widget and eclipse welcome screen (BIRT reports preview, GWT less than 2.0-SNAPSHOT hosted mode and so on...). Well done, dude ;)