Skip to content

Add support for jniLibs #824

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion src/gd_kotlin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@
unlink(file_user_path_global.utf8().get_data()); // we do not really care about errors here
#endif
Ref<DirAccess> dir_access {DirAccess::open(USER_DIRECTORY)};
dir_access->make_dir(JVM_DIRECTORY);
dir_access->make_dir_recursive(JNI_LIBS_PATH);

Check failure on line 221 in src/gd_kotlin.cpp

View workflow job for this annotation

GitHub Actions / 🍎 Build macOS / Build release template x86_64

use of undeclared identifier 'JNI_LIBS_PATH'

Check failure on line 221 in src/gd_kotlin.cpp

View workflow job for this annotation

GitHub Actions / 🍎 Build macOS / Build debug template x86_64

use of undeclared identifier 'JNI_LIBS_PATH'

Check failure on line 221 in src/gd_kotlin.cpp

View workflow job for this annotation

GitHub Actions / 🍏 Build iOS / Build ios debug (arm64)

use of undeclared identifier 'JNI_LIBS_PATH'

Check failure on line 221 in src/gd_kotlin.cpp

View workflow job for this annotation

GitHub Actions / 🪟 Build Windows / Build debug template

'JNI_LIBS_PATH': undeclared identifier

Check failure on line 221 in src/gd_kotlin.cpp

View workflow job for this annotation

GitHub Actions / 🪟 Build Windows / Build release template

'JNI_LIBS_PATH': undeclared identifier

Check failure on line 221 in src/gd_kotlin.cpp

View workflow job for this annotation

GitHub Actions / 🍎 Build macOS / Build debug template arm64

use of undeclared identifier 'JNI_LIBS_PATH'

Check failure on line 221 in src/gd_kotlin.cpp

View workflow job for this annotation

GitHub Actions / 🍏 Build iOS / Build ios release (arm64)

use of undeclared identifier 'JNI_LIBS_PATH'

Check failure on line 221 in src/gd_kotlin.cpp

View workflow job for this annotation

GitHub Actions / 🍎 Build macOS / Build release template arm64

use of undeclared identifier 'JNI_LIBS_PATH'
dir_access->copy(file_res_path, file_user_path);
#ifndef __ANDROID__
}
Expand Down Expand Up @@ -285,6 +285,35 @@
return true;
}

#ifdef __ANDROID__
Vector<String> GDKotlin::get_res_files_recursively(const String &path) {
const Ref<DirAccess> dir_access = DirAccess::open(String{"res://"} + path);
if (!dir_access.is_valid()) return {};

dir_access->list_dir_begin();
Vector<String> files;

while (true) {
String file_name = dir_access->get_next();
if (file_name.is_empty()) break;

if (file_name == "." || file_name == "..") continue;

String full_path = path.path_join(file_name);

if (dir_access->current_is_dir()) {
files.append_array(get_res_files_recursively(full_path));
} else {
files.push_back(full_path);
}
}

dir_access->list_dir_end();
return files;
}
#endif


