The Maven NAR Plugin provides the easiest way to interface native code to Java projects. This example shows the configuration needed in order to build a JNI library, and package it into a launcher structure using the cross-platform-launcher-plugin.
The cross-platform-launcher-plugin has been developed and tested with version 2.1-SNAPSHOT of the NAR plugin.
This cross-platform example does not show the actual code, just the Maven plugin configuration. This example is taken from the early development of another DevZendo.org project, the Cross Platform Filesystem Access library. At this stage, the library was nothing more than a "Hello World", taken from the example code of the Maven NAR Plugin.
This example comprises three Maven Projects, and illustrates the typical partitioning and packaging of JNI projects:
There are multiple profiles activated on specific operating systems in order to create a launcher structure appropriate to the system its 'package' goal is run on. Each OS-activated profile declares the relevant NAR plugin's AOL (Architecture-OperatingSystem-Linker) classifiers and artifact types.
The nar-download, nar-unpack and nar-assembly goals of the Maven NAR Plugin must be executed, followed by the CrossPlatformLauncherPlugin. The cross-platform-launcher-plugin understands AOL:type classifiers and will copy these, and their .nar libraries over into the launcher structure.
The 'main' class referred to in the cross-platform-launcher-plugin configuration is that of the CrossPlatformFileSystemAccessTest project.
First, CrossPlatformFileSystemAccess's pom.xml builds a JNI library and autogenerated NarSystem class in our projects' package:
<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>org.devzendo</groupId> <artifactId>CrossPlatformFileSystemAccess</artifactId> <name>CrossPlatformFileSystemAccess</name> <version>0.0.1-SNAPSHOT</version> <description>Java Native code for advanced file attribute and file system operations</description> <packaging>nar</packaging> <parent> <artifactId>GroupParent</artifactId> <groupId>org.devzendo</groupId> <version>1.0.0</version> </parent> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.4</version> <scope>test</scope> </dependency> <dependency> <groupId>org.easymock</groupId> <artifactId>easymock</artifactId> <version>2.3</version> <scope>test</scope> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.8</version> </dependency> </dependencies> <build> <defaultGoal>install</defaultGoal> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-nar-plugin</artifactId> <version>2.1-SNAPSHOT</version> <extensions>true</extensions> <configuration> <java> <include>true</include> </java> <javah /> <libraries> <library> <type>jni</type> <narSystemPackage>org.devzendo.xpfsa</narSystemPackage> </library> </libraries> </configuration> </plugin> </plugins> </build> </project>
Second, CrossPlatformFileSystemAccessTest's pom.xml:
<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>org.devzendo</groupId> <artifactId>CrossPlatformFileSystemAccessTest</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>nar</packaging> <parent> <artifactId>GroupParent</artifactId> <groupId>org.devzendo</groupId> <version>1.0.0</version> </parent> <properties> <skipTests>true</skipTests> </properties> <!-- for Eclipse --> <build> <defaultGoal>integration-test</defaultGoal> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-nar-plugin</artifactId> <version>2.1-SNAPSHOT</version> <extensions>true</extensions> <executions> <execution> <id>unpack-nar-dependencies</id> <phase>package</phase> <goals> <goal>nar-download</goal> <goal>nar-unpack</goal> <goal>nar-assembly</goal> </goals> </execution> </executions> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.devzendo</groupId> <artifactId>CrossPlatformFileSystemAccess</artifactId> <version>0.0.1-SNAPSHOT</version> <type>nar</type> </dependency> <dependency> <groupId>org.devzendo</groupId> <artifactId>CommonCode</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.4</version> <scope>test</scope> </dependency> </dependencies> </project>
Finally, CrossPlatformFileSystemAccessProduct's pom.xml. Note the activation of configuration specific to the operating system upon which the package goal is invoked, and the specification of the NAR Plugin's AOL-classifier:type in each invocation of the cross-platform-launcher-plugin.
The Mac OS X profile also copies the Quaqua JNI library over to the launcher structure, and declares the dependency of the java half of Quaqua.
<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>org.devzendo</groupId> <artifactId>CrossPlatformFileSystemAccessProduct</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>pom</packaging> <description>Test Application</description> <parent> <artifactId>GroupParent</artifactId> <groupId>org.devzendo</groupId> <version>1.0.0</version> </parent> <properties> <appName>CrossPlatformFileSystemAccessProduct</appName> <skipTests>true</skipTests> </properties> <profiles> <profile> <id>mac os x</id> <activation> <os> <name>mac os x</name> </os> </activation> <build> <plugins> <!-- Create the Mac OS X BeanMinder.app launcher structure under target/macosx. --> <plugin> <groupId>org.devzendo</groupId> <artifactId>cross-platform-launcher-plugin</artifactId> <version>1.1.0</version> <configuration> <os>MacOSX</os> <applicationName>${appName}</applicationName> <mainClassName>org.devzendo.xpfsatest.XPFSATest</mainClassName> <iconsFileName>BeanMinder.icns</iconsFileName> <narClassifierTypes> <param>x86_64-MacOSX-g++:jni</param> </narClassifierTypes> <!-- I don't have an assigned creator code <bundleSignature>BM</bundleSignature> --> </configuration> <executions> <execution> <id>createlauncher</id> <phase>package</phase> <goals> <goal>createlauncher</goal> </goals> </execution> </executions> </plugin> <!-- Copy the Quaqua native libraries into the correct location in the Mac OS X launcher structure created above. --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>unpack-quaqua-dependencies</id> <phase>package</phase> <goals> <goal>unpack</goal> </goals> <configuration> <artifactItems> <artifactItem> <groupId>org.devzendo</groupId> <artifactId>libquaqua</artifactId> <version>9.1</version> <type>zip</type> <overWrite>true</overWrite> <includes>*</includes> <outputDirectory>${project.build.directory}/macosx/${appName}.app/Contents/Resources/Java/lib </outputDirectory> </artifactItem> </artifactItems> <!-- other configurations here --> </configuration> </execution> </executions> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.devzendo</groupId> <artifactId>quaqua</artifactId> <version>9.1</version> </dependency> </dependencies> </profile> <!-- mac os x --> <profile> <id>windows</id> <activation> <os> <family>Windows</family> </os> </activation> <build> <plugins> <!-- Create the Windows launcher structure under target/windows. --> <plugin> <groupId>org.devzendo</groupId> <artifactId>cross-platform-launcher-plugin</artifactId> <version>1.1.0</version> <configuration> <os>Windows</os> <applicationName>${appName}</applicationName> <mainClassName>org.devzendo.xpfsatest.XPFSATest</mainClassName> <narClassifierTypes> <param>x86-Windows-msvc:jni</param> </narClassifierTypes> </configuration> <executions> <execution> <id>createlauncher</id> <phase>package</phase> <goals> <goal>createlauncher</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </profile> <!-- Windows --> <profile> <id>linux</id> <activation> <os> <family>Linux</family> </os> </activation> <build> <plugins> <!-- Create the Linux launcher structure under target/linux. --> <plugin> <groupId>org.devzendo</groupId> <artifactId>cross-platform-launcher-plugin</artifactId> <version>1.1.0</version> <configuration> <os>Linux</os> <applicationName>${appName}</applicationName> <mainClassName>org.devzendo.xpfsatest.XPFSATest</mainClassName> <narClassifierTypes> <param>i386-Linux-g++:jni</param> </narClassifierTypes> </configuration> <executions> <execution> <id>createlauncher</id> <phase>package</phase> <goals> <goal>createlauncher</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </profile> <!-- Linux --> </profiles> <!-- Common for all profiles, and needed for Eclipse --> <build> <defaultGoal>integration-test</defaultGoal> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-nar-plugin</artifactId> <version>2.1-SNAPSHOT</version> <extensions>true</extensions> <executions> <execution> <id>unpack-nar-dependencies</id> <phase>package</phase> <goals> <goal>nar-download</goal> <goal>nar-unpack</goal> <goal>nar-assembly</goal> </goals> </execution> </executions> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.devzendo</groupId> <artifactId>CrossPlatformFileSystemAccessTest</artifactId> <version>0.0.1-SNAPSHOT</version> <type>nar</type> </dependency> </dependencies> </project>