Java 用于JNI应用程序的可移植Makefile
我有一个Java应用程序,它有一个C JNI后端,我想分发。分发Java部分非常简单——这正是JAR和JVM的用途。分发预编译的C代码并不是那么容易,我想我将不得不要求用户自己构建本机库 目前,我正在使用Java 用于JNI应用程序的可移植Makefile,java,c,makefile,java-native-interface,Java,C,Makefile,Java Native Interface,我有一个Java应用程序,它有一个C JNI后端,我想分发。分发Java部分非常简单——这正是JAR和JVM的用途。分发预编译的C代码并不是那么容易,我想我将不得不要求用户自己构建本机库 目前,我正在使用ant构建Java代码,并使用make构建C代码。问题是我在Makefile中硬编码了jni.h和jni_md.h的位置,这是不可移植的。我在万维网上搜索了尽可能多的JNI示例,它们都有硬编码的路径。如果它是JNI以外的任何包,我可以很高兴地使用类似于pkg config的东西来获得正确的inc
ant
构建Java代码,并使用make
构建C代码。问题是我在Makefile中硬编码了jni.h
和jni_md.h
的位置,这是不可移植的。我在万维网上搜索了尽可能多的JNI示例,它们都有硬编码的路径。如果它是JNI以外的任何包,我可以很高兴地使用类似于pkg config
的东西来获得正确的include标志,但据我所知,JNI不提供任何此类功能
问题:如何编写一个可移植的makefile,在任何*系统中查找JNI头并编译我的C本机代码
以下是我考虑过的几个选项供参考:
- 我可以使用CMake的函数,但我不想使用,因为C代码没有那么复杂,CMake有点过火(加上对用户的额外依赖)
- 我希望设置了
环境变量,但我并不希望总是这样,因为(至少在Ubuntu中)在安装JAVA时,它不是默认设置的JAVA\u HOME
- 我可以使用
或locate
手动查找文件并将include标志缝合在一起,但这感觉相当粗糙find
*我最感兴趣的是Windows、OSX和主流Ubuntu版本,以及任何合理的现代Java版本。如果它的便携性足以让您依赖GNU make(至少,这在大多数平台上都可用),您可以使用
Java\u HOME
并尝试自己确定它,以防它不是这样设置的:
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
示例输出:
>制作
JAVA_HOME:/usr/lib/jvm/JAVA-6-openjdk-amd64
JNI_INCLUDEDIR:/usr/lib/jvm/java-6-openjdk-amd64/include
JNI_平台包含目录:/usr/lib/jvm/java-6-openjdk-amd64/include/linux
>使JAVA_成为HOME=/foo/bar
JAVA\u HOME:/foo/bar
JNI_INCLUDEDIR:/foo/bar/include
JNI_PLATFORMINCLUDEDIR:/foo/bar/include/linux
>使JNI_INCLUDEDIR=/foo/bar
JAVA_HOME:/usr/lib/jvm/JAVA-6-openjdk-amd64
JNI_INCLUDEDIR:/foo/bar
JNI_平台包含目录:/foo/bar/linux
>使JNI_平台=amigaos
JAVA_HOME:/usr/lib/jvm/JAVA-6-openjdk-amd64
JNI_INCLUDEDIR:/usr/lib/jvm/java-6-openjdk-amd64/include
JNI_平台包含目录:/usr/lib/jvm/java-6-openjdk-amd64/include/amigaos
在您的软件包中分发正确版本的jni.h
怎么样?@KinCheung感谢您的评论。jni.h
是否依赖于安装的特定Java版本?在我的系统中,jni.h
位于/usr/lib/jvm/java-8-openjdk-amd64
中,因此,AFAIK仅仅抓住jni.h
不一定能在使用除openjdk 8以外的任何java的系统中工作。不是这样吗?太棒了,谢谢@FelixPalmen。jni_md.h怎么样?这通常位于${JNI_INCLUDEDIR}
的依赖于操作系统的子文件夹中。有没有办法在${JNI_INCLUDEDIR}
中查找和包含子文件夹?这有点棘手,最好的办法是根据$(CC)-dumpmachine
的输出来确定它。。。我将添加一个简单的示例,看起来不错,它在我的Ubuntu 16.04中做到了这一点。我将在Windows机器上试用,如果它能工作,我会将答案标记为正确。记录在案:我试过了,它确实按预期工作。回答接受,谢谢!