2
0
Эх сурвалжийг харах

Merge pull request #12586 from karroffel/gdnative-gdnlibrary-changes

[GDNative] use feature tags, added load once option
Thomas Herzog 7 жил өмнө
parent
commit
bd2b1a62d9

+ 1 - 1
modules/gdnative/gd_native_library_editor.cpp

@@ -44,7 +44,7 @@ void GDNativeLibraryEditor::_find_gdnative_singletons(EditorFileSystemDirectory
 		}
 
 		Ref<GDNativeLibrary> lib = ResourceLoader::load(p_dir->get_file_path(i));
-		if (lib.is_valid() && lib->is_singleton_gdnative()) {
+		if (lib.is_valid() && lib->is_singleton()) {
 			String path = p_dir->get_file_path(i);
 			TreeItem *ti = libraries->create_item(libraries->get_root());
 			ti->set_text(0, path.get_file());

+ 234 - 141
modules/gdnative/gdnative.cpp

@@ -37,161 +37,56 @@
 
 #include "scene/main/scene_tree.h"
 
-const String init_symbol = "godot_gdnative_init";
-const String terminate_symbol = "godot_gdnative_terminate";
+const String init_symbol = "gdnative_init";
+const String terminate_symbol = "gdnative_terminate";
+const String default_symbol_prefix = "godot_";
 
 // Defined in gdnative_api_struct.gen.cpp
 extern const godot_gdnative_core_api_struct api_struct;
 
-String GDNativeLibrary::platform_names[NUM_PLATFORMS + 1] = {
-	"X11_32bit",
-	"X11_64bit",
-	"Windows_32bit",
-	"Windows_64bit",
-	"OSX",
-
-	"Android",
-
-	"iOS_32bit",
-	"iOS_64bit",
-
-	"WebAssembly",
-
-	""
-};
-String GDNativeLibrary::platform_lib_ext[NUM_PLATFORMS + 1] = {
-	"so",
-	"so",
-	"dll",
-	"dll",
-	"dylib",
-
-	"so",
-
-	"dylib",
-	"dylib",
-
-	"wasm",
-
-	""
-};
-
-GDNativeLibrary::Platform GDNativeLibrary::current_platform =
-#if defined(X11_ENABLED)
-		(sizeof(void *) == 8 ? X11_64BIT : X11_32BIT);
-#elif defined(WINDOWS_ENABLED)
-		(sizeof(void *) == 8 ? WINDOWS_64BIT : WINDOWS_32BIT);
-#elif defined(OSX_ENABLED)
-		OSX;
-#elif defined(IPHONE_ENABLED)
-		(sizeof(void *) == 8 ? IOS_64BIT : IOS_32BIT);
-#elif defined(ANDROID_ENABLED)
-		ANDROID;
-#elif defined(JAVASCRIPT_ENABLED)
-		WASM;
-#else
-		NUM_PLATFORMS;
-#endif
-
-GDNativeLibrary::GDNativeLibrary()
-	: library_paths(), singleton_gdnative(false) {
-}
+Map<String, Vector<Ref<GDNative> > > *GDNativeLibrary::loaded_libraries = NULL;
 
-GDNativeLibrary::~GDNativeLibrary() {
-}
-
-void GDNativeLibrary::_bind_methods() {
-	ClassDB::bind_method(D_METHOD("set_library_path", "platform", "path"), &GDNativeLibrary::set_library_path);
-	ClassDB::bind_method(D_METHOD("get_library_path", "platform"), &GDNativeLibrary::get_library_path);
-	ClassDB::bind_method(D_METHOD("get_active_library_path"), &GDNativeLibrary::get_active_library_path);
+GDNativeLibrary::GDNativeLibrary() {
+	config_file.instance();
 
-	ClassDB::bind_method(D_METHOD("is_singleton_gdnative"), &GDNativeLibrary::is_singleton_gdnative);
-	ClassDB::bind_method(D_METHOD("set_singleton_gdnative", "singleton"), &GDNativeLibrary::set_singleton_gdnative);
+	symbol_prefix = default_symbol_prefix;
 
-	ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "singleton_gdnative"), "set_singleton_gdnative", "is_singleton_gdnative");
-}
-
-bool GDNativeLibrary::_set(const StringName &p_name, const Variant &p_value) {
-	String name = p_name;
-	if (name.begins_with("platform/")) {
-		set_library_path(name.get_slice("/", 1), p_value);
-		return true;
-	}
-	return false;
-}
-
-bool GDNativeLibrary::_get(const StringName &p_name, Variant &r_ret) const {
-	String name = p_name;
-	if (name.begins_with("platform/")) {
-		r_ret = get_library_path(name.get_slice("/", 1));
-		return true;
+	if (GDNativeLibrary::loaded_libraries == NULL) {
+		GDNativeLibrary::loaded_libraries = memnew((Map<String, Vector<Ref<GDNative> > >));
 	}
-	return false;
 }
 
-void GDNativeLibrary::_get_property_list(List<PropertyInfo> *p_list) const {
-	for (int i = 0; i < NUM_PLATFORMS; i++) {
-		p_list->push_back(PropertyInfo(Variant::STRING,
-				"platform/" + platform_names[i],
-				PROPERTY_HINT_FILE,
-				"*." + platform_lib_ext[i]));
-	}
+GDNativeLibrary::~GDNativeLibrary() {
 }
 
-void GDNativeLibrary::set_library_path(StringName p_platform, String p_path) {
-	int i;
-	for (i = 0; i <= NUM_PLATFORMS; i++) {
-		if (i == NUM_PLATFORMS) break;
-		if (platform_names[i] == p_platform) {
-			break;
-		}
-	}
-
-	if (i == NUM_PLATFORMS) {
-		ERR_EXPLAIN(String("No such platform: ") + p_platform);
-		ERR_FAIL();
-	}
+void GDNativeLibrary::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("get_config_file"), &GDNativeLibrary::get_config_file);
 
-	library_paths[i] = p_path;
-}
+	ClassDB::bind_method(D_METHOD("get_current_library_path"), &GDNativeLibrary::get_current_library_path);
+	ClassDB::bind_method(D_METHOD("get_current_dependencies"), &GDNativeLibrary::get_current_dependencies);
+	ClassDB::bind_method(D_METHOD("is_current_library_statically_linked"), &GDNativeLibrary::is_current_library_statically_linked);
 
-String GDNativeLibrary::get_library_path(StringName p_platform) const {
-	int i;
-	for (i = 0; i <= NUM_PLATFORMS; i++) {
-		if (i == NUM_PLATFORMS) break;
-		if (platform_names[i] == p_platform) {
-			break;
-		}
-	}
+	ClassDB::bind_method(D_METHOD("should_load_once"), &GDNativeLibrary::should_load_once);
+	ClassDB::bind_method(D_METHOD("is_singleton"), &GDNativeLibrary::is_singleton);
+	ClassDB::bind_method(D_METHOD("get_symbol_prefix"), &GDNativeLibrary::get_symbol_prefix);
 
-	if (i == NUM_PLATFORMS) {
-		ERR_EXPLAIN(String("No such platform: ") + p_platform);
-		ERR_FAIL_V("");
-	}
+	ClassDB::bind_method(D_METHOD("set_load_once", "load_once"), &GDNativeLibrary::set_load_once);
+	ClassDB::bind_method(D_METHOD("set_singleton", "singleton"), &GDNativeLibrary::set_singleton);
+	ClassDB::bind_method(D_METHOD("set_symbol_prefix", "symbol_prefix"), &GDNativeLibrary::set_symbol_prefix);
 
-	return library_paths[i];
-}
-
-String GDNativeLibrary::get_active_library_path() const {
-	if (GDNativeLibrary::current_platform != NUM_PLATFORMS) {
-		return library_paths[GDNativeLibrary::current_platform];
-	}
-	return "";
+	ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "load_once"), "set_load_once", "should_load_once");
+	ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "singleton"), "set_singleton", "is_singleton");
+	ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "symbol_prefix"), "set_symbol_prefix", "get_symbol_prefix");
 }
 
 GDNative::GDNative() {
 	native_handle = NULL;
+	initialized = false;
 }
 
 GDNative::~GDNative() {
 }
 
