Pedro Mediano
Pedro Mediano

Reputation: 143

Portable Makefile for JNI applications

I have a Java application with a C JNI backend I want to distribute. Distributing the Java part is easy enough -- that's precisely what jars and the JVM are for. Distributing pre-compiled C code is not that easy, and I assume I will have to ask users to build the native library on their own.

At the moment I'm using ant to build the Java code and make to build the C code. The problem is that I have hard-coded the location of jni.h and jni_md.h in my Makefile, which is far from portable. I've searched through as many JNI examples as I could find in the world wide web and all of them had a hard-coded path somewhere. If it were any package other than JNI I could happily use something like pkg-config to get the right include flags, but as far as I'm aware JNI does not provide any such functionality.

Question: how can I write a portable makefile that will find the JNI headers and compile my C native code in any* system?

For reference, here are a few options I've considered:

*I'm mostly interested in Windows, OSX and mainstream Ubuntu versions with any reasonable modern version of Java.

Upvotes: 4

Views: 508

Answers (1)

user2371524
user2371524

Reputation:

If it's portable enough for you to rely on GNU make (at least, this is available on most platforms), you could use JAVA_HOME and try to determine it yourself in case it is not set like this:

ifeq ($(JAVA_HOME),)
ifeq ($(OS),Windows_NT)
which = $(shell where $1)
else
which = $(shell which $1)
endif
JAVAC ?= $(realpath $(call which,javac))
JAVA_HOME = $(abspath $(dir $(JAVAC))..)
endif

ifneq ($(JAVA_HOME),)
JNI_INCLUDEDIR ?= $(JAVA_HOME)/include
endif

ifeq ($(JNI_INCLUDEDIR),)
$(error could not determine JNI include dir, try specifying either \
    JAVA_HOME or JNI_INCLUDEDIR)
endif

TARGETTRIPLET := $(shell $(CC) -dumpmachine)
ifeq ($(JNI_PLATFORM),)
ifeq ($(findstring mingw,$(TARGETTRIPLET)),mingw)
JNI_PLATFORM:= win32
else
ifeq ($(findstring linux,$(TARGETTRIPLET)),linux)
JNI_PLATFORM:= linux
# add more checks here
endif
endif
endif

JNI_PLATFORMINCLUDEDIR ?= $(JNI_INCLUDEDIR)/$(JNI_PLATFORM)

$(info JAVA_HOME: $(JAVA_HOME))
$(info JNI_INCLUDEDIR: $(JNI_INCLUDEDIR))
$(info JNI_PLATFORMINCLUDEDIR: $(JNI_PLATFORMINCLUDEDIR))

all:
    @:

.PHONY: all

example outputs:

> make
JAVA_HOME: /usr/lib/jvm/java-6-openjdk-amd64
JNI_INCLUDEDIR: /usr/lib/jvm/java-6-openjdk-amd64/include
JNI_PLATFORMINCLUDEDIR: /usr/lib/jvm/java-6-openjdk-amd64/include/linux

> make JAVA_HOME=/foo/bar
JAVA_HOME: /foo/bar
JNI_INCLUDEDIR: /foo/bar/include
JNI_PLATFORMINCLUDEDIR: /foo/bar/include/linux

> make JNI_INCLUDEDIR=/foo/bar
JAVA_HOME: /usr/lib/jvm/java-6-openjdk-amd64
JNI_INCLUDEDIR: /foo/bar
JNI_PLATFORMINCLUDEDIR: /foo/bar/linux

> make JNI_PLATFORM=amigaos
JAVA_HOME: /usr/lib/jvm/java-6-openjdk-amd64
JNI_INCLUDEDIR: /usr/lib/jvm/java-6-openjdk-amd64/include
JNI_PLATFORMINCLUDEDIR: /usr/lib/jvm/java-6-openjdk-amd64/include/amigaos

Upvotes: 2

Related Questions