Reputation: 143
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 could use CMake's FindJNI function, but I'd rather not since the C code is not that complex and CMake would be a bit of an overkill (plus an extra dependency for the users).
I could hope that the JAVA_HOME
environment variable is set, which I don't expect always to be the case, since (at least in Ubuntu) it's not set by default when you install Java.
I could use locate
or find
to manually find the files and stitch the include flags together, but this feels rather hacky.
*I'm mostly interested in Windows, OSX and mainstream Ubuntu versions with any reasonable modern version of Java.
Upvotes: 4
Views: 508
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