bool GDKotlin::load_user_code() {
jni::Env env {jni::Jvm::current_env()};
if (user_configuration.vm_type == jni::JvmType::GRAAL_NATIVE_IMAGE) {
Expand All @@ -297,6 +326,13 @@
String user_code_path {copy_new_file_to_user_dir(USER_CODE_FILE)};
#endif

#ifdef __ANDROID__
for (auto file : get_res_files_recursively(JNI_LIBS_PATH)) {
JVM_LOG_INFO("Copying file: %s", file);
copy_new_file_to_user_dir(file);
}
#endif

if (!FileAccess::exists(user_code_path)) {
String message {"No main.jar detected at %s. No classes will be loaded. Build the gradle "
"project to load classes"};
Expand Down
4 changes: 4 additions & 0 deletions src/gd_kotlin.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ class GDKotlin {
static String get_path_to_native_image();
#endif

#ifdef __ANDROID__
static Vector<String> get_res_files_recursively(const String &path);
#endif

bool load_bootstrap();
void unload_boostrap();

Expand Down
42 changes: 40 additions & 2 deletions src/kotlin_editor_export_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,13 @@
_generate_export_configuration_file(jni::JvmType::GRAAL_NATIVE_IMAGE);
}
} else if (is_android_export) {
const String jni_libs_dir {String(RES_DIRECTORY).path_join(JVM_DIRECTORY).path_join(JNI_LIBS_BASE_DIR)};

// add jniLibs dir with native libraries per platform
for (const auto file : _get_files_recursively(jni_libs_dir)) {

Check warning on line 136 in src/kotlin_editor_export_plugin.cpp

View workflow job for this annotation

GitHub Actions / 🍎 Build macOS / Build editor release arm64 (target=editor)

loop variable 'file' creates a copy from type 'String const'

Check warning on line 136 in src/kotlin_editor_export_plugin.cpp

View workflow job for this annotation

GitHub Actions / 🍎 Build macOS / Build editor release x86_64 (target=editor)

loop variable 'file' creates a copy from type 'String const'

Check warning on line 136 in src/kotlin_editor_export_plugin.cpp

View workflow job for this annotation

GitHub Actions / 🍎 Build macOS / Build editor debug arm64 (target=editor, debug_symbols=true )

loop variable 'file' creates a copy from type 'String const'

Check warning on line 136 in src/kotlin_editor_export_plugin.cpp

View workflow job for this annotation

GitHub Actions / 🍎 Build macOS / Build editor debug x86_64 (target=editor, debug_symbols=true )

loop variable 'file' creates a copy from type 'String const'

Check warning on line 136 in src/kotlin_editor_export_plugin.cpp

View workflow job for this annotation

GitHub Actions / 🍎 Build macOS / Build editor dev x86_64 (target=editor, dev_build=yes, debug_symbols=true )

loop variable 'file' creates a copy from type 'String const'

Check warning on line 136 in src/kotlin_editor_export_plugin.cpp

View workflow job for this annotation

GitHub Actions / 🍎 Build macOS / Build editor dev arm64 (target=editor, dev_build=yes, debug_symbols=true )

loop variable 'file' creates a copy from type 'String const'
files_to_add.push_back(file);
}

_generate_export_configuration_file(jni::JvmType::ART);
} else if (is_ios_export) {
String base_ios_build_dir {String(RES_DIRECTORY).path_join(JVM_DIRECTORY).path_join("ios")};
Expand Down Expand Up @@ -183,17 +190,46 @@
get_export_preset()->set_exclude_filter(get_export_preset()->get_exclude_filter() + "," + JVM_CONFIGURATION_PATH);
}

if (const String build_dir = String {BUILD_DIRECTORY}.path_join("*"); !get_export_preset()->get_exclude_filter().contains(build_dir)) {
if (const String build_dir = String {BUILD_DIRECTORY}.path_join("*");
!get_export_preset()->get_exclude_filter().contains(build_dir)) {
// exclude build folder
get_export_preset()->set_exclude_filter(get_export_preset()->get_exclude_filter() + "," + build_dir);
}

if (const String jre_jars = String {"res://"} + JVM_DIRECTORY + "jre-*/**/*.jar"; !get_export_preset()->get_exclude_filter().contains(jre_jars)) {
if (const String jre_jars = String {"res://"} + JVM_DIRECTORY + "jre-*/**/*.jar";
!get_export_preset()->get_exclude_filter().contains(jre_jars)) {
// exclude any jars in the embedded jre
get_export_preset()->set_exclude_filter(get_export_preset()->get_exclude_filter() + "," + jre_jars);
}
}

Vector<String> KotlinEditorExportPlugin::_get_files_recursively(const String &path) {
const Ref<DirAccess> dir_access = DirAccess::open(path);
if (!dir_access.is_valid()) return {};

dir_access->list_dir_begin();
Vector<String> files;

while (true) {
String file_name = dir_access->get_next();
if (file_name.is_empty()) break;

if (file_name == "." || file_name == "..") continue;

String full_path = path.path_join(file_name);

if (dir_access->current_is_dir()) {
files.append_array(_get_files_recursively(full_path));
} else {
files.push_back(full_path);
}
}

dir_access->list_dir_end();
return files;
}


String KotlinEditorExportPlugin::get_name() const {
return "Godot Kotlin/Jvm";
}
Expand All @@ -207,4 +243,6 @@
}
}



#endif
1 change: 1 addition & 0 deletions src/kotlin_editor_export_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class KotlinEditorExportPlugin : public EditorExportPlugin {
private:
void _generate_export_configuration_file(jni::JvmType vm_type);
void _add_exclude_filter_preset();
static Vector<String> _get_files_recursively(const String& path);
};

#endif// GODOT_JVM_KOTLINEDITOREXPORTPLUGIN_H
Expand Down
22 changes: 18 additions & 4 deletions src/lifecycle/class_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
#include <sys/stat.h>
#endif

#include "core/config/project_settings.h"
#include "paths.h"

#include <cassert>

ClassLoader::ClassLoader(jni::Env& p_env, jni::JObject p_wrapped) {
Expand Down Expand Up @@ -43,11 +46,22 @@ ClassLoader* ClassLoader::create_instance(jni::Env& env, const String& full_jar_
jni::JClass class_loader_cls {env.find_class("dalvik/system/DexClassLoader")};
jni::MethodID ctor {class_loader_cls.get_constructor_method_id(env, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)V")};
jni::JObject jar_path {env.new_string(full_jar_path.utf8().get_data())};

jni::JObject parent_loader;
if (p_parent_loader.is_null()) {
jni::MethodID get_system_loader = class_loader_cls.get_static_method_id(env, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
parent_loader = class_loader_cls.call_static_object_method(env, get_system_loader);
} else {
parent_loader = p_parent_loader;
}

const jni::JObject jni_libs_path {env.new_string(ProjectSettings::get_singleton()->globalize_path(String{"user://"} + JNI_LIBS_PATH).utf8().get_data())};

jvalue args[4] = {
jni::to_jni_arg(jar_path),
jni::to_jni_arg(jni::JObject(nullptr)),
jni::to_jni_arg(jni::JObject(nullptr)),
jni::to_jni_arg(p_parent_loader)
jni::to_jni_arg(jar_path), // dexPath -> String: the list of jar/apk files containing classes and resources, delimited by File.pathSeparator, which defaults to ":" on Android
jni::to_jni_arg(jni::JObject(nullptr)), // optimizedDirectory -> String: this parameter is deprecated and has no effect since API level 26.
jni::to_jni_arg(jni_libs_path), // librarySearchPath -> String: the list of directories containing native libraries, delimited by File.pathSeparator; may be null
jni::to_jni_arg(parent_loader) // parent -> ClassLoader: the parent class loader
};
#else
jni::JObject url = to_java_url(env, full_jar_path);
Expand Down
14 changes: 14 additions & 0 deletions src/lifecycle/paths.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
// Needs this as a macro if we want to append it to all other paths.
#define JVM_DIRECTORY "jvm/"

# define JNI_LIBS_BASE_DIR "android/jniLibs"

static constexpr const char* USER_DIRECTORY {"user://"};
static constexpr const char* RES_DIRECTORY {"res://"};

Expand Down Expand Up @@ -85,6 +87,18 @@ static constexpr const char* USER_CODE_FILE {ANDROID_USER_CODE_FILE};
static constexpr const char* GRAAL_NATIVE_IMAGE_FILE {ANDROID_GRAAL_NATIVE_IMAGE_FILE};
static constexpr const char* RELATIVE_JVM_LIB_PATH {ANDROID_RELATIVE_JVM_LIB_PATH};

#ifdef __aarch64__
static constexpr const char* JNI_LIBS_PATH {JVM_DIRECTORY JNI_LIBS_BASE_DIR "/" "arm64-v8a"};
#elif defined(__arm__)
static constexpr const char* JNI_LIBS_PATH {JVM_DIRECTORY JNI_LIBS_BASE_DIR "/" "armeabi"};
#elif defined(__x86_64__)
static constexpr const char* JNI_LIBS_PATH {JVM_DIRECTORY JNI_LIBS_BASE_DIR "/" "x86_64"};
#elif defined(__i386__)
static constexpr const char* JNI_LIBS_PATH {JVM_DIRECTORY JNI_LIBS_BASE_DIR "/" "x86"};
#else
#error "Unsupported architecture"
#endif

#elif IOS_ENABLED

static constexpr const char* BOOTSTRAP_FILE {IOS_BOOTSTRAP_FILE};
Expand Down
Loading