Skip to content
/ java-native Public template

Template to build a multi-platforms Native Java Maven package

License

Notifications You must be signed in to change notification settings

Mizux/java-native

Repository files navigation

Github-CI: Build Status Build Status Build Status Build Status

Introduction

| Requirement | Codemap | Dependencies | Build | CI | Appendices | License |

This is an example of how to create a Modern CMake C++/Java Project.

This project aim to explain how you build a Java 1.8 native (for win32-x86-64, linux-x86-64 and darwin-x86-64) maven multiple package using mvn and few POM.xml.
e.g. You have a cross platform C++ library and a JNI wrapper on it thanks to SWIG.
Then you want to provide a cross-platform Maven package to consume it in a Maven project...

This project should run on:

  • MacOS (darwin-aarch64, darwin-x86-64)
  • GNU/Linux (linux-aarch64, linux-x86-64)
  • Windows (win32-x86-64)

Requirement

You'll need:

  • "CMake >= 3.18".
  • "Java SDK >= 1.8" and "Maven >= 3.6".

Please verify you also have the JAVA_HOME environment variable set otherwise CMake and Maven won't be able to find your Java SDK.

Codemap

The project layout is as follow:

Dependencies

To complexify a little, the CMake project is composed of three libraries (Foo, Bar and FooBar) with the following dependencies:

Foo:
Bar:
FooBar: PUBLIC Foo PRIVATE Bar

Build Process

To Create a native dependent package we will split it in two parts:

  • A bunch of org.mizux.javanative:javanative-{platform} maven packages for each supported platform targeted and containing the native libraries.
  • A generic maven package org.mizux.javanative:javanative-java depending on each native packages and containing the Java code.

platform names come from the JNA project (Java Native Access) which will be use to find at runtime on which platform the code is currently running.

Local Package

The pipeline for linux-x86-64 should be as follow:
note: The pipeline will be similar for other architecture, don't hesitate to look at the CI log! Local Pipeline Legend

Building local native Package

disclaimer: In this git repository, we use CMake and SWIG.
Thus we have the C++ shared library libFoo.so and the SWIG generated Java wrapper Foo.java.
note: For a C++ CMake cross-platform project sample, take a look at Mizux/cmake-cpp.
note: For a C++/Swig CMake cross-platform project sample, take a look at Mizux/cmake-swig.

So first let's create the local org.mizux.javanative:javanative-{platform}.jar maven package.

Here some dev-note concerning this POM.xml.

  • This package is a native package only containing native libraries.

Then you can generate the package and install it locally using:

mvn package
mvn install

note: this will automatically trigger the mvn compile phase.

If everything good the package (located in <buildir>/java/org.mizux.javanative-<platform>/target/) should have this layout:

{...}/target/javanative-<platform>-1.0.jar:
\- <platform>
   \-libFoo.so.1.0
   \-libjnijavanative.so
...

note: <platform> could be linux-x86-64, darwin-x86-64 or win32-x86-64.

tips: since maven package are just zip archive you can use unzip -l <package>.jar to study their layout.

Building local Package

So now, let's create the local org.mizux.javanative:javanative-java.jar maven package which will depend on our previous native package.

Here some dev-note concerning this POM.xml.

  • Add runtime dependency on each native package(s) availabe:
    <dependency>
      <groupId>org.mizux.javanative</groupId>
      <artifactId>javanative-linux-x86-64</artifactId>
      <version>[1.0,)</version>
      <type>jar</type>
      <scope>runtime</scope>
    </dependency>
    • Add dependency to jna so we can find at runtime the current <platform>:
    <dependency>
      <groupId>net.java.dev.jna</groupId>
      <artifactId>jna-platform</artifactId>
      <version>5.13.0</version>
    </dependency>

Then you can generate the package using:

mvn package
mvn install

If everything good the package (located in <buildir>/java/org.mizux.javanative/target/) should have this layout:

{...}/target/javanative-java-1.0.jar:
\- org/
   \- mizux/
      \- javanative/
         \- Loader$PathConsumer.class
         \- Loader$1.class
         \- Loader.class
         \- foo/
            \- GlobalsJNI.class
            \- StringJaggedArray.class
            \- IntPair.class
            \- StringVector.class
            \- Foo.class
            \- PairVector.class
            \- PairJaggedArray.class
            \- Globals.class
...

Testing local Package

We can test everything is working by using the org.mizux.javanative.test:javanative-test project.

First you can build it using:

cmake --build build

note: javanative-test depends on javanative-java which is locally installed in the local maven cache (~/.m2/repository/org/mizux/javanative/...).

Then you can run it using:

cmake --build build --target test

or manually using:

cd <builddir>/java/org.mizux.javanative.test
mvn exec:java -Dexec.mainClass="org.mizux.javanative.Test"

Appendices

Few links on the subject...

Resources

Project layout:

  • The Pitchfork Layout Revision 1 (cxx-pflR1)

CMake:

Java:

Misc

Image has been generated using plantuml:

plantuml -Tsvg docs/{file}.dot

So you can find the dot source files in docs.

License

Apache 2. See the LICENSE file for details.

Disclaimer

This is not an official Google product, it is just code that happens to be owned by Google.