Add workarounds for Android JNI quirks
authorMatt Corallo <git@bluematt.me>
Tue, 2 Feb 2021 22:37:06 +0000 (17:37 -0500)
committerMatt Corallo <git@bluematt.me>
Wed, 3 Feb 2021 00:45:09 +0000 (19:45 -0500)
README.md
genbindings.py
genbindings.sh
java_strings.py

index 3768f520433f8066cafa03739a96b6907d4a6ce5..b1f0b74c3176331adba3d34d5951d5752aad651e 100644 (file)
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@ Building
 
 A release build of the Java bindings library for Linux is available in git. Thus, the bindings should work as long as the `LD_LIBRARY_PATH` includes the top-level directory of this repository.
 
-To build the bindings locally, the bindings require some additional work which is still making its way upstream, for now it should be built against the [rust-lightning 2020-10-java-bindings-base branch on git.bitcoin.ninja](https://git.bitcoin.ninja/?p=rust-lightning;a=shortlog;h=refs/heads/2020-10-java-bindings-base). Check that branch out locally and run the `genbindings.sh` script in it to build the required binaries. Thereafter, in this repo, run the `genbindings.sh` script with the first argument pointing to the rust-lightning directory, and the second the relevant JNI CFLAGS and the third argument set to `true` or `false` to indicate whether building in debug mode. JNI CFLAGS on debian are likely "-I/usr/lib/jvm/java-11-openjdk-amd64/include/ -I/usr/lib/jvm/java-11-openjdk-amd64/include/linux/". When running a program linking against the library in debug mode, LD_PRELOAD should likely include the relevant `libclang_rt.asan-platform.so` path.
+To build the bindings locally, the bindings require some additional work which is still making its way upstream, for now it should be built against the [rust-lightning 2020-10-java-bindings-base branch on git.bitcoin.ninja](https://git.bitcoin.ninja/?p=rust-lightning;a=shortlog;h=refs/heads/2020-10-java-bindings-base). Check that branch out locally and run the `genbindings.sh` script in it to build the required binaries. Thereafter, in this repo, run the `genbindings.sh` script with the first argument pointing to the rust-lightning directory, the second the relevant JNI CFLAGS, the third argument set to `true` or `false` to indicate whether building in debug mode, and the third set to true or false to indicate if the bindings should be built with workarounds required for Android. JNI CFLAGS on debian are likely "-I/usr/lib/jvm/java-11-openjdk-amd64/include/ -I/usr/lib/jvm/java-11-openjdk-amd64/include/linux/". When running a program linking against the library in debug mode, LD_PRELOAD should likely include the relevant `libclang_rt.asan-platform.so` path.
 
 Status
 ======
index d6e431f7abcbc8c9f687804c8bcdc39574289f84..be4bc64ef4c29221f2aac10a5b50413768c722b5 100755 (executable)
@@ -14,8 +14,12 @@ else:
     sys.exit(1)
 
 target = None
-if sys.argv[6] == "java":
+if sys.argv[6] == "java" or sys.argv[6] == "android":
+    import java_strings
     from java_strings import Consts
+    target = java_strings.Target.JAVA
+    if sys.argv[6] == "android":
+        target = java_strings.Target.ANDROID
 elif sys.argv[6] == "typescript":
     import typescript_strings
     from typescript_strings import Consts
index f4c5a80d61f9baa55a49f345caff09b1e3f2ef6c..01ef62fed42893f576720ad375c5df29c764be22 100755 (executable)
@@ -1,14 +1,20 @@
 #!/bin/bash
 usage() {
-       echo "USAGE: path/to/rust-lightning \"JNI_CFLAGS\" debug"
+       echo "USAGE: path/to/rust-lightning \"JNI_CFLAGS\" debug android"
        echo "For JNI_CFLAGS you probably want -I/usr/lib/jvm/java-11-openjdk-amd64/include/ -I/usr/lib/jvm/java-11-openjdk-amd64/include/linux/"
        echo "debug should either be true or false"
+       echo "android should either be true or false"
        exit 1
 }
 [ "$1" = "" -o "$2" = "" ] && usage
 [ "$3" != "true" -a "$3" != "false" ] && usage
+[ "$4" != "true" -a "$4" != "false" ] && usage
 
-COMMON_COMPILE="clang -std=c11 -Wall -Wextra -Wno-unused-parameter -Wno-ignored-qualifiers -Wno-unused-function -Wno-nullability-completeness -Wno-pointer-sign"
+if [ "$CC" != "" ]; then
+       COMMON_COMPILE="$CC -std=c11 -Wall -Wextra -Wno-unused-parameter -Wno-ignored-qualifiers -Wno-unused-function -Wno-nullability-completeness -Wno-pointer-sign"
+else
+       COMMON_COMPILE="clang -std=c11 -Wall -Wextra -Wno-unused-parameter -Wno-ignored-qualifiers -Wno-unused-function -Wno-nullability-completeness -Wno-pointer-sign"
+fi
 
 set -e
 
@@ -16,7 +22,11 @@ echo "Creating Java bindings..."
 mkdir -p src/main/java/org/ldk/{enums,structs}
 rm -f src/main/java/org/ldk/{enums,structs}/*.java
 rm -f src/main/jni/*.h
-./genbindings.py "$1/lightning-c-bindings/include/lightning.h" src/main/java/org/ldk/impl/bindings.java src/main/java/org/ldk src/main/jni/bindings.c $3 java
+if [ "$4" = "true" ]; then
+       ./genbindings.py "$1/lightning-c-bindings/include/lightning.h" src/main/java/org/ldk/impl/bindings.java src/main/java/org/ldk src/main/jni/bindings.c $3 android $4
+else
+       ./genbindings.py "$1/lightning-c-bindings/include/lightning.h" src/main/java/org/ldk/impl/bindings.java src/main/java/org/ldk src/main/jni/bindings.c $3 java $4
+fi
 javac -h src/main/jni src/main/java/org/ldk/enums/*.java src/main/java/org/ldk/impl/bindings.java
 rm src/main/java/org/ldk/enums/*.class src/main/java/org/ldk/impl/bindings*.class
 
index bc3c73cf05f2ea841bd68123264e8287c0d967fb..119693d54e33b5cde04d37473312fa8986ed9417 100644 (file)
@@ -1,7 +1,13 @@
 from bindingstypes import *
+from enum import Enum
+
+class Target(Enum):
+    JAVA = 1,
+    ANDROID = 2
 
 class Consts:
-    def __init__(self, DEBUG: bool, **kwargs):
+    def __init__(self, DEBUG: bool, target: Target, **kwargs):
+        self.target = target
         self.c_array_class_caches = set()
         self.c_type_map = dict(
             uint8_t = ['byte'],
@@ -449,7 +455,10 @@ import java.util.Arrays;
         out_c = out_c + self.c_fn_ty_pfx + "void JNICALL Java_org_ldk_impl_bindings_00024" + struct_name.replace("_", "_1") + "_init (" + self.c_fn_args_pfx + ") {\n"
         for var_name in variants:
             out_c = out_c + "\t" + struct_name + "_" + var_name + "_class =\n"
-            out_c = out_c + "\t\t(*env)->NewGlobalRef(env, (*env)->FindClass(env, \"Lorg/ldk/impl/bindings$" + struct_name + "$" + var_name + ";\"));\n"
+            if self.target == Target.ANDROID:
+                out_c = out_c + "\t\t(*env)->NewGlobalRef(env, (*env)->FindClass(env, \"org/ldk/impl/bindings$" + struct_name + "$" + var_name + "\"));\n"
+            else:
+                out_c = out_c + "\t\t(*env)->NewGlobalRef(env, (*env)->FindClass(env, \"Lorg/ldk/impl/bindings$" + struct_name + "$" + var_name + ";\"));\n"
             out_c = out_c + "\tCHECK(" + struct_name + "_" + var_name + "_class != NULL);\n"
             out_c = out_c + "\t" + struct_name + "_" + var_name + "_meth = (*env)->GetMethodID(env, " + struct_name + "_" + var_name + "_class, \"<init>\", \"(" + init_meth_jty_strs[var_name] + ")V\");\n"
             out_c = out_c + "\tCHECK(" + struct_name + "_" + var_name + "_meth != NULL);\n"
@@ -612,7 +621,7 @@ import java.util.Arrays;
                 out_c = out_c + "\t" + struct_name + "_JCalls *j_calls = (" + struct_name + "_JCalls*) this_arg;\n"
                 out_c = out_c + "\tif (atomic_fetch_sub_explicit(&j_calls->refcnt, 1, memory_order_acquire) == 1) {\n"
                 out_c = out_c + "\t\tJNIEnv *env;\n"
-                out_c = out_c + "\t\tDO_ASSERT((*j_calls->vm)->GetEnv(j_calls->vm, (void**)&env, JNI_VERSION_1_8) == JNI_OK);\n"
+                out_c = out_c + "\t\tDO_ASSERT((*j_calls->vm)->GetEnv(j_calls->vm, (void**)&env, JNI_VERSION_1_6) == JNI_OK);\n"
                 out_c = out_c + "\t\t(*env)->DeleteWeakGlobalRef(env, j_calls->o);\n"
                 out_c = out_c + "\t\tFREE(j_calls);\n"
                 out_c = out_c + "\t}\n}\n"
@@ -632,7 +641,7 @@ import java.util.Arrays;
                 out_c = out_c + ") {\n"
                 out_c = out_c + "\t" + struct_name + "_JCalls *j_calls = (" + struct_name + "_JCalls*) this_arg;\n"
                 out_c = out_c + "\tJNIEnv *env;\n"
-                out_c = out_c + "\tDO_ASSERT((*j_calls->vm)->GetEnv(j_calls->vm, (void**)&env, JNI_VERSION_1_8) == JNI_OK);\n"
+                out_c = out_c + "\tDO_ASSERT((*j_calls->vm)->GetEnv(j_calls->vm, (void**)&env, JNI_VERSION_1_6) == JNI_OK);\n"
 
                 for arg_info in fn_line.args_ty:
                     if arg_info.ret_conv is not None: