2

I have an Eclipse-based SWT application, not using Maven.

My application targets multiple operating systems (CentOS, Windows, and Mac).

The only jar file that is not OS agnostic is the SWT library, which is specific to each OS type, not to mention processor type (x86 and/or x64).

I saw this other issue, but that targets Maven and I am not using Maven.

I have "org.eclipse.swt" added to my project by following an outlined procedure and including the entire SWT downloaded ZIP file. That specifies a second project in Package Explorer.

Earlier when I was just including swt.jar, it was a bit easier, as I just had to delete the jar, include the new one, and rebuild, but that was a a pain. Now that I use the entire SWT ZIP, the process is a bit tedious and not professional.

What are the steps, so that when I specify "right click > Java > Runnable JAR file" to create a single executable jar that I get 3 (or however many) different jar files, one per operating system? Visual Studio does that nicely, just I do not know how to do that here in Eclipse.

UPDATE: To answer a comment, I wanted to add JFace support, as I want to use the TableViewer feature, which requires JFace. Eclipse has this page outlining in the first part how to add in SWT. The steps work except for adding the source code at the end, but that is off-topic.

I followed the steps for 64-bit Windows, however I have to support CENTOS and Mac would be a "would be nice" at the moment.

Independent of swt.jar verses org.eclipse.swt, I would like a clean way (think Visual Studio with .Net) to build a single runnable/executable jar file for my application, one per supported OS type. My thought is that I specify build (whatever menu key sequence after I set things up) and I get one single executable jar file per target OS.

Community
  • 1
  • 1
Sarah Weinberger
  • 15,041
  • 25
  • 83
  • 130
  • Can you explain what you mean with _"Now that I use the entire SWT ZIP"_? What does that include? And why is just the .jar not sufficient? – Baz Mar 10 '14 at 15:15
  • I will explain the new method, however my question is independent of that. I am tired of deleting and adding SWT.jar every time I do a build and wanted to know if Eclipse provided a cleaner way to do multi-platform development. I come out with different build regularly, and a streamlined approach would be nice. – Sarah Weinberger Mar 10 '14 at 15:22
  • I know that's not what you're asking for, but did you consider creating one single jar that runs on all platforms? AFAIK, there is no built-in way to export multiple jars for multiple platforms unless you are using Eclipse-RCP. – Baz Mar 10 '14 at 15:31
  • I am open to that, but did not know that is possible. I am still learning about Eclipse and Java. How would that be done? I come from a Windows background, so creating a single executable file (appname.exe) that targets every possible OS is not possible, so I assumed the same for Java, especially with SWT being OS and platform (x64 or x86) dependent. – Sarah Weinberger Mar 10 '14 at 15:34
  • There are several questions about how to do that ([here](http://stackoverflow.com/questions/2706222/create-cross-platform-java-swt-application) and [here](http://stackoverflow.com/questions/2037220/how-can-i-creating-executable-jar-with-swt-that-runs-on-all-platforms) for example). I'm using this approach myself and could even send you some code if that would be helpful. – Baz Mar 10 '14 at 15:37
  • The single approach is cleaver and solves the problem, although the JFace throws a bit of an obstacle, but my question is still interesting, nonetheless. I came across this link posted in one of the two links that you gave, http://www.chrisnewland.com/select-correct-swt-jar-for-your-os-and-jvm-at-runtime-191, but that deals with a single swt.jar not the zip file. – Sarah Weinberger Mar 10 '14 at 16:42
  • Using the method outlined by Chris Ewland, http://www.chrisnewland.com/select-correct-swt-jar-for-your-os-and-jvm-at-runtime-191, I ran into problems. Simply adding in the various SWT.jars using [Project | Right click | Build Path | Configure Build Path... | Libraries] renders no swt.jars added to the library. I want to create a single JAR as per Baz recommendation. Not possible? – Sarah Weinberger Mar 10 '14 at 19:37
  • Baz, which approach do you use and can you send/post source? I Chhris Ewland's approach, but could not get past the missing SWT source, when executing the "display = Display.getDefault();" line. I had to add one of the SWT.jar files to the project libraries to get to build. As far as the other method with a jar in jar approach, I am not following how to build the two jars in Eclipse. Eclipse adds all my classes automatically, so not sure why I would need to add that again. An example would help. – Sarah Weinberger Mar 10 '14 at 20:51
  • Putting together a sample project just now. Will have to test it on a linux machine tonight and will post it later on (tomorrow at the latest)... – Baz Mar 11 '14 at 09:31
  • Did this work out for you in the end? – Baz Mar 17 '14 at 18:03

1 Answers1

0

Right, despite me saying that you can create a single .jar file for all platforms, I wasn't able to get it working properly.

However, I managed to get an example project up and running that will create a separate .jar file for each platform for you by simply using Ant.

You can download the whole project here.

The build script looks like this:

<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" />

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

    <!-- Define the class path -->
    <path id="classpath">
        <fileset dir="${lib.dir}" includes="**/*.jar" />
        <fileset dir="${lib.deploy.dir}" includes="**/swt_linux_gtk_x86.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>

    <!-- Define classpath and create the jar folder -->
    <target name="pre_jar" depends="compile">
        <pathconvert property="manifest.classpath" pathsep=" ">
            <path refid="classpath" />
            <mapper>
                <chainedmapper>
                    <flattenmapper />
                    <globmapper from="*.jar" to="*.jar" />
                </chainedmapper>
            </mapper>
        </pathconvert>

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

    <!-- Create the jar files -->
    <target name="jar" depends="pre_jar">
        <!-- Linux 32bit -->
        <jar destfile="${jar.dir}/${ant.project.name}_linux_gtk_x86.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="./ ${manifest.classpath}" />
            </manifest>

            <zipgroupfileset dir="${lib.dir}" includes="**/jar-in-jar-loader.jar" />
            <zipfileset dir="${lib.deploy.dir}" includes="**/swt_linux_gtk_x86.jar" />
            <zipfileset dir="${lib.dir}" includes="**/*.jar" excludes="**/jar-in-jar-loader.jar" />
        </jar>
        <!-- Linux 64bit -->
        <jar destfile="${jar.dir}/${ant.project.name}_linux_gtk_x64.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="./ ${manifest.classpath}" />
            </manifest>

            <zipgroupfileset dir="${lib.dir}" includes="**/jar-in-jar-loader.jar" />
            <zipfileset dir="${lib.deploy.dir}" includes="**/swt_linux_gtk_x64.jar" />
            <zipfileset dir="${lib.dir}" includes="**/*.jar" excludes="**/jar-in-jar-loader.jar" />
        </jar>
        <!-- Windows 32bit -->
        <jar destfile="${jar.dir}/${ant.project.name}_win32_x86.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="./ ${manifest.classpath}" />
            </manifest>

            <zipgroupfileset dir="${lib.dir}" includes="**/jar-in-jar-loader.jar" />
            <zipfileset dir="${lib.deploy.dir}" includes="**/swt_win32_x86.jar" />
            <zipfileset dir="${lib.dir}" includes="**/*.jar" excludes="**/jar-in-jar-loader.jar" />
        </jar>
        <!-- Windows 64bit -->
        <jar destfile="${jar.dir}/${ant.project.name}_win32_x64.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="./ ${manifest.classpath}" />
            </manifest>

            <zipgroupfileset dir="${lib.dir}" includes="**/jar-in-jar-loader.jar" />
            <zipfileset dir="${lib.deploy.dir}" includes="**/swt_win32_x64.jar" />
            <zipfileset dir="${lib.dir}" includes="**/*.jar" excludes="**/jar-in-jar-loader.jar" />
        </jar>
        <!-- MacOS 32bit -->
        <jar destfile="${jar.dir}/${ant.project.name}_macos_x86.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="./ ${manifest.classpath}" />
            </manifest>

            <zipgroupfileset dir="${lib.dir}" includes="**/jar-in-jar-loader.jar" />
            <zipfileset dir="${lib.deploy.dir}" includes="**/swt_macosx_x86.jar" />
            <zipfileset dir="${lib.dir}" includes="**/*.jar" excludes="**/jar-in-jar-loader.jar" />
        </jar>
        <!-- MacOS 64bit -->
        <jar destfile="${jar.dir}/${ant.project.name}_macos_x64.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="./ ${manifest.classpath}" />
            </manifest>

            <zipgroupfileset dir="${lib.dir}" includes="**/jar-in-jar-loader.jar" />
            <zipfileset dir="${lib.deploy.dir}" includes="**/swt_macosx_x64.jar" />
            <zipfileset dir="${lib.dir}" includes="**/*.jar" excludes="**/jar-in-jar-loader.jar" />
        </jar>
    </target>

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

</project>

The project itself is nothing fancy, just a JFace Dialog to show that JFace works as well.


NOTE:

To make this compile on a Windows machine, you will have to change one line:

<fileset dir="${lib.deploy.dir}" includes="**/swt_linux_gtk_x86.jar" />

change it to:

<fileset dir="${lib.deploy.dir}" includes="**/swt_win32_x64.jar" />

or

<fileset dir="${lib.deploy.dir}" includes="**/swt_win32_x86.jar" />

Basically, this line has to represent YOUR system, i.e., the system you're compiling on.

Baz
  • 36,440
  • 11
  • 68
  • 94