Tycho Advanced by Dirk Fauth

6 minute read

Reading the current literature regarding Eclipse 4 and Maven Tycho, I realized that some aspects on dependency management are not described. IMHO these aspects are important and with this post I will try to close some of those gaps.

This post will cover some advanced techniques on how Tycho resolves project dependencies. If you are not familiar with Tycho already, you should read the following tutorial first: http://www.vogella.com/articles/EclipseTycho/article.html

All of the information I wrote down here are also available in the Tycho Wiki. So if you need a more detailed description of the following aspects have a look at the links at the end of this post.

Using a PDE target definition

If you are not familiar with the PDE target definitions, you should read this tutorial first: http://www.vogella.com/articles/EclipseTargetPlatform/article.html

Tycho always builds against a target platform. A target platform is a set of artifacts used to resolve the project dependencies for the build. Most of the tutorials and articles out there are showing examples that are using the simple target platform configuration. This is to use a repository definition containing repositories of type p2. In this case the whole content of all defined p2 repositories will become part of the target platform. This is similar to using the PDE export wizard without a custom PDE target definition (which means the current running platform with all containing plugins is used).

<repository>
    <id>eclipse-juno</id>
    <url>http://download.eclipse.org/releases/juno</url>
    <layout>p2</layout>
</repository>

In Eclipse based development, it is best practice to develop and build against a specific target definition. This way you are sure that dependencies and their versions doesn’t change while developing. You also ensure that all developers in a team are using the same dependencies and versions, rather than being dependent on the versions installed in the IDE of every developer. If a target definition is used in the project for development, the build should also use this instead of using a whole repository. Tycho supports this for quite a while. But since 0.16.0 it has become a lot easier to configure.

Assuming you already have a multi-module-project, you need to create a new project for the target definition and add it to the list of modules of the parent. This project will only consist of two files, the pom.xml needed for building and the PDE target definition file. The pom.xml can be as minimal as showed below by using the new packaging type eclipse-target-platform introduced with 0.16.0:

<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/maven-v4\_0\_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>some-group-id</groupId>
    <artifactId>target-definition-id</artifactId>
    <version>target-definition-version</version>
    <packaging>eclipse-target-definition</packaging>
</project>

You also need to configure the target-platform-configuration plugin to tell Tycho to use the PDE target definition for building.

<plugin>
    <groupId>org.eclipse.tycho</groupId>
    <artifactId>target-platform-configuration</artifactId>
    <version>${tycho-version}</version>
    <configuration>
        <target>
            <artifact>
                <groupId>some-group-id</groupId>
                <artifactId>target-definition-id</artifactId>
                <version>target-definition-version</version>
            </artifact>
        </target>
    </configuration>
</plugin>

This approach comes with two limitations on handling PDE target definition files:

  1. This mechanism only supports a single target platform definition file in the projects base directory
  2. The file needs to have the same name as the artifactId defined in the pom, suffixed with .target

In about 99% of the Eclipse based development, this is enough. But there might be some cases where you are not able to always name the file like the artifactId. An example might be the usage of build profiles, where each profile comes with a different target definition. In this case you are still able to use the mechanism that worked before 0.16.0. This is adding the classifier tag to the target-platform-configuration plugin and adding the build-helper-maven-plugin to the target definition pom.xml. Note that the classifier defined in the target-platform-configuration needs to be the same as in the build-helper-maven-plugin.

<plugin>
    <groupId>org.eclipse.tycho</groupId>
    <artifactId>target-platform-configuration</artifactId>
    <version>${tycho-version}</version>
    <configuration>
        <target>
            <artifact>
                <groupId>org.eclipse.nebula.widgets.nattable</groupId>
                <artifactId>target-platform</artifactId>
                <version>${project.version}</version>
                <classifier>nattable</classifier>
            </artifact>
        </target>
    </configuration>
</plugin>

The following is the pom.xml of the target definition project of the NatTable. It is an example for showing how to use profiles to support different PDE target definition files and already worked pre 0.16.0. A profile can be selected for a build with the -P parameter as described here: http://maven.apache.org/guides/introduction/introduction-to-profiles.html

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

    <parent>
        <groupId>org.eclipse.nebula.widgets.nattable</groupId>
        <artifactId>parent</artifactId>
        <version>${project.version}</version>
        <relativePath>../org.eclipse.nebula.widgets.nattable.parent</relativePath>
    </parent>

    <artifactId>target-platform</artifactId>

    <packaging>pom</packaging>

    <profiles>
        <profile>
            <id>default</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <target-file-name>nattable.target</target-file-name>
            </properties>
        </profile>
        <profile>
            <id>build-server</id>
            <properties>
                <target-file-name>nattable\_buildserver.target</target-file-name>
            </properties>
        </profile>
    </profiles>

    <build>
        <plugins>
            <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>${target-file-name}</file>
                                    <type>target</type>
                                    <classifier>nattable</classifier>
                                </artifact>
                            </artifacts>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

On creating a PDE target definition, you should be aware of the limitation, that Tycho only supports Software Sites as locations. Directory, Installation and Feature are not supported and will be ignored by the build process.

POM dependency resolution

Another information gap or misinformation that can be found in current literature is that Tycho doesn’t support dependency resolution of POM dependencies. This is not true. It is true that Tycho uses the MANIFEST-first approach to resolve the dependencies. And it is suggested to rely on that because of several facts. One you will notice on reading further. But in some cases it still might be useful to use default Maven POM dependencies too. Think of a dependency to a third-party-library that is not hosted in a p2 repository and can only be found in Maven Central. If this third-party-library is an OSGi bundle, and only in this case, Tycho is able to resolve such a dependency. All you have to do is to specify the dependencies to the OSGi bundle artifact in the section of the POM and set the flag _pomDemendencies=consider_ to the _target-platform-configuration_ plugin.

The following example will show how to add the dependency to the Scala OSGi bundle artifact in Maven Central. Of course this could also be solved by adding a dependency to the Scala IDE p2 repository.

...
<plugin>
    <groupId>org.eclipse.tycho</groupId>
    <artifactId>target-platform-configuration</artifactId>
    <version>${tycho-version}</version>
    <configuration>
        <pomDependencies>consider</pomDependencies>
        <environments>
            <environment>
                <os>win32</os>
                <ws>win32</ws>
                <arch>x86</arch>
            </environment>
        </environments>        
    </configuration>
</plugin>
...
<dependencies>
    <dependency>
        <groupId>com.weiglewilczek.scala-lang-osgi</groupId>
        <artifactId>scala-library</artifactId>
        <version>2.9.1</version>
    </dependency>
</dependencies>
...

Doing this of course has the downside, that the target platform used for the build and the one used at development time are not the same anymore. To work around this you need to add a Directory location to the PDE target definition, putting in the jar you need to download from Maven Central manually before. As said before, Tycho will ignore the Directory location in the build process and will only show a warning. But it doesn’t has further impact to the build.

The above is one of the downsides in using POM dependencies with Tycho instead of p2 repositories. You need to deal with having the target platform for the build and the development environment yourself. Whenever possible you should rely on dependencies that can be resolved by a p2 repository. But it is good to know that you still have the opportunity to workaround that, if the bundle you are dependent to is not available in a p2 repository.

http://wiki.eclipse.org/Tycho/Packaging_Types#eclipse-target-definition http://wiki.eclipse.org/Tycho/Reference_Card#Target_file_providing_the_context_of_the_build http://wiki.eclipse.org/Tycho/Target_Platform#Target_platform_configuration

Updated: