Use a generator for the java and native library lookups.
Change the library table to be read/write and include the full name.
# 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
# <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
# ----------------
# <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
# -------
# 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
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
--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)))
# 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
# 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
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)))))
# ######################################################################
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 \
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 $< $@
--- /dev/null
+#!/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";
+}
#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");
/* ********************************************************************** */
-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;
}
/* ********************************************************************** */
--- /dev/null
+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
+}
*
*/
+#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;
#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;
#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