# HG changeset patch # User Scoopta # Date 1680570514 25200 # Mon Apr 03 18:08:34 2023 -0700 # Node ID 5b028720129f1876b62911f1bb5f2a3be36ef566 # Parent d6fa320a38703f1cdbd052e1135efe306ffd817e I finally figured out how to do modules with JNI diff --git a/README.md b/README.md --- a/README.md +++ b/README.md @@ -3,11 +3,11 @@ ## Dependencies wofi - openjdk-11-jdk - pkg-config + openjdk-17-jdk + pkgconf meson ## Building hg clone https://hg.sr.ht/~scoopta/WofiJ cd WofiJ/src - meson -Djdk_home=$JAVA_HOME -Dmode_class=org/example/MyMode ../build + meson -Djdk_home=$JAVA_HOME -Dwofij_path=/path/to/wofij.jar -Dmode_class=com.example.my_mode/com.example.my_mode.Main -Dmode_path=/path/to/my/mode.jar ../build ninja -C ../build diff --git a/src/meson.build b/src/meson.build --- a/src/meson.build +++ b/src/meson.build @@ -5,13 +5,13 @@ pixbuf = dependency('gdk-pixbuf-2.0') java_home = get_option('jdk_home') +wofij_path = get_option('wofij_path') mode_class = get_option('mode_class') -class_path = get_option('class_path') -add_project_arguments('-DMODE_CLASS="' + mode_class + '"', language : 'c') +mode_path = get_option('mode_path') -if class_path != '' - add_project_arguments('-DCLASS_PATH="' + class_path + '"', language : 'c') -endif +add_project_arguments('-DMODULE_PATH="' + wofij_path + '"', language : 'c') +add_project_arguments('-DMODE_CLASS="' + mode_class + '"', language : 'c') +add_project_arguments('-DMODE_PATH="' + mode_path + '"', language : 'c') jvm = cc.find_library('jvm', dirs : [java_home + '/lib/j9vm', java_home + '/lib/server']) @@ -23,7 +23,8 @@ deps = [wofi, jvm, pixbuf] -jsources = [jsrcdir + '/Cache.java', +jsources = ['module-info.java', + jsrcdir + '/Cache.java', jsrcdir + '/Map.java', jsrcdir + '/Mode.java', jsrcdir + '/Widget.java', diff --git a/src/meson_options.txt b/src/meson_options.txt --- a/src/meson_options.txt +++ b/src/meson_options.txt @@ -1,3 +1,4 @@ option('jdk_home', type : 'string', description : 'The path to the jdk install folder') +option('wofij_path', type : 'string', description : 'The path to the wofij jar') option('mode_class', type : 'string', description : 'The class that implements mode') -option('class_path', type : 'string', description : 'The class path to use, defaults to the path of the DSO determined at runtime, primarily used for debugging') \ No newline at end of file +option('mode_path', type : 'string', description : 'The path to your mode\'s module') diff --git a/src/module-info.java b/src/module-info.java new file mode 100644 --- /dev/null +++ b/src/module-info.java @@ -0,0 +1,3 @@ +module ninja.scoopta.software.wofij { + exports ninja.scoopta.software.wofij; +} \ No newline at end of file diff --git a/src/ninja/scoopta/software/wofij/Wofi.java b/src/ninja/scoopta/software/wofij/Wofi.java --- a/src/ninja/scoopta/software/wofij/Wofi.java +++ b/src/ninja/scoopta/software/wofij/Wofi.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Scoopta + * Copyright (C) 2020-2023 Scoopta * This file is part of WofiJ * WofiJ is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,6 +17,10 @@ package ninja.scoopta.software.wofij; +import java.util.Set; +import java.nio.file.*; +import java.lang.module.*; + public final class Wofi { final long mode; private static Wofi wofi; @@ -35,9 +39,20 @@ } } - private static final void load(long mode, Class clazz) { + private static final void load(long mode, byte[] clazz, byte[] path) { try { - impl = (Mode) clazz.getConstructor().newInstance(); + String[] p = new String(path).split(":"); + Path[] paths = new Path[p.length]; + for(int count = 0; count < p.length; ++count) { + paths[count] = Paths.get(p[count]); + } + String[] split = new String(clazz).split("/"); + + ModuleLayer boot = ModuleLayer.boot(); + Configuration config = boot.configuration().resolve(ModuleFinder.of(paths), ModuleFinder.of(), Set.of(split[0])); + ModuleLayer layer = boot.defineModulesWithOneLoader(config, ClassLoader.getSystemClassLoader()); + Module module = layer.findModule(split[0]).get(); + impl = (Mode) Class.forName(module, split[1]).getConstructor().newInstance(); wofi = new Wofi(mode); impl.load(wofi); } catch(Exception e) { diff --git a/wofi_jni/src/wofi_jni.c b/wofi_jni/src/wofi_jni.c --- a/wofi_jni/src/wofi_jni.c +++ b/wofi_jni/src/wofi_jni.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2022 Scoopta + * Copyright (C) 2020-2023 Scoopta * This file is part of WofiJ * WofiJ is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -155,15 +155,12 @@ void load(struct mode* _mode) { mode = _mode; JavaVMInitArgs args; - JavaVMOption options[1]; -#ifdef CLASS_PATH - char* cp = CLASS_PATH; -#else - char* cp = wofi_get_dso_path(mode); -#endif - options[0].optionString = utils_concat(2, "-Djava.class.path=", cp); + JavaVMOption options[2]; + char* p = MODULE_PATH; + options[0].optionString = "-Djdk.module.main=ninja.scoopta.software.wofij"; + options[1].optionString = utils_concat(2, "--module-path=", p); args.version = JNI_VERSION_10; - args.nOptions = 1; + args.nOptions = 2; args.options = options; args.ignoreUnrecognized = false; @@ -226,13 +223,17 @@ wofi = (*env)->NewGlobalRef(env, class); (*env)->RegisterNatives(env, wofi, natives, sizeof(natives) / sizeof(JNINativeMethod)); - jmethodID method = (*env)->GetStaticMethodID(env, wofi, "load", "(JLjava/lang/Class;)V"); - jclass mode_class = (*env)->FindClass(env, MODE_CLASS); - if(mode_class == NULL) { - fprintf(stderr, "Cannot find main class\n"); - exit(1); - } - (*env)->CallStaticVoidMethod(env, wofi, method, mode, mode_class); + jmethodID method = (*env)->GetStaticMethodID(env, wofi, "load", "(J[B[B)V"); + + size_t mode_class_l = strlen(MODE_CLASS); + jbyteArray arr = (*env)->NewByteArray(env, mode_class_l); + (*env)->SetByteArrayRegion(env, arr, 0, mode_class_l, (jbyte*) MODE_CLASS); + + size_t mode_path_l = strlen(MODE_PATH); + jbyteArray arr2 = (*env)->NewByteArray(env, mode_path_l); + (*env)->SetByteArrayRegion(env, arr2, 0, mode_path_l, (jbyte*) MODE_PATH); + + (*env)->CallStaticVoidMethod(env, wofi, method, mode, arr, arr2); map_jni_init(env); cache_jni_init(env);