ソースを参照

Merge pull request #104129 from dsnopek/gdextension-get-used-classes

GDExtension: Add mechanism to get which classes an extension is using
Thaddeus Crews 5 ヶ月 前
コミット
1b631edf67

+ 16 - 0
core/extension/gdextension.cpp

@@ -679,6 +679,13 @@ void GDExtension::_get_library_path(GDExtensionClassLibraryPtr p_library, GDExte
 	memnew_placement(r_path, String(library_path));
 }
 
+void GDExtension::_register_get_classes_used_callback(GDExtensionClassLibraryPtr p_library, GDExtensionEditorGetClassesUsedCallback p_callback) {
+#ifdef TOOLS_ENABLED
+	GDExtension *self = reinterpret_cast<GDExtension *>(p_library);
+	self->get_classes_used_callback = p_callback;
+#endif
+}
+
 HashMap<StringName, GDExtensionInterfaceFunctionPtr> GDExtension::gdextension_interface_functions;
 
 void GDExtension::register_interface_function(const StringName &p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer) {
@@ -799,6 +806,7 @@ void GDExtension::initialize_gdextensions() {
 	register_interface_function("classdb_register_extension_class_signal", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_signal);
 	register_interface_function("classdb_unregister_extension_class", (GDExtensionInterfaceFunctionPtr)&GDExtension::_unregister_extension_class);
 	register_interface_function("get_library_path", (GDExtensionInterfaceFunctionPtr)&GDExtension::_get_library_path);
+	register_interface_function("editor_register_get_classes_used_callback", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_get_classes_used_callback);
 }
 
 void GDExtension::finalize_gdextensions() {
@@ -1034,6 +1042,14 @@ void GDExtension::_untrack_instance(void *p_user_data, void *p_instance) {
 	extension->instances.erase(obj->get_instance_id());
 }
 
+PackedStringArray GDExtension::get_classes_used() const {
+	PackedStringArray ret;
+	if (get_classes_used_callback) {
+		get_classes_used_callback((GDExtensionTypePtr)&ret);
+	}
+	return ret;
+}
+
 Vector<StringName> GDExtensionEditorPlugins::extension_classes;
 GDExtensionEditorPlugins::EditorPluginRegisterFunc GDExtensionEditorPlugins::editor_node_add_plugin = nullptr;
 GDExtensionEditorPlugins::EditorPluginRegisterFunc GDExtensionEditorPlugins::editor_node_remove_plugin = nullptr;

+ 4 - 0
core/extension/gdextension.h

@@ -93,6 +93,7 @@ class GDExtension : public Resource {
 	static void _register_extension_class_signal(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_signal_name, const GDExtensionPropertyInfo *p_argument_info, GDExtensionInt p_argument_count);
 	static void _unregister_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name);
 	static void _get_library_path(GDExtensionClassLibraryPtr p_library, GDExtensionStringPtr r_path);
+	static void _register_get_classes_used_callback(GDExtensionClassLibraryPtr p_library, GDExtensionEditorGetClassesUsedCallback p_callback);
 
 	GDExtensionInitialization initialization;
 	int32_t level_initialized = -1;
@@ -101,6 +102,7 @@ class GDExtension : public Resource {
 	bool is_reloading = false;
 	Vector<GDExtensionMethodBind *> invalid_methods;
 	Vector<ObjectID> instance_bindings;
+	GDExtensionEditorGetClassesUsedCallback get_classes_used_callback = nullptr;
 
 	static void _track_instance(void *p_user_data, void *p_instance);
 	static void _untrack_instance(void *p_user_data, void *p_instance);
@@ -155,6 +157,8 @@ public:
 
 	void track_instance_binding(Object *p_object);
 	void untrack_instance_binding(Object *p_object);
+
+	PackedStringArray get_classes_used() const;
 #endif
 
 	InitializationLevel get_minimum_library_initialization_level() const;

+ 19 - 0
core/extension/gdextension_interface.h

@@ -400,6 +400,9 @@ typedef struct {
 
 typedef void *GDExtensionClassLibraryPtr;
 
+/* Passed a pointer to a PackedStringArray that should be filled with the classes that may be used by the GDExtension. */
+typedef void (*GDExtensionEditorGetClassesUsedCallback)(GDExtensionTypePtr p_packed_string_array);
+
 /* Method */
 
 typedef enum {
@@ -3111,6 +3114,22 @@ typedef void (*GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars)(const char *
  */
 typedef void (*GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen)(const char *p_data, GDExtensionInt p_size);
 
+/**
+ * @name editor_register_get_classes_used_callback
+ * @since 4.5
+ *
+ * Registers a callback that Godot can call to get the list of all classes (from ClassDB) that may be used by the calling GDExtension.
+ *
+ * This is used by the editor to generate a build profile (in "Tools" > "Engine Compilation Configuration Editor..." > "Detect from project"),
+ * in order to recompile Godot with only the classes used.
+ * In the provided callback, the GDExtension should provide the list of classes that _may_ be used statically, thus the time of invocation shouldn't matter.
+ * If a GDExtension doesn't register a callback, Godot will assume that it could be using any classes.
+ *
+ * @param p_library A pointer the library received by the GDExtension's entry point function.
+ * @param p_callback The callback to retrieve the list of classes used.
+ */
+typedef void (*GDExtensionInterfaceEditorRegisterGetClassesUsedCallback)(GDExtensionClassLibraryPtr p_library, GDExtensionEditorGetClassesUsedCallback p_callback);
+
 #ifdef __cplusplus
 }
 #endif