Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Build one jar per platform for multi-platform SWT application

There are a couple of questions to this topic already, but none of them seem to work properly.

Here is a list of them:

  • Bulding an multi-platform SWT application using Ant
  • Build multi-platform executable for a SWT application (Eclipse)
  • Build multi-platform executable for a SWT application using maven
  • SWT jar for different platform
  • Create cross platform Java SWT Application

My requirement is to build an ant script that creates one jar per platform, i.e. one for Windows x86, one for Windows x64, Linux x86/x64 and so on.

Does anyone have any further insight?

Using the aforementioned methods, I was not able to produce a workable solution. It either ended with the SWT jar file not automatically being loaded or it not being included in the classpath.

If someone can come up with a working example (ideally including the complete source code), that would be grand!

like image 454
Baz Avatar asked Apr 29 '14 08:04

Baz


1 Answers

Right, so I finally came up with a solution that I successfully tested on three platforms.

The two magic components are the jar-in-jar-loader and a proper build script.

The build script with comments can be found here:

<project name="RandomApp" basedir="." default="clean-build">

    <property name="src.dir" value="src" />

    <!-- Define the necessary paths -->
    <property name="build.dir" value="bin_temp" />
    <property name="lib.dir" value="lib" />
    <property name="lib.deploy.dir" value="lib_swt" />
    <property name="classes.dir" value="${build.dir}/classes" />
    <property name="jar.dir" value="${build.dir}/jar" />
    <property name="img.dir" value="img" />
    <property name="res.dir" value="res" />

    <!-- Define the main class -->
    <property name="main-class" value="org.baz.desktop.randomapp.gui.RandomApp" />

    <path id="base-classpath">
        <fileset dir="${lib.dir}" includes="**/*.jar" />
    </path>

    <!-- Define the class path -->
    <path id="classpath">
        <fileset dir="${lib.dir}" includes="**/*.jar" />
        <fileset dir="${lib.deploy.dir}" includes="**/swt_win32_x64.jar" />
    </path>

    <!-- Clean previously built files -->
    <target name="clean">
        <delete dir="${build.dir}" />
    </target>

    <!-- Compile the project -->
    <target name="compile">
        <mkdir dir="${classes.dir}" />
        <javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath" includeantruntime="false" />
    </target>

    <macrodef name="createclasspath">
        <attribute name="name" />
        <attribute name="swtlib" />
        <sequential>
            <pathconvert property="@{name}.classpath" pathsep=" ">
                <path refid="base-classpath" />
                <fileset dir="${lib.deploy.dir}" includes="**/swt_@{swtlib}.jar" />
                <mapper>
                    <chainedmapper>
                        <flattenmapper />
                        <globmapper from="*.jar" to="*.jar" />
                    </chainedmapper>
                </mapper>
            </pathconvert>
        </sequential>
    </macrodef>

    <!-- Define classpath and create the jar folder -->
    <target name="pre_jar" depends="compile">
        <!-- Linux 32bit -->
        <createclasspath name="win86" swtlib="win32_x86" />
        <!-- Linux 64bit -->
        <createclasspath name="win64" swtlib="win32_x64" />
        <!-- Windows 32bit -->
        <createclasspath name="linux86" swtlib="linux_gtk_x86" />
        <!-- Windows 64bit -->
        <createclasspath name="linux64" swtlib="linux_gtk_x64" />
        <!-- MacOS 32bit -->
        <createclasspath name="macos86" swtlib="macos_x86" />
        <!-- MacOS 64bit -->
        <createclasspath name="macos64" swtlib="macos_x64" />

        <mkdir dir="${jar.dir}" />
    </target>

    <macrodef name="createjar">
        <attribute name="swtlib" />
        <attribute name="swtclasspath" />
        <sequential>
            <jar destfile="${jar.dir}/${ant.project.name}_@{swtlib}.jar" basedir="${classes.dir}">
                <manifest>
                    <attribute name="Main-Class" value="org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader" />
                    <attribute name="Rsrc-Main-Class" value="${main-class}" />
                    <attribute name="Class-Path" value="." />
                    <attribute name="Rsrc-Class-Path" value="./ @{swtclasspath}" />
                </manifest>

                <zipgroupfileset dir="${lib.dir}" includes="**/jar-in-jar-loader.jar" />
                <zipfileset dir="${lib.deploy.dir}" includes="**/swt_@{swtlib}.jar" />
                <zipfileset dir="${lib.dir}" includes="**/*.jar" excludes="**/jar-in-jar-loader.jar" />
            </jar>
        </sequential>
    </macrodef>

    <!-- Create the jar files -->
    <target name="jar" depends="pre_jar">
        <!-- Linux 32bit -->
        <createjar swtlib="linux_gtk_x86" swtclasspath="${linux86.classpath}" />
        <!-- Linux 64bit -->
        <createjar swtlib="linux_gtk_x64" swtclasspath="${linux64.classpath}" />
        <!-- Windows 32bit -->
        <createjar swtlib="win32_x86" swtclasspath="${win86.classpath}" />
        <!-- Windows 64bit -->
        <createjar swtlib="win32_x64" swtclasspath="${win64.classpath}" />
        <!-- MacOS 32bit -->
        <createjar swtlib="macos_x86" swtclasspath="${macos86.classpath}" />
        <!-- MacOS 64bit -->
        <createjar swtlib="macos_x64" swtclasspath="${macos64.classpath}" />
    </target>

    <target name="clean-build" depends="clean,jar" />

</project>

What it basically does is define a base classpath without any SWT library. Then it creates platform specific classpaths using the base one and adding the appropriate platform SWT library.

The jar task then creates a separate jar for each platform using these classpaths and the jar-in-jar-loader.

And that's it, a fully automated way of generating jars for each (supported) platform.


I've created an example project that people can download and test out. It's an easy starting point for a multi-platform application.

https://www.dropbox.com/s/ianrbl4bn0fmsdi/SWTApplication.7z


Update:

I've managed to significantly shorten the ant script by making proper use of macrodef :)

like image 119
Baz Avatar answered Oct 30 '22 12:10

Baz