From 92863bb41138a5d71ce7154ce62a87915887899a Mon Sep 17 00:00:00 2001 From: Michael Zucchi Date: Mon, 22 Apr 2019 18:46:06 +0930 Subject: [PATCH] Added some useful variables to java.make Use a generator for the java and native library lookups. Change the library table to be read/write and include the full name. --- config.make | 7 +- java.make | 86 +++++++--- src/notzed.nativez/jni/jni.make | 17 +- src/notzed.nativez/jni/nativez-gen | 205 +++++++++++++++++++++++ src/notzed.nativez/jni/nativez-jni.c | 121 +++++-------- src/notzed.nativez/jni/nativez-jni.def | 22 +++ src/notzed.nativez/jni/nativez-linux.c | 68 +++++--- src/notzed.nativez/jni/nativez-windows.c | 66 +++++--- src/notzed.nativez/jni/nativez.h | 101 ++++------- 9 files changed, 471 insertions(+), 222 deletions(-) create mode 100755 src/notzed.nativez/jni/nativez-gen create mode 100644 src/notzed.nativez/jni/nativez-jni.def diff --git a/config.make b/config.make index 08853c7..f82e020 100644 --- a/config.make +++ b/config.make @@ -14,23 +14,22 @@ JAVACFLAGS += -source 11 # Linux options linux-amd64_CPPFLAGS = \ -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -linux-amd64_CFLAGS = -fPIC -Wall +linux-amd64_CFLAGS = -fPIC -Os -Wall linux-amd64_CC = cc linux-amd64_LD = ld linux-amd64_SO = .so linux-amd64_LIB = lib -linux-amd64_JMOD_LIBS = --libs # Windows options -windows-amd64_CPPFLAGS= \ +windows-amd64_CPPFLAGS = \ -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux \ -DHAVE_ALIGNED_MALLOC \ -DWIN32 +windows-amd64_CFLAGS = -Os -Wall windows-amd64_CC = x86_64-w64-mingw32-gcc windows-amd64_LD = x86_64-w64-mingw32-ld windows-amd64_LDFLAGS = -Wl,--subsystem,windows windows-amd64_SO = .dll windows-amd64_LIB = -windows-amd64_JMOD_LIBS = --cmds diff --git a/java.make b/java.make index c7074ab..7228203 100644 --- a/java.make +++ b/java.make @@ -49,9 +49,21 @@ # _JARFLAGS # _JMODFLAGS +# _JAVA Java sources. If not set it is found from src//classes/(*.java) +# _RESOURCES .jar resources. If not set it is found from src//classes/(not *.java) +# _JAVA_GENERATED Java generated sources. These must be relative to the package name. -# _JAVA Java sources. This is set internally. -# _RESOURCES .jar resources. This is set internally. +# Variables for use in fragments + +# gen.make and jni.make can additionally make use of these variables + +# _gendir Location for files used in Java generation process (per project). +# _genjavadir Location where _JAVA_GENERATED .java files will be created (per project). +# _jnidir Location for jni generated files (per target). +# _objdir Location for c objects (per target). +# _incdir Location for output includes, .jmod staging. +# _libdir Location for output libraries, .jmod staging. May point to _bindir. +# _bindir Location for output commands, .jmod staging. # Define libraries # ---------------- @@ -81,6 +93,7 @@ # _SOURCES .c, .cc, .C - source files for library. Paths are relative to src//jni. # _HEADERS header files for jmod +# _COMMANDS commands/bin/scripts for jmod # _LDFLAGS link flags # _LIBADD extra objects to add to link line @@ -92,6 +105,14 @@ # .c files have dependencies automatically generated +# Targets +# ------- + +# make gen only generate java sources +# make clean rm -rf bin +# make dist create dist tar in bin/ +# make | make jar make all jars and jmods +# make bin make everything but jars and mods # Outputs # ------- @@ -129,24 +150,32 @@ java_JARS=$(foreach module,$(java_MODULES),$(if $(wildcard src/$(module)/jni/jni # Modules with generated java source java_JGEN=$(foreach module,$(java_MODULES),$(if $(wildcard src/$(module)/gen/gen.make),$(module))) -# Define per-module source and resource variables -$(foreach module,$(java_MODULES),$(eval $(module)_JAVA := $(shell find src/$(module)/classes -type f -name '*.java'))) -$(foreach module,$(java_MODULES),$(eval $(module)_RESOURCES := $(shell find src/$(module)/classes -type f \! -name '*.java'))) - -# external jni deps -$(foreach mod,$(java_MODULES),$(eval $(mod)_JDEPMOD_JNI=$(foreach jdep,$($(mod)_JDEPMOD),$(if $(wildcard src/$(mod)/jni),$(jdep))))) +# Define some useful variables before including fragments +define java_variables= +$(1)_gendir:=bin/gen/$(1)/gen +$(1)_genjavadir:=bin/gen/$(1)/classes +$(1)_jnidir:=bin/$(1)/$(TARGET)/jni +$(1)_objdir:=bin/$(1)/$(TARGET)/obj +$(1)_incdir:=bin/$(1)/$(TARGET)/include +$(1)_libdir:=$$(if $$(filter windows-%,$(TARGET)),bin/$(1)/$(TARGET)/bin,bin/$(1)/$(TARGET)/lib) +$(1)_bindir:=bin/$(1)/$(TARGET)/bin +ifndef $(1)_JAVA +$(1)_JAVA := $$(shell find src/$(1)/classes -type f -name '*.java') +endif +ifndef $(1)_RESOURCES +$(1)_RESOURCES := $$(shell find src/$(1)/classes -type f \! -name '*.java') +endif +endef -# Make some of the setup dirs (should it be a target?) -$(shell install -d bin/status bin/modules) +$(foreach module,$(java_MODULES),$(eval $(call java_variables,$(module)))) # ###################################################################### all: jar bin: -jni: -sources: +gen: -.PHONY: all clean jar jni bin sources +.PHONY: all clean jar bin gen clean: rm -rf bin @@ -159,11 +188,14 @@ include $(patsubst %,src/%/jni/jni.make,$(java_JMODS)) define java_targets= # Rules for module $(1) +$(1)_JAVA_generated = $$(addprefix $$($(1)_genjavadir)/,$$($(1)_JAVA_GENERATED)) + bin/status/$(1).data: $$($(1)_RESOURCES) -bin/status/$(1).classes: $(patsubst %,bin/status/%.classes,$($(1)_JDEPMOD)) $$($(1)_JAVA) +bin/status/$(1).classes: $(patsubst %,bin/status/%.classes,$($(1)_JDEPMOD)) $$($(1)_JAVA) $$($(1)_JAVA_generated) jar $(1): bin/$(1)/$(1).jar $(if $(wildcard src/$(1)/jni/jni.make),bin/$(1)/$(TARGET)/$(1).jmod) bin: bin/status/$(1).classes bin/status/$(1).data sources: bin/$(1)/$(1)-sources.zip +gen: $$($(1)_JAVA_generated) # Create modular jar bin/$(1)/$(1).jar: bin/status/$(1).classes bin/status/$(1).data @@ -182,11 +214,13 @@ bin/$(1)/$(TARGET)/$(1).jmod: bin/status/$(1).classes bin/status/$(1).data --class-path bin/modules/$(1) \ $$(if $$(wildcard bin/$(1)/$(TARGET)/include),--header-files bin/$(1)/$(TARGET)/include) \ $$(if $$(wildcard src/$(1)/legal),--legal-notices src/$(1)/legal) \ - $$($(TARGET)_JMOD_LIBS) bin/$(1)/$(TARGET)/lib \ + $$(if $$(wildcard $$($(1)_bindir)),--cmds $$($(1)_bindir)) \ + $$(if $$(wildcard $$($(1)_libdir)),--libs $$($(1)_libdir)) \ $$@ # Create an IDE source zip, paths have to match --module-source-path bin/$(1)/$(1)-sources.zip: bin/status/$(1).classes + @install -d $$(@D) jar -c -f $$@ -M \ $$(patsubst src/$(1)/classes/%,-C src/$(1)/classes %,$$(filter src/$(1)/classes/%,$$($(1)_JAVA))) \ $$(patsubst bin/gen/$(1)/classes/%,-C bin/gen/$(1)/classes %,$$(filter bin/gen/$(1)/classes/%,$$($(1)_JAVA))) @@ -201,6 +235,7 @@ $(foreach module,$(java_MODULES),$(eval $(call java_targets,$(module)))) # Stage resources bin/status/%.data: + @install -d $(@D) for data in $(patsubst src/$*/classes/%,"%",$($*_RESOURCES)) ; do \ install -vDC "src/$*/classes/$$data" "bin/modules/$*/$$data" || exit 1 ; \ done @@ -208,13 +243,14 @@ bin/status/%.data: # Compile one module. This only updates (javac -h) headers if they changed. bin/status/%.classes: + @install -d $(@D) $(JAVAC) \ --module-source-path "src/*/classes:bin/gen/*/classes" \ $(JAVACFLAGS) $($*_JAVACFLAGS) \ -h bin/inc \ -d bin/modules \ -m $* \ - $($*_JAVA) + $($*_JAVA) $($*_JAVA_generated) if [ -d bin/inc/$* ] ; then \ install -DC -t bin/include/$* bin/inc/$*/*.h ; \ fi @@ -228,37 +264,40 @@ SUFFIXES=.c .C .cc SO=$($(TARGET)_SO) LIB=$($(TARGET)_LIB) +# functions to find cross-module stuff $(call library-path,modname,libname) library-path=bin/$(1)/$(TARGET)/lib/$(LIB)$(2)$(SO) library-dir=bin/$(1)/$(TARGET)/lib/ define jni_library= # Rule for library $(2) in module $(1) -$(2)_OBJS = $(foreach sx,$(SUFFIXES),$(patsubst %$(sx), bin/$(1)/$(TARGET)/obj/%.o, $(filter %$(sx),$($(2)_SOURCES)))) +$(2)_OBJS = $(foreach sx,$(SUFFIXES),$(patsubst %$(sx), $($(1)_objdir)/%.o, $(filter %$(sx),$($(2)_SOURCES)))) $(2)_SRCS = $(addprefix src/$(1)/jni/,$($(2)_SOURCES)) -bin/$(1)/$(TARGET)/lib/$(LIB)$(2)$(SO): $$($(2)_OBJS) $($(2)_LIBADD) $($(2)_DEPENDENCIES) +$($(1)_libdir)/$(LIB)$(2)$(SO): $$($(2)_OBJS) $($(2)_LIBADD) $($(2)_DEPENDENCIES) @install -d $$(@D) $($(TARGET)_CC) -o $$@ -shared \ $($(TARGET)_LDFLAGS) $($(2)_LDFLAGS) $$($(2)_OBJS) $($(2)_LIBADD) $($(TARGET)_LDLIBS) $($(2)_LDLIBS) -bin/$(1)/$(TARGET)/obj/%.o: src/$(1)/jni/%.c bin/status/$(1).classes +$($(1)_objdir)/%.o: src/$(1)/jni/%.c bin/status/$(1).classes @install -d $$(@D) $($(TARGET)_CC) -Isrc/$(1)/jni -Ibin/include/$(1) $($(TARGET)_CPPFLAGS) $($(2)_CPPFLAGS) \ $($(TARGET)_CFLAGS) $($(2)_CFLAGS) -c -o $$@ $$< -bin/$(1)/$(TARGET)/include/%.h: src/$(1)/jni/%.h +$($(1)_incdir)/%.h: src/$(1)/jni/%.h install -D $$< $$@ -bin/$(1)/$(TARGET)/obj/%.d: src/$(1)/jni/%.c bin/status/$(1).classes +$($(1)_objdir)/%.d: src/$(1)/jni/%.c bin/status/$(1).classes @install -d $$(@D) @rm -f $$@ @$($(TARGET)_CC) -MM -MT "bin/$(1)/$(TARGET)/obj/$$*.o" -Isrc/$(1)/jni -Ibin/include/$(1) \ $($(TARGET)_CPPFLAGS) $($(2)_CPPFLAGS) $$< -o $$@.d 2>/dev/null @sed 's,\($$*\.o\) *:,\1 $$@ : ,g' $$@.d > $$@ ; rm $$@.d -bin jni $(1) bin/$(1)/$(TARGET)/$(1).jmod: bin/$(1)/$(TARGET)/lib/$(LIB)$(2)$(SO) $(addprefix bin/$(1)/$(TARGET)/include/,$($(2)_HEADERS)) +bin jni $(1) bin/$(1)/$(TARGET)/$(1).jmod: $($(1)_libdir)/$(LIB)$(2)$(SO) \ + $(addprefix $($(1)_incdir)/,$($(2)_HEADERS)) \ + $(addprefix $($(1)_bindir)/,$($(2)_COMMANDS)) -$(if $(filter clean dist,$(MAKECMDGOALS)),,-include $$($(2)_OBJS:.o=.d)) +$(if $(filter clean dist gen,$(MAKECMDGOALS)),,-include $$($(2)_OBJS:.o=.d)) endef #$(foreach module,$(java_JMODS),$(foreach library,$($(module)_JNI_LIBRARIES),$(info $(call jni_library,$(module),$(library))))) @@ -267,6 +306,7 @@ $(foreach module,$(java_JMODS),$(foreach library,$($(module)_JNI_LIBRARIES),$(ev # ###################################################################### dist: + @install -d bin tar cfz bin/$(dist_NAME)-$(dist_VERSION).tar.gz \ --transform=s,^,$(dist_NAME)-$(dist_VERSION)/, \ config.make java.make Makefile src \ diff --git a/src/notzed.nativez/jni/jni.make b/src/notzed.nativez/jni/jni.make index c9908db..f2cad7d 100644 --- a/src/notzed.nativez/jni/jni.make +++ b/src/notzed.nativez/jni/jni.make @@ -2,5 +2,20 @@ notzed.nativez_JNI_LIBRARIES = nativez nativez_SOURCES = nativez-jni.c nativez-$(TARGET:-amd64=).c -nativez_CFLAGS = -Os -Wmissing-prototypes +nativez_CPPFLAGS = -I$(notzed.nativez_jnidir) +nativez_CFLAGS = -Wmissing-prototypes nativez_HEADERS = nativez.h +nativez_DEFS = nativez-jni.def + +nativez_makedep=$(notzed.nativez_objdir)/$(1).o: $(notzed.nativez_jnidir)/$(1).h + +$(foreach def,$(nativez_DEFS),$(eval $(call nativez_makedep,$(def:.def=)))) + +$(notzed.nativez_jnidir)/%.h: src/notzed.nativez/jni/%.def src/notzed.nativez/jni/nativez-gen + @install -d $(@D) + src/notzed.nativez/jni/nativez-gen -J $< > $@ || ( rm $@ ; exit 1) + +# include tool in jmod +nativez_COMMANDS=nativez-gen +$(notzed.nativez_bindir)/nativez-gen: src/notzed.nativez/jni/nativez-gen + install -DC $< $@ diff --git a/src/notzed.nativez/jni/nativez-gen b/src/notzed.nativez/jni/nativez-gen new file mode 100755 index 0000000..2c7844c --- /dev/null +++ b/src/notzed.nativez/jni/nativez-gen @@ -0,0 +1,205 @@ +#!/usr/bin/perl + +# usage [ options ]* def-file.def +# -b basedir Base directory for any 'header' sections. +# -I incdir Extra include directory +# -Iincdir Extra include directory +# --func-name Function table variable name. Default is `fn'. +# --java-name Java table variable name. Default is 'java'. +# -J Create #defines to map java names to the variable name. +# --java-long Create long java names for object types. Sort of like mangled jni names. + +$args = "$0 ".join " ", @ARGV; +$java_name = "java"; +$func_name = "fn"; +$doJ = 0; +$doLong = 0; + +while ($#ARGV >= 0) { + my $cmd = shift; + if ($cmd eq "-b") { + $basedir = shift; + $includes.=" '-I${basedir}'"; + } elsif ($cmd eq "-I") { + my $dir = shift; + $includes.= " '-I$dir'"; + } elsif ($cmd =~ m/^-I/) { + $includes.= " '$cmd'"; + } elsif ($cmd eq "--func-name") { + $func_name = shift; + } elsif ($cmd eq "--java-name") { + $java_name = shift; + } elsif ($cmd eq "-J") { + $doJ = 1; + } elsif ($cmd eq "--java-long") { + $doLong = 1; + } else { + $def = $cmd; + } +} + +#die ("`$def': input file doesn't exist") if ! -f $def; +#die ("`$basedir': doesn't exist") if ! -d $basedir; + +$header = ""; +$librart = ""; +@functions = (); +@headers = (); +%proto = (); +$last_library = ""; +$mode = ""; + +open IN,"<$def"; + +while () { + chop; + s/#.*$//; + if (m/^header (.*) (.*) \{/) { + $library = $1; + $header = $2; + push @headers, $header; + + -f "$basedir/$header" || die ("header $header not found"); + + %proto = (); + open PROTO, "cproto -q -x ${includes} $basedir/$header|"; + + while () { + chop; + $cproto = $_; + if (m/([a-zA-Z0-9_]*)\(/) { + $func = $1; + $proto{$func} = $cproto; + } + } + close PROTO; + + if ($library ne $last_library) { + push @functions, "#$library"; + $last_library = $library; + } + $mode = "proto"; + } elsif (m/^java (.*) (.*) \{/) { + $name = $1; + $class = $2; + $mode = "java"; + push @classes,"#$name:$class"; + } elsif (m/^}$/) { + $mode = ""; + } elsif ($mode eq "proto") { + if (m/\s*([a-zA-Z0-9_]+)/) { + my $func= $1; + my $cproto = $proto{$func}; + + die ("No function $func in $header") if !defined($cproto); + + push @functions, $cproto; + } + } elsif ($mode eq "java") { + # maps to strict "[static|],name,(arguments)" + if (m/(static)? *([\w<>]*) *, *([\[\w<>\(\)\/;]*)/) { + push @classes,"$1,$2,$3"; + } + } +} +close IN; + +$date = `date`; +chop $date; +print "/* This file was autogenerated on $date: */\n"; +print "/* $args */\n"; + +if ($#headers >= 0) { + # Handle C prototype mappings + foreach $h (@headers) { + print "#include <$h>\n"; + } + + print "static struct functable {\n"; + foreach $func (@functions) { + if ($func =~ m/^\#(.+)/) { + print "\t/* lib$1 */\n"; + } else { + $dfunc = $func; + $dfunc =~ s/([a-zA-Z0-9_]*)(\(.*;)/(*\1)\2/; + print "\t$dfunc\n"; + } + } + print "} ${func_name};\n"; + print "static const char *${func_name}_names =\n"; + foreach $func (@functions) { + if ($func =~ m/^(\#.+)/) { + print "\t\"$func\\0\"\n"; + } else { + $func =~ m/([a-zA-Z0-9_]*)\(/; + print "\t\"$1\\0\"\n"; + } + } + print "\t;\n"; +} + +if ($#classes >= 0) { + # Handle java defines + $name = ""; + $class = ""; + print "static struct {\n"; + foreach $func (@classes) { + if ($func =~ m/^#(.+):(.+)/) { + $name = $1; + $class = $2; + print "\t// $class\n"; + print "\tjclass $name"."_classid;\n"; + printf "#define $name"."_classid ${java_name}.$name"."_classid\n" if $doJ; + } elsif ($func =~ m/(.*),(.+),\((.*)\).*/) { + my $method = $2; + my $args = $3; + + if ($doLong) { + while ($args =~ m/(.*)L([^;]*);(.*)/) { + my $a = $1; + my $b = $2; + my $c = $3; + + $b =~ s,/,_,g; + $args = $a."_".$b."_".$c; + } + } else { + $args =~ s/L[^;]*;/l/g; + $args =~ tr/A-Z/a-z/; + } + $args =~ s/\[/_/g; + + $method =~ s//new/; + + print "\tjmethodID $name"."_$method"."_$args;\n"; + print "#define $name"."_$method"."_$args ${java_name}.$name"."_$method"."_$args\n" if $doJ; + } elsif ($func =~ m/(.*),(.+),(.+)/) { + my $field = $2; + my $type = $3; + + print "\tjfieldID $name"."_$field;\n"; + print "#define $name"."_$field ${java_name}.$name"."_$field\n" if $doJ; + } else { + die("can't parse java signature $func"); + } + } + print "} ${java_name};\n"; + print "static const char *${java_name}_names =\n"; + foreach $func (@classes) { + if ($func =~ m/^#(.+):(.+)/) { + $name = $1; + $class = $2; + + print "\t\"#$class\\0\"\n"; + } elsif ($func =~ m/static,(.*),(.*\(.*\).*)/) { + print "\t\":$1\\0$2\\0\"\n"; + } elsif ($func =~ m/,(.*),(.*\(.*\).*)/) { + print "\t\".$1\\0$2\\0\"\n"; + } elsif ($func =~ m/static,(.*),(.*)/) { + print "\t\";$1\\0$2\\0\"\n"; + } elsif ($func =~ m/,(.*),(.*)/) { + print "\t\",$1\\0$2\\0\"\n"; + } + } + print "\t;\n"; +} diff --git a/src/notzed.nativez/jni/nativez-jni.c b/src/notzed.nativez/jni/nativez-jni.c index d3c7593..77c553c 100644 --- a/src/notzed.nativez/jni/nativez-jni.c +++ b/src/notzed.nativez/jni/nativez-jni.c @@ -35,64 +35,28 @@ #include #include +#include #include "nativez.h" - -#define NZOBJECT "au/notzed/nativez/NativeZ" +#include "nativez-jni.h" static JavaVM *vm; -static jclass Buffer_classid; -static jmethodID Buffer_hasArray_; -static jmethodID Buffer_isDirect_; -static jmethodID Buffer_array_; -static jmethodID Buffer_arrayOffset_; -static jmethodID Buffer_position_; -static jmethodID Buffer_position_i; -static jmethodID Buffer_limit_; -static jmethodID Buffer_limit_i; - -static jclass ByteBuffer_classid; -static jmethodID ByteBuffer_order_l; - static jobject ByteOrder_nativeOrder; // ByteOrder.nativeOrder() -static jclass NativeZ_classid; -static jmethodID NativeZ_create_lj; -static jmethodID NativeZ_register_l; -static jmethodID NativeZ_resolve_lj; -static jmethodID NativeZ_refer_lj; -static jfieldID NativeZ_p; - -static const NZRefTable reftable[] = { - JCLASS(Buffer_classid, "java/nio/Buffer"), - JMETHOD(Buffer_hasArray_, "hasArray", "()Z"), - JMETHOD(Buffer_isDirect_, "isDirect", "()Z"), - JMETHOD(Buffer_array_, "array", "()Ljava/lang/Object;"), - JMETHOD(Buffer_arrayOffset_, "arrayOffset", "()I"), - JMETHOD(Buffer_position_, "position", "()I"), - JMETHOD(Buffer_position_i, "position", "(I)Ljava/nio/Buffer;"), - JMETHOD(Buffer_limit_, "limit", "()I"), - JMETHOD(Buffer_limit_i, "limit", "(I)Ljava/nio/Buffer;"), - - JCLASS(ByteBuffer_classid, "java/nio/ByteBuffer"), - JMETHOD(ByteBuffer_order_l, "order", "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;"), - - JCLASS(NativeZ_classid, NZOBJECT), - JSMETHOD(NativeZ_create_lj, "create", "(Ljava/lang/Class;J)L" NZOBJECT ";"), - JSMETHOD(NativeZ_register_l, "register", "(L" NZOBJECT ";)L" NZOBJECT ";"), - JSMETHOD(NativeZ_resolve_lj, "resolve", "(Ljava/lang/Class;J)L" NZOBJECT ";"), - JSMETHOD(NativeZ_refer_lj, "refer", "(Ljava/lang/Class;J)L" NZOBJECT ";"), - JFIELD(NativeZ_p, "p", "J"), - - JEND -}; +static int fail(const char *ctx, const char *what) __attribute__ ((noinline)); +static int fail(const char *ctx, const char *what) { + fprintf(stderr, "%s: %s\n", ctx, what); + perror(ctx); + fflush(stderr); + return -1; +} jint nativez_OnLoad(JavaVM *vmi, JNIEnv *env) { /* Save VM - required for callbacks from threads */ vm = vmi; - if (nativez_ResolveReferences(env, reftable) != 0) + if (nativez_ResolveReferences(env, java_names, &java) != 0) return -1; jclass jc = (*env)->FindClass(env, "java/nio/ByteOrder"); @@ -223,48 +187,49 @@ jstring nativez_NewString(JNIEnv *env, const char *s) { /* ********************************************************************** */ -int nativez_ResolveReferences(JNIEnv *env, const NZRefTable *table) { +int nativez_ResolveReferences(JNIEnv *env, const char *jn_names, void *jnp) { jclass jc = NULL; - const char *cname = NULL; - int failed = 0; - - for (int i=0;table[i].type;i++) { - switch (table[i].type) { - case 1: - jc = (*env)->FindClass(env, table[i].name); - if (!jc) { - fprintf(stderr, "Unablet to resolve class `%s'\n", table[i].name); - fflush(stderr); - return -1; - } - if (table[i].ptr) { - jc = (*env)->NewGlobalRef(env, jc); - *(table[i].ptr) = jc; - } - cname = table[i].name; + + const char *name = jn_names; + int index = 0; + void **jn = jnp; + const char *cname = "?"; + + while (*name) { + const char *next = name + strlen(name) + 1; + + switch (*name) { + case '#': // class + jc = (*env)->FindClass(env, name + 1); + jn[index] = jc = (*env)->NewGlobalRef(env, jc); + cname = name + 1; break; - case 2: // method - *(table[i].ptr) = (*env)->GetMethodID(env, jc, table[i].name, table[i].signature); + case ',': // field + jn[index] = (*env)->GetFieldID(env, jc, name+1, next); break; - case 3: // static method - *(table[i].ptr) = (*env)->GetStaticMethodID(env, jc, table[i].name, table[i].signature); + case ';': // static field + jn[index] = (*env)->GetStaticFieldID(env, jc, name+1, next); break; - case 4: // field - *(table[i].ptr) = (*env)->GetFieldID(env, jc, table[i].name, table[i].signature); + case '.': // method + jn[index] = (*env)->GetMethodID(env, jc, name+1, next); break; - case 5: // static field - *(table[i].ptr) = (*env)->GetStaticFieldID(env, jc, table[i].name, table[i].signature); + case ':': // static method + jn[index] = (*env)->GetStaticMethodID(env, jc, name+1, next); break; + default: + return fail("Invalid table", name); } - if ((table[i].ptr) && !*(table[i].ptr)) { - failed--; - fprintf(stderr, "Unable to resolve `%s.%s' sig `%s'\n", cname, table[i].name, table[i].signature); - fflush(stderr); - } + if (!jn[index]) + return fail(cname, name+1); + + if (*name != '#') + next = next + strlen(next) + 1; + name = next; + index += 1; } - return failed; + return 0; } /* ********************************************************************** */ diff --git a/src/notzed.nativez/jni/nativez-jni.def b/src/notzed.nativez/jni/nativez-jni.def new file mode 100644 index 0000000..3fa29af --- /dev/null +++ b/src/notzed.nativez/jni/nativez-jni.def @@ -0,0 +1,22 @@ +java Buffer java/nio/Buffer { + hasArray, ()Z + isDirect, ()Z + array, ()Ljava/lang/Object; + arrayOffset, ()I + position, ()I + position, (I)Ljava/nio/Buffer; + limit, ()I + limit, (I)Ljava/nio/Buffer; +} + +java ByteBuffer java/nio/ByteBuffer { + order, (Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer; +} + +java NativeZ au/notzed/nativez/NativeZ { + static create, (Ljava/lang/Class;J)Lau/notzed/nativez/NativeZ; + static register, (Lau/notzed/nativez/NativeZ;)Lau/notzed/nativez/NativeZ; + static resolve, (Ljava/lang/Class;J)Lau/notzed/nativez/NativeZ; + static refer, (Ljava/lang/Class;J)Lau/notzed/nativez/NativeZ; + p, J +} diff --git a/src/notzed.nativez/jni/nativez-linux.c b/src/notzed.nativez/jni/nativez-linux.c index 05ce767..36aae60 100644 --- a/src/notzed.nativez/jni/nativez-linux.c +++ b/src/notzed.nativez/jni/nativez-linux.c @@ -33,45 +33,61 @@ * */ +#include +#include #include #include "nativez.h" -int nativez_ResolveLibraries(JNIEnv *env, const NZLibTable *table) { - char name[64]; - - for (int i=0;table[i].ptr;i++) { - void *lib; - - sprintf(name, "lib%s.so", table[i].name); - - lib = dlopen(name, RTLD_LAZY | RTLD_GLOBAL); - if (!lib) { - fprintf(stderr, "Unable to open library `%s'\n", name); - perror("dlopen"); - fflush(stderr); - return -1; - } +static int fail(const char *ctx, const char *what) { + fprintf(stderr, "%s: %s\n", ctx, what); + perror(ctx); + fflush(stderr); + return -1; +} - *(table[i].ptr) = lib; +int nativez_ResolveLibraries(JNIEnv *env, NZLibTable *table) { + for (int i=0;table[i].name;i++) { + table[i].lib = dlopen(table[i].path, RTLD_LAZY | RTLD_GLOBAL); + if (!table[i].lib && (table[i].flags & NZSO_NONCORE) == 0) + return fail("open library", table[i].path); } return 0; } -int nativez_ResolveFunctions(JNIEnv *env, const NZFuncTable * const table) { +int nativez_ResolveFunctions(JNIEnv *env, const NZLibTable *table, const char *fn_names, void *fnp) { void *lib = NULL; - for (int i=0;table[i].ptr;i++) { - if (table[i].name) { - void *entry = dlsym(lib, table[i].name); + const char *name = fn_names; + int index = 0; + const char *lib_name = ""; + void **fn = fnp; + int lib_flags = 0; + + while (*name) { + const char *next = name + strlen(name) + 1; - *(table[i].ptr) = entry; - if (!entry) { - fprintf(stderr, "Unable to resolve `%s'\n", table[i].name); - fflush(stderr); + if (*name == '#') { + lib = NULL; + lib_flags = 0; + lib_name = name+1; + for (int i=0;table[i].name;i++) { + if (strcmp(table[i].name, lib_name) == 0) { + lib = table[i].lib; + lib_flags = table[i].flags; + break; + } } - } else { - lib = *(table[i].ptr); + } else if (lib) { + void *entry = dlsym(lib, name); + + fn[index++] = entry; + if (!entry) + return fail("resolve function", name); + } else if ((lib_flags & NZSO_NONCORE) == 0) { + return fail(lib_name, name); } + + name = next; } return 0; diff --git a/src/notzed.nativez/jni/nativez-windows.c b/src/notzed.nativez/jni/nativez-windows.c index 1b8241d..ff616e9 100644 --- a/src/notzed.nativez/jni/nativez-windows.c +++ b/src/notzed.nativez/jni/nativez-windows.c @@ -37,41 +37,55 @@ #include "nativez.h" -int nativez_ResolveLibraries(JNIEnv *env, const NZLibTable *table) { - char name[64]; - - for (int i=0;table[i].ptr;i++) { - void *lib; - - sprintf(name, "%s-%d.dll", table[i].name, table[i].version); - - lib = LoadLibrary(name); - if (!lib) { - fprintf(stderr, "Unable to open library `%s'\n", name); - perror("dlopen"); - fflush(stderr); - return -1; - } +static int fail(const char *ctx, const char *what) { + fprintf(stderr, "%s: %s\n", ctx, what); + perror(ctx); + fflush(stderr); + return -1; +} - *(table[i].ptr) = lib; +int nativez_ResolveLibraries(JNIEnv *env, NZLibTable *table) { + for (int i=0;table[i].name;i++) { + table[i].lib = LoadLibrary(table[i].name); + if (!table[i].lib && (table[i].flags & NZSO_NONCORE) == 0) + return fail("open library", table[i].name); } return 0; } -int nativez_ResolveFunctions(JNIEnv *env, const NZFuncTable * const table) { +int nativez_ResolveFunctions(JNIEnv *env, const NZLibTable *table, const char *fn_names, void *fnp) { void *lib = NULL; - for (int i=0;table[i].ptr;i++) { - if (table[i].name) { - void *entry = GetProcAddress(lib, table[i].name); + const char *name = fn_names; + int index = 0; + const char *lib_name = ""; + void **fn = fnp; + int lib_flags = 0; + + while (*name) { + const char *next = name + strlen(name) + 1; - *(table[i].ptr) = entry; - if (!entry) { - fprintf(stderr, "Unable to resolve `%s'\n", table[i].name); - fflush(stderr); + if (*name == '#') { + lib = NULL; + lib_flags = 0; + lib_name = name+1; + for (int i=0;table[i].name;i++) { + if (strcmp(table[i].name, lib_name) == 0) { + lib = table[i].lib; + lib_flags = table[i].flags; + break; + } } - } else { - lib = *(table[i].ptr); + } else if (lib) { + void *entry = GetProcAddress(lib, name); + + fn[index++] = entry; + if (!entry) + return fail("resolve function", name); + } else if ((lib_flags & NZSO_NONCORE) == 0) { + return fail(lib_name, name); } + + name = next; } return 0; diff --git a/src/notzed.nativez/jni/nativez.h b/src/notzed.nativez/jni/nativez.h index 74c37e6..a192dbb 100644 --- a/src/notzed.nativez/jni/nativez.h +++ b/src/notzed.nativez/jni/nativez.h @@ -38,79 +38,52 @@ #include -/* - For resolving classes and methods with little code - Sequence: (JCLASS JMETHOD* JSMETHOD* JFIELD* JSFIEKD* - */ - -// Resolve a class stored in a variable -#define JCLASS(x, name) { 1, name, NULL, (void **)&x } -// Resolve a class not saved -#define JVCLASS(name) { 1, name, NULL, NULL } -// Resolve an object method on the last resolved class -#define JMETHOD(x, name, sig) { 2, name, sig, (void **)&x } -// Resolve a static method on the last resolved class -#define JSMETHOD(x, name, sig) { 3, name, sig, (void **)&x } -// Resolve an object field on the last resolved class -#define JFIELD(x, name, sig) { 4, name, sig, (void **)&x } -// Resolve a static field on the last resolved class -#define JSFIELD(x, name, sig) { 5, name, sig, (void **)&x } -// End the table -#define JEND { 0, NULL, NULL, NULL } - -typedef struct NZRefTable { - const int type; - const char *name; - const char *signature; - void **ptr; -} NZRefTable; - -int nativez_ResolveReferences(JNIEnv *env, const NZRefTable *table); - -/* - For resolving link libraries. +/** + * Resolves a java table created by nativez-gen */ +int nativez_ResolveReferences(JNIEnv *env, const char *jn_names, void *jnp); -// Define a library base name, version and flags. -// A variable `_lib' must exist accessible to the compilation -// unit to store the library handle. -#define DLSO(name, v, flags) { #name, v, flags, (void **)&name ## _lib } - +/** + * Support for dynamic library loading. + * + * It happens in two parts: + * + * 1. load the libraries using nativez_ResolveLibraries; + * 2. resolve the function pointers using nativez_ResolveFunctions. + * + */ typedef struct NZLibTable { - const char * name; /* name of library */ - const int version; /* version of library, used on some platforms */ - const int flags; /* DLSO_* flags */ - void **ptr; /* pointer to library handle */ + const char *name; /* portable name of library */ + const char *path; /* platform-specific name of library file */ + const int flags; /* NZSO_* flags */ + void *lib; /* pointer to library handle */ } NZLibTable; -#define DLSO_NONCORE 1 // non-core library, if missing is safely ignored +// Define NZLibTable entry. +#define NZSO(name, path, flags) { name, path, flags } +#define NZSO_END { 0 } -int nativez_ResolveLibraries(JNIEnv *env, const NZLibTable *table); +// non-core library, non-existance is not a failure +#define NZSO_NONCORE 1 -/* - Resolve functions from libraries, table is 0-terminated. - - Sequence: (DLLIB DLFUNC*)* DLEND -*/ - -// Set the current library variable. It doesn't include the _lib suffix. -#define DLLIB(x) { NULL, &x ## _lib } -// Resolve a function by name. The variable holding the function pointer must start with 'd'. -#define DLFUNC(x) { #x, (void **)&(d ## x) } -// Terminate the list -#define DLEND { NULL, NULL } - -typedef struct JJFuncTable { - const char *name; - void **ptr; -} NZFuncTable; +/** + * ResolveLibraries loads libraires via a table of NZLibTable entries. + * The library name is platform specific. Also see NZSO_* flags. + * The opened library is stored in the table[].lib. + * The table is terminated with an empty entry or NZSO_END. + */ +int nativez_ResolveLibraries(JNIEnv *env, NZLibTable *table); -// Check if function exists, return value if not -#define DLCHECK_RET(env, x, ret) do { if (!nativez_NonNull(env, #x, (void *)d ## x)) { return ret; } } while (0) -// Call a function pointer -#define DLCALL(x) (* d ## x) +/** + * ResolveFunctions uses the output of nativez-gen to fill out + * a table. + */ +int nativez_ResolveFunctions(JNIEnv *env, const NZLibTable *table, const char *fn_names, void *fnp); -int nativez_ResolveFunctions(JNIEnv *env, const NZFuncTable *table); +// Check if function exists, return value if not and set an exception +#define NZCHECK_RET(env, x, ret) do { if (!nativez_NonNull(env, #x, (void *)fn.x)) { return ret; } } while (0) +// Call a function pointer, or just use the struct directly. +#define NZCALL(x) (fn.x) /** * Checks if ptr is non-null, if it is null throws a NullPointer -- 2.39.5