-extern "C" void _api_anchor();
-
-void GDNative::_compile_dummy_for_api() {
-	_api_anchor();
-}
-
 void GDNative::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_library", "library"), &GDNative::set_library);
 	ClassDB::bind_method(D_METHOD("get_library"), &GDNative::get_library);
@@ -220,8 +115,8 @@ bool GDNative::initialize() {
 		return false;
 	}
 
-	String lib_path = library->get_active_library_path();
-	if (lib_path.empty()) {
+	String lib_path = library->get_current_library_path();
+	if (lib_path.empty() && !library->is_current_library_statically_linked()) {
 		ERR_PRINT("No library set for this platform");
 		return false;
 	}
@@ -230,16 +125,34 @@ bool GDNative::initialize() {
 #else
 	String path = ProjectSettings::get_singleton()->globalize_path(lib_path);
 #endif
+
+	if (library->should_load_once()) {
+		if (GDNativeLibrary::loaded_libraries->has(lib_path)) {
+			// already loaded. Don't load again.
+			// copy some of the stuff instead
+			this->native_handle = (*GDNativeLibrary::loaded_libraries)[lib_path][0]->native_handle;
+			initialized = true;
+			return true;
+		}
+	}
+
 	Error err = OS::get_singleton()->open_dynamic_library(path, native_handle);
-	if (err != OK) {
+	if (err != OK && !library->is_current_library_statically_linked()) {
 		return false;
 	}
 
 	void *library_init;
-	err = get_symbol(init_symbol, library_init);
+
+	// we cheat here a little bit. you saw nothing
+	initialized = true;
+
+	err = get_symbol(library->get_symbol_prefix() + init_symbol, library_init);
+
+	initialized = false;
 
 	if (err || !library_init) {
-		OS::get_singleton()->close_dynamic_library(native_handle);
+		if (!library->is_current_library_statically_linked())
+			OS::get_singleton()->close_dynamic_library(native_handle);
 		native_handle = NULL;
 		ERR_PRINT("Failed to obtain godot_gdnative_init symbol");
 		return false;
@@ -260,18 +173,42 @@ bool GDNative::initialize() {
 
 	library_init_fpointer(&options);
 
+	initialized = true;
+
+	if (library->should_load_once() && !GDNativeLibrary::loaded_libraries->has(lib_path)) {
+		Vector<Ref<GDNative> > gdnatives;
+		gdnatives.resize(1);
+		gdnatives[0] = Ref<GDNative>(this);
+		GDNativeLibrary::loaded_libraries->insert(lib_path, gdnatives);
+	}
+
 	return true;
 }
 
 bool GDNative::terminate() {
 
-	if (native_handle == NULL) {
+	if (!initialized) {
 		ERR_PRINT("No valid library handle, can't terminate GDNative object");
 		return false;
 	}
 
+	if (library->should_load_once()) {
+		Vector<Ref<GDNative> > *gdnatives = &(*GDNativeLibrary::loaded_libraries)[library->get_current_library_path()];
+		if (gdnatives->size() > 1) {
+			// there are other GDNative's still using this library, so we actually don't terminte
+			gdnatives->erase(Ref<GDNative>(this));
+			initialized = false;
+			return true;
+		} else if (gdnatives->size() == 1) {
+			// we're the last one, terminate!
+			gdnatives->clear();
+			// wew this looks scary, but all it does is remove the entry completely
+			GDNativeLibrary::loaded_libraries->erase(GDNativeLibrary::loaded_libraries->find(library->get_current_library_path()));
+		}
+	}
+
 	void *library_terminate;
-	Error error = get_symbol(terminate_symbol, library_terminate);
+	Error error = get_symbol(library->get_symbol_prefix() + terminate_symbol, library_terminate);
 	if (error || !library_terminate) {
 		OS::get_singleton()->close_dynamic_library(native_handle);
 		native_handle = NULL;
@@ -281,13 +218,13 @@ bool GDNative::terminate() {
 	godot_gdnative_terminate_fn library_terminate_pointer;
 	library_terminate_pointer = (godot_gdnative_terminate_fn)library_terminate;
 
-	// TODO(karroffel): remove this? Should be part of NativeScript, not
-	// GDNative IMO
 	godot_gdnative_terminate_options options;
 	options.in_editor = Engine::get_singleton()->is_editor_hint();
 
 	library_terminate_pointer(&options);
 
+	initialized = false;
+
 	// GDNativeScriptLanguage::get_singleton()->initialized_libraries.erase(p_native_lib->path);
 
 	OS::get_singleton()->close_dynamic_library(native_handle);
@@ -297,7 +234,7 @@ bool GDNative::terminate() {
 }
 
 bool GDNative::is_initialized() {
-	return (native_handle != NULL);
+	return initialized;
 }
 
 void GDNativeCallRegistry::register_native_call_type(StringName p_call_type, native_call_cb p_callback) {
@@ -342,7 +279,7 @@ Variant GDNative::call_native(StringName p_native_call_type, StringName p_proced
 
 Error GDNative::get_symbol(StringName p_procedure_name, void *&r_handle) {
 
-	if (native_handle == NULL) {
+	if (!initialized) {
 		ERR_PRINT("No valid library handle, can't get symbol from GDNative object");
 		return ERR_CANT_OPEN;
 	}
@@ -355,3 +292,159 @@ Error GDNative::get_symbol(StringName p_procedure_name, void *&r_handle) {
 
 	return result;
 }
+
+RES GDNativeLibraryResourceLoader::load(const String &p_path, const String &p_original_path, Error *r_error) {
+	Ref<GDNativeLibrary> lib;
+	lib.instance();
+
+	Ref<ConfigFile> config = lib->get_config_file();
+
+	Error err = config->load(p_path);
+
+	if (r_error) {
+		*r_error = err;
+	}
+
+	lib->set_singleton(config->get_value("general", "singleton", false));
+	lib->set_load_once(config->get_value("general", "load_once", true));
+	lib->set_symbol_prefix(config->get_value("general", "symbol_prefix", default_symbol_prefix));
+
+	String entry_lib_path;
+	{
+
+		List<String> entry_keys;
+		config->get_section_keys("entry", &entry_keys);
+
+		for (List<String>::Element *E = entry_keys.front(); E; E = E->next()) {
+			String key = E->get();
+
+			Vector<String> tags = key.split(".");
+
+			bool skip = false;
+			for (int i = 0; i < tags.size(); i++) {
+				bool has_feature = OS::get_singleton()->has_feature(tags[i]);
+
+				if (!has_feature) {
+					skip = true;
+					break;
+				}
+			}
+
+			if (skip) {
+				continue;
+			}
+
+			entry_lib_path = config->get_value("entry", key);
+			break;
+		}
+	}
+
+	Vector<String> dependency_paths;
+	{
+
+		List<String> dependency_keys;
+		config->get_section_keys("dependencies", &dependency_keys);
+
+		for (List<String>::Element *E = dependency_keys.front(); E; E = E->next()) {
+			String key = E->get();
+
+			Vector<String> tags = key.split(".");
+
+			bool skip = false;
+			for (int i = 0; i < tags.size(); i++) {
+				bool has_feature = OS::get_singleton()->has_feature(tags[i]);
+
+				if (!has_feature) {
+					skip = true;
+					break;
+				}
+			}
+
+			if (skip) {
+				continue;
+			}
+
+			dependency_paths = config->get_value("dependencies", key);
+			break;
+		}
+	}
+
+	bool is_statically_linked = false;
+	{
+
+		List<String> static_linking_keys;
+		config->get_section_keys("static_linking", &static_linking_keys);
+
+		for (List<String>::Element *E = static_linking_keys.front(); E; E = E->next()) {
+			String key = E->get();
+
+			Vector<String> tags = key.split(".");
+
+			bool skip = false;
+
+			for (int i = 0; i < tags.size(); i++) {
+				bool has_feature = OS::get_singleton()->has_feature(tags[i]);
+
+				if (!has_feature) {
+					skip = true;
+					break;
+				}
+			}
+
+			if (skip) {
+				continue;
+			}
+
+			is_statically_linked = config->get_value("static_linking", key);
+			break;
+		}
+	}
+
+	lib->current_library_path = entry_lib_path;
+	lib->current_dependencies = dependency_paths;
+	lib->current_library_statically_linked = is_statically_linked;
+
+	return lib;
+}
+
+void GDNativeLibraryResourceLoader::get_recognized_extensions(List<String> *p_extensions) const {
+	p_extensions->push_back("gdnlib");
+}
+
+bool GDNativeLibraryResourceLoader::handles_type(const String &p_type) const {
+	return p_type == "GDNativeLibrary";
+}
+
+String GDNativeLibraryResourceLoader::get_resource_type(const String &p_path) const {
+	String el = p_path.get_extension().to_lower();
+	if (el == "gdnlib")
+		return "GDNativeLibrary";
+	return "";
+}
+
+Error GDNativeLibraryResourceSaver::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
+
+	Ref<GDNativeLibrary> lib = p_resource;
+
+	if (lib.is_null()) {
+		return ERR_INVALID_DATA;
+	}
+
+	Ref<ConfigFile> config = lib->get_config_file();
+
+	config->set_value("general", "singleton", lib->is_singleton());
+	config->set_value("general", "load_once", lib->should_load_once());
+	config->set_value("general", "symbol_prefix", lib->get_symbol_prefix());
+
+	return config->save(p_path);
+}
+
+bool GDNativeLibraryResourceSaver::recognize(const RES &p_resource) const {
+	return Object::cast_to<GDNativeLibrary>(*p_resource) != NULL;
+}
+
+void GDNativeLibraryResourceSaver::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
+	if (Object::cast_to<GDNativeLibrary>(*p_resource) != NULL) {
+		p_extensions->push_back("gdnlib");
+	}
+}

+ 64 - 47
modules/gdnative/gdnative.h

@@ -38,66 +38,69 @@
 #include "gdnative/gdnative.h"
 #include "gdnative_api_struct.gen.h"
 
-class GDNativeLibrary : public Resource {
-	GDCLASS(GDNativeLibrary, Resource)
-
-	enum Platform {
-		X11_32BIT,
-		X11_64BIT,
-		WINDOWS_32BIT,
-		WINDOWS_64BIT,
-		// NOTE(karroffel): I heard OSX 32 bit is dead, so 64 only
-		OSX,
-
-		// Android .so files must be located in directories corresponding to Android ABI names:
-		// https://developer.android.com/ndk/guides/abis.html
-		// Android runtime will select the matching library depending on the device.
-		// The value here must simply point to the .so name, for example:
-		// "res://libmy_gdnative.so" or "libmy_gdnative.so",
-		// while in the project the actual paths can be "lib/android/armeabi-v7a/libmy_gdnative.so",
-		// "lib/android/arm64-v8a/libmy_gdnative.so".
-		ANDROID,
-
-		IOS_32BIT,
-		IOS_64BIT,
-
-		// TODO(karroffel): figure out how to deal with web stuff at all...
-		WASM,
-
-		// TODO(karroffel): does UWP have different libs??
-		// UWP,
+#include "io/config_file.h"
 
-		NUM_PLATFORMS
+class GDNativeLibraryResourceLoader;
+class GDNative;
 
-	};
+class GDNativeLibrary : public Resource {
+	GDCLASS(GDNativeLibrary, Resource)
 
-	static String platform_names[NUM_PLATFORMS + 1];
-	static String platform_lib_ext[NUM_PLATFORMS + 1];
+	static Map<String, Vector<Ref<GDNative> > > *loaded_libraries;
 
-	static Platform current_platform;
+	friend class GDNativeLibraryResourceLoader;
+	friend class GDNative;
 
-	String library_paths[NUM_PLATFORMS];
+	Ref<ConfigFile> config_file;
 
-	bool singleton_gdnative;
+	String current_library_path;
+	Vector<String> current_dependencies;
+	bool current_library_statically_linked;
 
-protected:
-	bool _set(const StringName &p_name, const Variant &p_value);
-	bool _get(const StringName &p_name, Variant &r_ret) const;
-	void _get_property_list(List<PropertyInfo> *p_list) const;
+	bool singleton;
+	bool load_once;
+	String symbol_prefix;
 
 public:
 	GDNativeLibrary();
 	~GDNativeLibrary();
 
-	static void _bind_methods();
+	_FORCE_INLINE_ Ref<ConfigFile> get_config_file() { return config_file; }
+
+	// things that change per-platform
+	// so there are no setters for this
+	_FORCE_INLINE_ String get_current_library_path() const {
+		return current_library_path;
+	}
+	_FORCE_INLINE_ Vector<String> get_current_dependencies() const {
+		return current_dependencies;
+	}
+	_FORCE_INLINE_ bool is_current_library_statically_linked() const {
+		return current_library_statically_linked;
+	}
 
-	void set_library_path(StringName p_platform, String p_path);
-	String get_library_path(StringName p_platform) const;
+	// things that are a property of the library itself, not platform specific
+	_FORCE_INLINE_ bool should_load_once() const {
+		return load_once;
+	}
+	_FORCE_INLINE_ bool is_singleton() const {
+		return singleton;
+	}
+	_FORCE_INLINE_ String get_symbol_prefix() const {
+		return symbol_prefix;
+	}
 
-	String get_active_library_path() const;
+	_FORCE_INLINE_ void set_load_once(bool p_load_once) {
+		load_once = p_load_once;
+	}
+	_FORCE_INLINE_ void set_singleton(bool p_singleton) {
+		singleton = p_singleton;
+	}
+	_FORCE_INLINE_ void set_symbol_prefix(String p_symbol_prefix) {
+		symbol_prefix = p_symbol_prefix;
+	}
 
-	_FORCE_INLINE_ bool is_singleton_gdnative() const { return singleton_gdnative; }
-	_FORCE_INLINE_ void set_singleton_gdnative(bool p_singleton) { singleton_gdnative = p_singleton; }
+	static void _bind_methods();
 };
 
 typedef godot_variant (*native_call_cb)(void *, godot_array *);
@@ -124,10 +127,9 @@ class GDNative : public Reference {
 
 	Ref<GDNativeLibrary> library;
 
-	// TODO(karroffel): different platforms? WASM????
 	void *native_handle;
 
-	void _compile_dummy_for_api();
+	bool initialized;
 
 public:
 	GDNative();
@@ -148,4 +150,19 @@ public:
 	Error get_symbol(StringName p_procedure_name, void *&r_handle);
 };
 
+class GDNativeLibraryResourceLoader : public ResourceFormatLoader {
+public:
+	virtual RES load(const String &p_path, const String &p_original_path, Error *r_error);
+	virtual void get_recognized_extensions(List<String> *p_extensions) const;
+	virtual bool handles_type(const String &p_type) const;
+	virtual String get_resource_type(const String &p_path) const;
+};
+
+class GDNativeLibraryResourceSaver : public ResourceFormatSaver {
+public:
+	virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags);
+	virtual bool recognize(const RES &p_resource) const;
+	virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const;
+};
+
 #endif // GDNATIVE_H

+ 0 - 3
modules/gdnative/gdnative/array.cpp

@@ -41,9 +41,6 @@
 extern "C" {
 #endif
 
-void _array_api_anchor() {
-}
-
 void GDAPI godot_array_new(godot_array *r_dest) {
 	Array *dest = (Array *)r_dest;
 	memnew_placement(dest, Array);

+ 0 - 2
modules/gdnative/gdnative/basis.cpp

@@ -36,8 +36,6 @@
 extern "C" {
 #endif
 
-void _basis_api_anchor() {}
-
 void GDAPI godot_basis_new_with_rows(godot_basis *r_dest, const godot_vector3 *p_x_axis, const godot_vector3 *p_y_axis, const godot_vector3 *p_z_axis) {
 	const Vector3 *x_axis = (const Vector3 *)p_x_axis;
 	const Vector3 *y_axis = (const Vector3 *)p_y_axis;

+ 0 - 2
modules/gdnative/gdnative/color.cpp

@@ -36,8 +36,6 @@
 extern "C" {
 #endif
 
-void _color_api_anchor() {}
-
 void GDAPI godot_color_new_rgba(godot_color *r_dest, const godot_real p_r, const godot_real p_g, const godot_real p_b, const godot_real p_a) {
 
 	Color *dest = (Color *)r_dest;

+ 0 - 2
modules/gdnative/gdnative/dictionary.cpp

@@ -38,8 +38,6 @@
 extern "C" {
 #endif
 
-void _dictionary_api_anchor() {}
-
 void GDAPI godot_dictionary_new(godot_dictionary *r_dest) {
 	Dictionary *dest = (Dictionary *)r_dest;
 	memnew_placement(dest, Dictionary);

+ 0 - 49
modules/gdnative/gdnative/gdnative.cpp

@@ -40,47 +40,6 @@
 extern "C" {
 #endif
 
-extern "C" void _string_api_anchor();
-extern "C" void _string_name_api_anchor();
-extern "C" void _vector2_api_anchor();
-extern "C" void _rect2_api_anchor();
-extern "C" void _vector3_api_anchor();
-extern "C" void _transform2d_api_anchor();
-extern "C" void _plane_api_anchor();
-extern "C" void _quat_api_anchor();
-extern "C" void _basis_api_anchor();
-extern "C" void _rect3_api_anchor();
-extern "C" void _transform_api_anchor();
-extern "C" void _color_api_anchor();
-extern "C" void _node_path_api_anchor();
-extern "C" void _rid_api_anchor();
-extern "C" void _dictionary_api_anchor();
-extern "C" void _array_api_anchor();
-extern "C" void _pool_arrays_api_anchor();
-extern "C" void _variant_api_anchor();
-
-void _api_anchor() {
-
-	_string_api_anchor();
-	_string_name_api_anchor();
-	_vector2_api_anchor();
-	_rect2_api_anchor();
-	_vector3_api_anchor();
-	_transform2d_api_anchor();
-	_plane_api_anchor();
-	_quat_api_anchor();
-	_rect3_api_anchor();
-	_basis_api_anchor();
-	_transform_api_anchor();
-	_color_api_anchor();
-	_node_path_api_anchor();
-	_rid_api_anchor();
-	_dictionary_api_anchor();
-	_array_api_anchor();
-	_pool_arrays_api_anchor();
-	_variant_api_anchor();
-}
-
 void GDAPI godot_object_destroy(godot_object *p_o) {
 	memdelete((Object *)p_o);
 }
@@ -133,14 +92,6 @@ godot_variant GDAPI godot_method_bind_call(godot_method_bind *p_method_bind, god
 	return ret;
 }
 
-// @Todo
-/*
-void GDAPI godot_method_bind_varcall(godot_method_bind *p_method_bind)
-{
-
-}
-*/
-
 godot_class_constructor GDAPI godot_get_class_constructor(const char *p_classname) {
 	ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(StringName(p_classname));
 	if (class_info)

+ 0 - 2
modules/gdnative/gdnative/node_path.cpp

@@ -36,8 +36,6 @@
 extern "C" {
 #endif
 
-void _node_path_api_anchor() {}
-
 void GDAPI godot_node_path_new(godot_node_path *r_dest, const godot_string *p_from) {
 	NodePath *dest = (NodePath *)r_dest;
 	const String *from = (const String *)p_from;

+ 0 - 2
modules/gdnative/gdnative/plane.cpp

@@ -36,8 +36,6 @@
 extern "C" {
 #endif
 
-void _plane_api_anchor() {}
-
 void GDAPI godot_plane_new_with_reals(godot_plane *r_dest, const godot_real p_a, const godot_real p_b, const godot_real p_c, const godot_real p_d) {
 
 	Plane *dest = (Plane *)r_dest;

+ 0 - 3
modules/gdnative/gdnative/pool_arrays.cpp

@@ -41,9 +41,6 @@
 extern "C" {
 #endif
 
-void _pool_arrays_api_anchor() {
-}
-
 #define memnew_placement_custom(m_placement, m_class, m_constr) _post_initialize(new (m_placement, sizeof(m_class), "") m_constr)
 
 // byte

+ 0 - 2
modules/gdnative/gdnative/quat.cpp

@@ -36,8 +36,6 @@
 extern "C" {
 #endif
 
-void _quat_api_anchor() {}
-
 void GDAPI godot_quat_new(godot_quat *r_dest, const godot_real p_x, const godot_real p_y, const godot_real p_z, const godot_real p_w) {
 
 	Quat *dest = (Quat *)r_dest;

+ 0 - 2
modules/gdnative/gdnative/rect2.cpp

@@ -36,8 +36,6 @@
 extern "C" {
 #endif
 
-void _rect2_api_anchor() {}
-
 void GDAPI godot_rect2_new_with_position_and_size(godot_rect2 *r_dest, const godot_vector2 *p_pos, const godot_vector2 *p_size) {
 	const Vector2 *position = (const Vector2 *)p_pos;
 	const Vector2 *size = (const Vector2 *)p_size;

+ 0 - 2
modules/gdnative/gdnative/rect3.cpp

@@ -36,8 +36,6 @@
 extern "C" {
 #endif
 
-void _rect3_api_anchor() {}
-
 void GDAPI godot_rect3_new(godot_rect3 *r_dest, const godot_vector3 *p_pos, const godot_vector3 *p_size) {
 	const Vector3 *pos = (const Vector3 *)p_pos;
 	const Vector3 *size = (const Vector3 *)p_size;

+ 0 - 2
modules/gdnative/gdnative/rid.cpp

@@ -37,8 +37,6 @@
 extern "C" {
 #endif
 
-void _rid_api_anchor() {}
-
 void GDAPI godot_rid_new(godot_rid *r_dest) {
 	RID *dest = (RID *)r_dest;
 	memnew_placement(dest, RID);

+ 0 - 3
modules/gdnative/gdnative/string.cpp

@@ -39,9 +39,6 @@
 extern "C" {
 #endif
 
-void _string_api_anchor() {
-}
-
 void GDAPI godot_string_new(godot_string *r_dest) {
 	String *dest = (String *)r_dest;
 	memnew_placement(dest, String);

+ 0 - 3
modules/gdnative/gdnative/string_name.cpp

@@ -38,9 +38,6 @@
 extern "C" {
 #endif
 
-void _string_name_api_anchor() {
-}
-
 void GDAPI godot_string_name_new(godot_string_name *r_dest, const godot_string *p_name) {
 	StringName *dest = (StringName *)r_dest;
 	const String *name = (const String *)p_name;

+ 0 - 2
modules/gdnative/gdnative/transform.cpp

@@ -36,8 +36,6 @@
 extern "C" {
 #endif
 
-void _transform_api_anchor() {}
-
 void GDAPI godot_transform_new_with_axis_origin(godot_transform *r_dest, const godot_vector3 *p_x_axis, const godot_vector3 *p_y_axis, const godot_vector3 *p_z_axis, const godot_vector3 *p_origin) {
 	const Vector3 *x_axis = (const Vector3 *)p_x_axis;
 	const Vector3 *y_axis = (const Vector3 *)p_y_axis;

+ 0 - 2
modules/gdnative/gdnative/transform2d.cpp

@@ -36,8 +36,6 @@
 extern "C" {
 #endif
 
-void _transform2d_api_anchor() {}
-
 void GDAPI godot_transform2d_new(godot_transform2d *r_dest, const godot_real p_rot, const godot_vector2 *p_pos) {
 	const Vector2 *pos = (const Vector2 *)p_pos;
 	Transform2D *dest = (Transform2D *)r_dest;

+ 0 - 2
modules/gdnative/gdnative/variant.cpp

@@ -36,8 +36,6 @@
 extern "C" {
 #endif
 
-void _variant_api_anchor() {}
-
 #define memnew_placement_custom(m_placement, m_class, m_constr) _post_initialize(new (m_placement, sizeof(m_class), "") m_constr)
 
 // Constructors

+ 0 - 2
modules/gdnative/gdnative/vector2.cpp

@@ -36,8 +36,6 @@
 extern "C" {
 #endif
 
-void _vector2_api_anchor() {}
-
 void GDAPI godot_vector2_new(godot_vector2 *r_dest, const godot_real p_x, const godot_real p_y) {
 
 	Vector2 *dest = (Vector2 *)r_dest;

+ 0 - 2
modules/gdnative/gdnative/vector3.cpp

@@ -36,8 +36,6 @@
 extern "C" {
 #endif
 
-void _vector3_api_anchor() {}
-
 void GDAPI godot_vector3_new(godot_vector3 *r_dest, const godot_real p_x, const godot_real p_y, const godot_real p_z) {
 
 	Vector3 *dest = (Vector3 *)r_dest;

+ 1 - 1
modules/gdnative/include/gdnative/gdnative.h

@@ -53,7 +53,7 @@ extern "C" {
 
 // This is for libraries *using* the header, NOT GODOT EXPOSING STUFF!!
 #ifdef _WIN32
-#define GDN_EXPORT __declspec(dllexport)
+#define GDN_EXPORT
 #else
 #define GDN_EXPORT
 #endif

+ 24 - 22
modules/gdnative/nativescript/nativescript.cpp

@@ -40,6 +40,8 @@
 #include "scene/main/scene_tree.h"
 #include "scene/resources/scene_format_text.h"
 
+#include <stdlib.h>
+
 #ifndef NO_THREADS
 #include "os/thread.h"
 #endif
@@ -52,7 +54,11 @@
 #include "editor/editor_node.h"
 #endif
 
-////// Script stuff
+//
+//
+// Script stuff
+//
+//
 
 void NativeScript::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_class_name", "class_name"), &NativeScript::set_class_name);
@@ -108,7 +114,7 @@ void NativeScript::set_library(Ref<GDNativeLibrary> p_library) {
 		return;
 	}
 	library = p_library;
-	lib_path = library->get_active_library_path();
+	lib_path = library->get_current_library_path();
 
 #ifndef NO_THREADS
 	if (Thread::get_caller_id() != Thread::get_main_id()) {
@@ -414,7 +420,6 @@ Variant NativeScript::_new(const Variant **p_args, int p_argcount, Variant::Call
 	}
 }
 
-// TODO(karroffel): implement this
 NativeScript::NativeScript() {
 	library = Ref<GDNative>();
 	lib_path = "";
@@ -424,7 +429,6 @@ NativeScript::NativeScript() {
 #endif
 }
 
-// TODO(karroffel): implement this
 NativeScript::~NativeScript() {
 	NSL->unregister_script(this);
 
@@ -433,7 +437,11 @@ NativeScript::~NativeScript() {
 #endif
 }
 
-////// ScriptInstance stuff
+//
+//
+// ScriptInstance stuff
+//
+//
 
 #define GET_SCRIPT_DESC() script->get_script_desc()
 
@@ -691,7 +699,6 @@ NativeScriptInstance::RPCMode NativeScriptInstance::get_rpc_mode(const StringNam
 	return RPC_MODE_DISABLED;
 }
 
-// TODO(karroffel): implement this
 NativeScriptInstance::RPCMode NativeScriptInstance::get_rset_mode(const StringName &p_variable) const {
 
 	NativeScriptDesc *script_data = GET_SCRIPT_DESC();
@@ -774,15 +781,14 @@ NativeScriptInstance::~NativeScriptInstance() {
 	}
 }
 
-////// ScriptingLanguage stuff
+//
+//
+// ScriptingLanguage stuff
+//
+//
 
 NativeScriptLanguage *NativeScriptLanguage::singleton;
 
-extern "C" void _native_script_hook();
-void NativeScriptLanguage::_hacky_api_anchor() {
-	_native_script_hook();
-}
-
 void NativeScriptLanguage::_unload_stuff() {
 	for (Map<String, Map<StringName, NativeScriptDesc> >::Element *L = library_classes.front(); L; L = L->next()) {
 		for (Map<StringName, NativeScriptDesc>::Element *C = L->get().front(); C; C = C->next()) {
@@ -819,9 +825,7 @@ NativeScriptLanguage::NativeScriptLanguage() {
 #endif
 }
 
-// TODO(karroffel): implement this
 NativeScriptLanguage::~NativeScriptLanguage() {
-	// _unload_stuff(); // NOTE(karroffel): This gets called in ::finish()
 
 	for (Map<String, Ref<GDNative> >::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) {
 
@@ -847,7 +851,6 @@ void _add_reload_node() {
 #endif
 }
 
-// TODO(karroffel): implement this
 void NativeScriptLanguage::init() {
 
 #if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED)
@@ -860,6 +863,7 @@ void NativeScriptLanguage::init() {
 		if (generate_c_api(E->next()->get()) != OK) {
 			ERR_PRINT("Failed to generate C API\n");
 		}
+		exit(0);
 	}
 #endif
 
@@ -886,11 +890,9 @@ void NativeScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) co
 void NativeScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const {
 }
 
-// TODO(karroffel): implement this
 Ref<Script> NativeScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const {
 	NativeScript *s = memnew(NativeScript);
 	s->set_class_name(p_class_name);
-	// TODO(karroffel): use p_base_class_name
 	return Ref<NativeScript>(s);
 }
 bool NativeScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const {
@@ -988,7 +990,7 @@ void NativeScriptLanguage::init_library(const Ref<GDNativeLibrary> &lib) {
 	MutexLock lock(mutex);
 #endif
 	// See if this library was "registered" already.
-	const String &lib_path = lib->get_active_library_path();
+	const String &lib_path = lib->get_current_library_path();
 	ERR_EXPLAIN(lib->get_name() + " does not have a library for the current platform");
 	ERR_FAIL_COND(lib_path.length() == 0);
 	Map<String, Ref<GDNative> >::Element *E = library_gdnatives.find(lib_path);
@@ -998,7 +1000,7 @@ void NativeScriptLanguage::init_library(const Ref<GDNativeLibrary> &lib) {
 		gdn.instance();
 		gdn->set_library(lib);
 
-		// TODO(karroffel): check the return value?
+		// TODO check the return value?
 		gdn->initialize();
 
 		library_gdnatives.insert(lib_path, gdn);
@@ -1010,7 +1012,7 @@ void NativeScriptLanguage::init_library(const Ref<GDNativeLibrary> &lib) {
 
 		void *proc_ptr;
 
-		Error err = gdn->get_symbol(_init_call_name, proc_ptr);
+		Error err = gdn->get_symbol(lib->get_symbol_prefix() + _init_call_name, proc_ptr);
 
 		if (err != OK) {
 			ERR_PRINT(String("No " + _init_call_name + " in \"" + lib_path + "\" found").utf8().get_data());
@@ -1051,7 +1053,7 @@ void NativeScriptLanguage::call_libraries_cb(const StringName &name) {
 		if (L->get()->is_initialized()) {
 
 			void *proc_ptr;
-			Error err = L->get()->get_symbol(name, proc_ptr);
+			Error err = L->get()->get_symbol(L->get()->get_library()->get_symbol_prefix() + name, proc_ptr);
 
 			if (!err) {
 				((void (*)())proc_ptr)();
@@ -1140,7 +1142,7 @@ void NativeReloadNode::_notification(int p_what) {
 				// here the library registers all the classes and stuff.
 
 				void *proc_ptr;
-				Error err = L->get()->get_symbol("godot_nativescript_init", proc_ptr);
+				Error err = L->get()->get_symbol(L->get()->get_library()->get_symbol_prefix() + "nativescript_init", proc_ptr);
 				if (err != OK) {
 					ERR_PRINT(String("No godot_nativescript_init in \"" + L->key() + "\" found").utf8().get_data());
 				} else {

+ 4 - 4
modules/gdnative/nativescript/nativescript.h

@@ -229,15 +229,15 @@ public:
 	Map<String, Set<NativeScript *> > library_script_users;
 
 	const StringName _init_call_type = "nativescript_init";
-	const StringName _init_call_name = "godot_nativescript_init";
+	const StringName _init_call_name = "nativescript_init";
 
 	const StringName _noarg_call_type = "nativescript_no_arg";
 
-	const StringName _frame_call_name = "godot_nativescript_frame";
+	const StringName _frame_call_name = "nativescript_frame";
 
 #ifndef NO_THREADS
-	const StringName _thread_enter_call_name = "godot_nativescript_thread_enter";
-	const StringName _thread_exit_call_name = "godot_nativescript_thread_exit";
+	const StringName _thread_enter_call_name = "nativescript_thread_enter";
+	const StringName _thread_exit_call_name = "nativescript_thread_exit";
 #endif
 
 	NativeScriptLanguage();

+ 15 - 3
modules/gdnative/register_types.cpp

@@ -81,7 +81,7 @@ Set<String> get_gdnative_singletons(EditorFileSystemDirectory *p_dir) {
 		}
 
 		Ref<GDNativeLibrary> lib = ResourceLoader::load(p_dir->get_file_path(i));
-		if (lib.is_valid() && lib->is_singleton_gdnative()) {
+		if (lib.is_valid() && lib->is_singleton()) {
 			file_paths.insert(p_dir->get_file_path(i));
 		}
 	}
@@ -141,6 +141,9 @@ GDNativeCallRegistry *GDNativeCallRegistry::singleton;
 
 Vector<Ref<GDNative> > singleton_gdnatives;
 
+GDNativeLibraryResourceLoader *resource_loader_gdnlib = NULL;
+GDNativeLibraryResourceSaver *resource_saver_gdnlib = NULL;
+
 void register_gdnative_types() {
 
 #ifdef TOOLS_ENABLED
@@ -153,6 +156,12 @@ void register_gdnative_types() {
 	ClassDB::register_class<GDNativeLibrary>();
 	ClassDB::register_class<GDNative>();
 
+	resource_loader_gdnlib = memnew(GDNativeLibraryResourceLoader);
+	resource_saver_gdnlib = memnew(GDNativeLibraryResourceSaver);
+
+	ResourceLoader::add_resource_format_loader(resource_loader_gdnlib);
+	ResourceSaver::add_resource_format_saver(resource_saver_gdnlib);
+
 	GDNativeCallRegistry::singleton = memnew(GDNativeCallRegistry);
 
 	GDNativeCallRegistry::singleton->register_native_call_type("standard_varcall", cb_standard_varcall);
@@ -185,11 +194,11 @@ void register_gdnative_types() {
 
 		void *proc_ptr;
 		Error err = singleton_gdnatives[i]->get_symbol(
-				"godot_gdnative_singleton",
+				lib->get_symbol_prefix() + "gdnative_singleton",
 				proc_ptr);
 
 		if (err != OK) {
-			ERR_PRINT((String("No godot_gdnative_singleton in \"" + singleton_gdnatives[i]->get_library()->get_active_library_path()) + "\" found").utf8().get_data());
+			ERR_PRINT((String("No godot_gdnative_singleton in \"" + singleton_gdnatives[i]->get_library()->get_current_library_path()) + "\" found").utf8().get_data());
 		} else {
 			((void (*)())proc_ptr)();
 		}
@@ -224,6 +233,9 @@ void unregister_gdnative_types() {
 	}
 #endif
 
+	memdelete(resource_loader_gdnlib);
+	memdelete(resource_saver_gdnlib);
+
 	// This is for printing out the sizes of the core types
 
 	/*