From: Matt Corallo Date: Tue, 2 Feb 2021 22:37:06 +0000 (-0500) Subject: Add workarounds for Android JNI quirks X-Git-Tag: v0.0.1~3 X-Git-Url: http://git.bitcoin.ninja/index.cgi?p=ldk-java;a=commitdiff_plain;h=c740af8efd2dd15d8b5e2e109ce18714b1b65629 Add workarounds for Android JNI quirks --- diff --git a/README.md b/README.md index 3768f520..b1f0b74c 100644 --- 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 ====== diff --git a/genbindings.py b/genbindings.py index d6e431f7..be4bc64e 100755 --- a/genbindings.py +++ b/genbindings.py @@ -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 diff --git a/genbindings.sh b/genbindings.sh index f4c5a80d..01ef62fe 100755 --- a/genbindings.sh +++ b/genbindings.sh @@ -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 diff --git a/java_strings.py b/java_strings.py index bc3c73cf..119693d5 100644 --- a/java_strings.py +++ b/java_strings.py @@ -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_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: