Building Eclipse Rich Client Application automatically (Tycho)

This post is attended to everyone who is creating Java applications with Eclipse Rich Client Platform. You will fins here a working tycho configuration on working demo project. That project can be build fully automatically with tycho on your CI server e.g. Jenkins.

If you have developed Eclipse RCP before, you may also come to the conclusion that PDE-Build out of Eclipse IDE is not really an appropriate and stable way to build serious, production ready applications. But also automation of PDE Build was not straightforward task, and a such is still not well documented.

Further maybe you heard about some alternatives like buckminister approach or athena. But tycho rule them all.

Tycho for PDE Build

Technically tycho PDE build is a set of maven plugins. Let it be said at the beginning, tycho tries to use all the eclipse PDE/JDT metadata first. One of the goals of tycho project is to minimize configuraton duplication between maven artefacts and Eclipse PDE project.

Here is the self-speaking list of tychos packaging types, i will covers some of them more detailed.

  • eclipse-plugin result in Eclipse Plug-In bundle
  • eclipse-test-plugin result in a test Plugin
  • eclipse-feature wich eclipse feature as Result
  • eclipse-application builds Eclipse Applicaton
  • eclipse-repository builds repository an executables
  • eclipse-update-site responisble for update-sites

Tycho current release is 0.13.0 and is used in my example.

Example Application

In this article used applicaton is Open source and can be cloned from GitHub (RCP Life Game1). This app is a very basic but working implementation of Conways Life Game. Technically it consist of:

  • one parent project,
  • one plugin project,
  • one feature,
  • as well as one target
  • and one repository project

Clone the Repository and you will be able to start the game out of eclipse IDE by clicking on the "Launch Eclipse Application" Button in the open org.holbreich.lfgm.eclipse-repository/example.product file.
As you know every RCP application should be build with a fixed set of the eclipse platform plugins so called target platform. That is where we start.

Target platform

Configuration of the target platform in eclipse can be stored in file with file-extension .target . So my example target platform definition looks like following.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>  
<?pde version="3.6"?>  
<target name="eclipse 3.7.1 (indigo)" sequenceNumber="16">  
 <locations>
  <location includeAllPlatforms="false" includeMode="planner" includeSource="false" type="InstallableUnit">
  <unit id="org.eclipse.rcp.source.feature.group" version="3.7.1.r37x_v20110729-9DB5FmNFnFLSFCtLxnRfMqt15A4A"/>
  <unit id="org.eclipse.equinox.sdk.feature.group" version="3.7.1.R37x_v20110907-7M7W8h8eNV4Vrz-hz01A7SL_MhZP"/>
  <unit id="org.eclipse.pde.feature.group" version="3.7.1.r37x_v20110810-0800-7b7qFVtFEx2XnmZ4jlM5mjM"/>
  <repository location="http://download.eclipse.org/releases/indigo"/>
 </location>
</locations>  
</target>  

Maven's central project configuration file is pom.xml. The Element build of the pom.xml is a central element where all the needed (plugin) declarations are placed, so that maven is able to get the knowlege about how to compile and build desired artefacts. Typically you'll find here the definition of needed maven plugins with their configurations, executions and goals2.

The target platform which was mentioned above is introduced to maven through mavens's build-helper-maven-plugin as an artifact. See the configuration section of that plugin.

<build>  
    <plugins>
       <plugin>
        <!-- Id and version of build helper plugin -->
    <groupId>org.codehaus.mojo</groupId>
        <artifactId>build-helper-maven-plugin</artifactId>
    <version>1.3</version>
        <executions>
        <execution>
          <id>attach-artifacts</id>
          <phase>package</phase>
          <goals>
            <goal>attach-artifact</goal>
          </goals>
          <configuration>
                <artifacts>
                             <artifact>
                 <file>indigo.target</file>
                 <type>target</type>
                 <classifier>indigo</classifier>
                 </artifact>
                 </artifacts>
          </configuration>
        </execution>
        </executions>
    </plugin>
    </plugins>
</build>  

Now our target platform can be used whenever we like and we would like to use it nearly everywhere, so that leads to the idea to provide this last configuration only once in the parent pom.xml of the maven parent project for the whole Life Game Application.

Parent project

A parent project is a maven way to handle a kind of configuration inheritance. My so called parent project defines some useful and multiply used things for all of the modules used in the current application and also provides me the ability to build the whole application at once. Let me show you the whole file here, excuse me if it appears a bit unreadable now.

<project xmlns="http://maven.apache.org/POM/4.0.0"  
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0  
http://maven.apache.org/xsd/maven-4.0.0.xsd">  
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.holbreich.lfgm</groupId>
  <artifactId>parent</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <packaging>pom</packaging>
  <name>Shuron's Life Game Maven Parent Project</name>

  <properties>
    <!-- just some properties, tycho version and encoding -->
  <tycho-version>0.13.0</tycho-version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
<!-- eclipse IDE flat project style. So parent project is only sibling folder  
   therefore has to acces his modules by "../". Here are all the child modules. -->
    <modules>
        <module>../org.holbreich.lfgm</module>
        <module>../org.holbreich.lfgm.target</module>
        <module>../org.holbreich.lfgm.feature</module>
        <module>../org.holbreich.lfgm.eclipse-repository</module>
    </modules>

    <build>
        <plugins>
                  <!-- defintion of tychos target-platform-configuration plugin -->
            <plugin>
                <groupId>org.eclipse.tycho</groupId>
                <artifactId>target-platform-configuration</artifactId>
                <version>${tycho-version}</version>
                <configuration>
                    <resolver>p2</resolver>
                    <target>
                            <!--  A reference to target platform artefact: -->
                        <artifact>
                            <groupId>org.holbreich.lfgm</groupId>
                            <artifactId>target-platform</artifactId>
                            <version>1.0.0-SNAPSHOT</version>
                            <classifier>indigo</classifier>
                        </artifact>
                    </target>
                    <ignoreTychoRepositories>true</ignoreTychoRepositories>
                           <!-- Environment configuration for the taget platform -->
                    <environments>
                        <environment>
                            <os>win32</os>
                            <ws>win32</ws>
                            <arch>x86</arch>
                        </environment>
                        <environment>
                            <os>linux</os>
                            <ws>gtk</ws>
                            <arch>x86</arch>
                          </environment>
                    </environments>
                </configuration>
            </plugin>
                 <!-- defintion of tycho-maven-plugin -->
            <plugin>
                <groupId>org.eclipse.tycho</groupId>
                <artifactId>tycho-maven-plugin</artifactId>
                <version>${tycho-version}</version>
                <extensions>true</extensions>
            </plugin>
        </plugins>
    </build>
</project>  

As already mentioned in the comments of the pom.xml that defines known modules and a set of plugins with their configuration. Actually two plugins:

  • target-platform-configuration - which refers to already discussed target platform artifact and provides additional environment configuration.
  • tycho-maven-plugin - which defines additional packaging types like eclipse-plugin and eclipse feature.

That configuration allows you to minimize pom.xml of the plugin's and features.

Plug-in pom.xml

As all used plugins are already defined in the parent, the actual the pom.xml file of the pluign project is pretty short and looks like this:

<?xml version="1.0" encoding="UTF-8"?>  
<project  
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
        http://maven.apache.org/xsd/maven-4.0.0.xsd"
    xmlns="http://maven.apache.org/POM/4.0.0" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <modelVersion>4.0.0</modelVersion>
    <artifactId>org.holbreich.lfgm</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>eclipse-plugin</packaging>
    <!-- Parent reference -->
    <parent>
         <artifactId>parent</artifactId>
         <groupId>org.holbreich.lfgm</groupId>
         <version>1.0.0-SNAPSHOT</version>
         <relativePath>../org.holbreich.lfgm.parent/pom.xml</relativePath>
      </parent>
</project>  

And this is great, because in a large application you will have much of the plugins with their simple pom files.
You see the important moment here is the reference to the parent and declaration of the packaging type eclipse-plugin. Eclipse Feature project uses eclipse-feature packaging target, but looks most the same, so i'm not showing it here.

Repository

And finally Repositoy Plugin come into play. It's defines routines for the last assembly and packing of a product. Here i bring only the build element of the pom.xml file where the execution element of tycho-p2-director-plugin defines these two goals.

<build>  
    <plugins>
    <plugin>
        <groupId>org.eclipse.tycho</groupId>
        <artifactId>tycho-p2-director-plugin</artifactId>
        <version>${tycho-version}</version>
        <executions>
            <execution>
                <id>materialize-products</id>
                <goals>
                    <goal>materialize-products</goal>
                </goals>
            </execution>
            <execution>
                <id>archive-products</id>
                <goals>
                    <goal>archive-products</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
    </plugins>
</build>  

Now here we are. I've didn't mentioned further eclipse artefacts like feature.xml or some.project, they stay as usual and must work also without maven.

To get started you can start to build your application by executing maven goals e.g. mvn clean install or run this in configuration in your CI server.

Build automation with Jenkins CI

The showed configuration is ready for automation as it is. You can automate thisvery simple with a standard Jenkins maven job. Provide git checkout path, for all the projects and define e.g. clean install as maven goals for execution on parent project's pom.xml in your Jenkins Job.

However zipped standalone executables for Linux and Windows can be found under org.holbreich.lfgm.eclipse-repository/target/products/ in the project workspace after successful build. Have fun and let me know if you missed something i this description.

Let me know if something of the abow topic is something of your interesst.
As well you are invited to comment your solutions and best practices.

Further Readings

Tank you for reading if you got here ;)


  • Update Okt 2013: I have consolidated build process. It is still Tycho v 0.13.0. Build works on Travis CI now.

  • Update Dez 2015: Removed outdated info. Fixed typos.

  1. Keep in this repository changed location.

  2. http://maven.apache.org/pom.html#Plugins