Added some useful variables to java.make
authorMichael Zucchi <michael@swordfish.com.au>
Mon, 22 Apr 2019 09:16:06 +0000 (18:46 +0930)
committerMichael Zucchi <michael@swordfish.com.au>
Mon, 22 Apr 2019 09:16:06 +0000 (18:46 +0930)
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
java.make
src/notzed.nativez/jni/jni.make
src/notzed.nativez/jni/nativez-gen [new file with mode: 0755]
src/notzed.nativez/jni/nativez-jni.c
src/notzed.nativez/jni/nativez-jni.def [new file with mode: 0644]
src/notzed.nativez/jni/nativez-linux.c
src/notzed.nativez/jni/nativez-windows.c
src/notzed.nativez/jni/nativez.h

index 08853c7..f82e020 100644 (file)
@@ -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
index c7074ab..7228203 100644 (file)
--- a/java.make
+++ b/java.make
 # <module>_JARFLAGS
 # <module>_JMODFLAGS
 
+# <module>_JAVA                Java sources.  If not set it is found from src/<module>/classes/(*.java)
+# <module>_RESOURCES   .jar resources.  If not set it is found from src/<module>/classes/(not *.java)
+# <module>_JAVA_GENERATED      Java generated sources.  These must be relative to the package name.
 
-# <module>_JAVA                Java sources.  This is set internally.
-# <module>_RESOURCES   .jar resources.  This is set internally.
+# Variables for use in fragments
+
+# gen.make and jni.make can additionally make use of these variables
+
+# <module>_gendir      Location for files used in Java generation process (per project).
+# <module>_genjavadir  Location where _JAVA_GENERATED .java files will be created (per project).
+# <module>_jnidir      Location for jni generated files (per target).
+# <module>_objdir      Location for c objects (per target).
+# <module>_incdir      Location for output includes, .jmod staging.
+# <module>_libdir      Location for output libraries, .jmod staging.  May point to _bindir.
+# <module>_bindir      Location for output commands, .jmod staging.
 
 # Define libraries
 # ----------------
@@ -81,6 +93,7 @@
 
 # <library>_SOURCES    .c, .cc, .C - source files for library.  Paths are relative to src/<module>/jni.
 # <library>_HEADERS    header files for jmod
+# <library>_COMMANDS   commands/bin/scripts for jmod
 
 # <library>_LDFLAGS    link flags
 # <library>_LIBADD     extra objects to add to link line
 
 # .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             \
index c9908db..f2cad7d 100644 (file)
@@ -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 (executable)
index 0000000..2c7844c
--- /dev/null
@@ -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 (<IN>) {
+    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 (<PROTO>) {
+           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/<init>/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";    
+}
index d3c7593..77c553c 100644 (file)
 
 #include <stdlib.h>
 #include <stdint.h>
+#include <string.h>
 
 #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 (file)
index 0000000..3fa29af
--- /dev/null
@@ -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
+}
index 05ce767..36aae60 100644 (file)
  * 
  */
 
+#include <string.h>
+#include <stdio.h>
 #include <dlfcn.h>
 
 #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;
index 1b8241d..ff616e9 100644 (file)
 
 #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;
index 74c37e6..a192dbb 100644 (file)
 
 #include <jni.h>
 
-/*
-  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 `<name>_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