OpenCV with Maven: Part 2 – Dealing with the natives

Pushing the natives

Maven repo is capable of hosting not only .jars, but other types of artifacts too. Such as native .dll files. ItSeez provides precompiled dlls, so fortunately there’s no need to compile the sources. We just need to turn the libs into maven modules preserving the dll packaging. To do that we can use the install plugin, which will conveniently generate the required pom file for us:

mvn install:install-file -Dfile=opencv2412.dll -DgroupId=eu.dindoffer -DartifactId=opencv_win -Dversion=2.4.12 -Dpackaging=dll –Dclassifier=32 -DgeneratePom=true
mvn install:install-file -Dfile=opencv2412.dll -DgroupId=eu.dindoffer -DartifactId=opencv_win -Dversion=2.4.12 -Dpackaging=dll –Dclassifier=64 -DgeneratePom=true

I recommend using a separate artifact for each build flavor (x86/x64) distinguished by a classifier. This way we gain fine-grained control over what we want to require in our maven projects. The install plugin creates the artifacts in local .m2 repo, which we can again copy to our private remote repo, just as in part 1.

Pulling the natives

Finally, we can require the native packages inside project poms:

<dependency>
    <groupId>eu.dindoffer</groupId>
    <artifactId>opencv_win</artifactId>
    <version>2.4.12</version>
    <classifier>64</classifier>
    <type>dll</type>
</dependency>
<dependency>
    <groupId>eu.dindoffer</groupId>
    <artifactId>opencv_win</artifactId>
    <version>2.4.12</version>
    <classifier>32</classifier>
    <type>dll</type>
</dependency>

However, the dependency declaration only downloads the packages. We have some work left to do to load the libs from the built project. To copy them to a specified target outputDirectory we will use maven dependency plugin:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>copy-dependencies</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
                <excludeTransitive>true</excludeTransitive>
                <includeArtifactIds>opencv_win</includeArtifactIds>
                <failOnMissingClassifierArtifact>true</failOnMissingClassifierArtifact>
                <silent>false</silent>
                <outputDirectory>target/native</outputDirectory>
                <overWriteReleases>true</overWriteReleases>
                <overWriteSnapshots>true</overWriteSnapshots>
                <overWriteIfNewer>true</overWriteIfNewer>
            </configuration>
        </execution>
    </executions>
</plugin>

This hooks the plugin to prepare-package phase, so after mvn install we end up with them in target/native folder. Now the loading of the libs from java can be done via simple absolute path:

switch (System.getProperty("sun.arch.data.model")) {
    case "64":
        System.load(System.getProperty("user.dir") + "\\native\\opencv_win-2.4.12-64.dll");
        break;
    case "32":
        System.load(System.getProperty("user.dir") + "\\native\\opencv_win-2.4.12-32.dll");
        break;
}

…now?

What we have described here is a static maven repo, meaning we have pushed artefacts only manually. To use our simple repo for build snapshot storage, we can configure the wagon plugin to push the artifacts during the build via FTP. However, if you intend to use the repo only for OpenCV (or other rarely changing artifacts), there’s no need for that.

Also, what we haven’t discussed are other build aspects of the maven projects. E.g. specifying the .jar manifest needed to start the jar as a standalone app and integration of other libs (or OpenCV java wrapper), both of which can be done via assembly plugin. However, these are out of scope of this tutorial and pretty straightforward. But remember: if you are packaging jar dependencies into the project jar, be sure to exclude the native libs from the packaging (<exclude>eu.dindoffer:opencv_win</exclude> )

Leave a Reply