From c90d7c5408a803b6aa3a41abe4710148c8fe70f7 Mon Sep 17 00:00:00 2001 From: Emmanuel Leblond Date: Sun, 4 Jun 2023 16:29:15 +0200 Subject: [PATCH] Support new GDExtensionInterfaceGetProcAddress based GDExtension interface --- .github/workflows/build.yml | 121 +++++++++++-- meson.build | 7 + misc/release_pythonscript.gdextension | 1 + scripts/extension_api_parser/classes.py | 3 + scripts/symlink.py | 43 +++++ src/godot/classes_pyx/class.pyx.j2 | 61 ++++++- src/godot/hazmat/gdnative_ptrs.pxd.j2 | 152 +++++++++++++++- src/godot/hazmat/gdnative_ptrs.pyx.j2 | 146 +++++++++++++++ src/godot/hazmat/meson.build | 4 + src/pythonscript.c | 170 ++++++++++++++---- tests/1-gdextension/my.c | 2 +- tests/1-gdextension/my.gdextension | 1 + .../pythonscript.gdextension | 1 + .../pythonscript.gdextension | 1 + tests/run.py | 4 +- 15 files changed, 659 insertions(+), 58 deletions(-) create mode 100644 scripts/symlink.py diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b6934b70..3eacc9a2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,9 +10,16 @@ on: - godot4-meson +# Cancel run if another commit is pushed on the branch +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + + # Global Settings env: PYTHON_VERSION: "3.8" # Python to run the build, no the one shipped ! + BLEEDING_EDGE_GODOT: true jobs: @@ -50,14 +57,17 @@ jobs: LD: lld PLATFORM: linux-x86_64 steps: + - name: 'Checkout' uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 with: submodules: true + - name: 'Set up Python' uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435 # pin@v4.5.0 with: python-version: ${{ env.PYTHON_VERSION }} + - name: 'Setup venv' run: | set -eux @@ -65,19 +75,61 @@ jobs: python --version pip install -U pip pip install -r requirements.in + + - name: Download bleeding edge Godot 🏗️ + uses: dsnopek/action-download-artifact@1322f74e2dac9feed2ee76a32d9ae1ca3b4cf4e9 + if: ${{ env.BLEEDING_EDGE_GODOT }} + with: + repo: godotengine/godot + branch: master + event: push + workflow: linux_builds.yml + workflow_conclusion: success + name: linux-editor-mono + search_artifacts: true + check_artifacts: true + ensure_latest: true + path: godot-artifacts + + - name: 'Setup bleeding edge Godot 🏗️' + id: setup-godot + if: ${{ env.BLEEDING_EDGE_GODOT }} + run: | + set -eux + + GODOT_BIN=./godot-artifacts/godot.linuxbsd.editor.x86_64.mono + GDEXTENSION_DIR=./gdextension_api + ls godot-artifacts + + chmod +x $GODOT_BIN + $GODOT_BIN --headless --version + + mkdir $GDEXTENSION_DIR && pushd $GDEXTENSION_DIR + $GODOT_BIN --headless --dump-extension-api + mkdir godot && pushd godot + $GODOT_BIN --headless --dump-gdextension-interface + popd && popd + + echo "EXTRA_MESON_SETUP_ARGS='-D gdextension_path=$GDEXTENSION_DIR'" >> $GITHUB_OUTPUT + echo "EXTRA_RUN_TESTS_ARGS='--godot-binary=$GODOT_BIN'" >> $GITHUB_OUTPUT + - name: 'Setup project' - run: python .github/scripts/meson_setup_or_dump_log.py build/ + run: python .github/scripts/meson_setup_or_dump_log.py build/ ${{ steps.setup-godot.outputs.EXTRA_MESON_SETUP_ARGS }} + - name: 'Build project' run: meson compile -C build/ - name: 'Run tests' run: | set -eux - python tests/run.py 0-gdscript --build-dir build/ -- --headless - python tests/run.py 1-gdextension --build-dir build/ -- --headless - python tests/run.py 2-pythonscript-init --build-dir build/ -- --headless - python tests/run.py 3-pythonscript-cython-only --build-dir build/ -- --headless + ARGS=--build-dir=build/ ${{ steps.setup-godot.outputs.EXTRA_RUN_TESTS_ARGS }} -- --headless + python tests/run.py 0-gdscript $ARGS + python tests/run.py 1-gdextension $ARGS + python tests/run.py 2-pythonscript-init $ARGS + python tests/run.py 3-pythonscript-cython-only $ARGS + # - name: 'Generate artifact archive' # run: meson compile -C build/ release + # - name: 'Export release artifact' # uses: actions/upload-artifact@11830c9f4d30053679cb8904e3b3ce1b8c00bf40 # pin@v2 # with: @@ -94,16 +146,20 @@ jobs: env: PLATFORM: 'windows-x86_64' steps: + - name: 'Checkout' uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 with: submodules: true + - name: 'Set up MSVC' uses: egor-tensin/vs-shell@9a932a62d05192eae18ca370155cf877eecc2202 # pin@v2.1 + - name: 'Set up Python' uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435 # pin@v4.5.0 with: python-version: ${{ env.PYTHON_VERSION }} + - name: 'Setup venv' shell: bash run: | @@ -111,18 +167,60 @@ jobs: python --version pip install -U pip pip install -r requirements.in + + - name: Download bleeding edge Godot 🏗️ + uses: dsnopek/action-download-artifact@1322f74e2dac9feed2ee76a32d9ae1ca3b4cf4e9 + if: ${{ env.BLEEDING_EDGE_GODOT }} + with: + repo: godotengine/godot + branch: master + event: push + workflow: windows_builds.yml + workflow_conclusion: success + name: windows-editor + search_artifacts: true + check_artifacts: true + ensure_latest: true + path: godot-artifacts + + - name: 'Setup bleeding edge Godot 🏗️' + id: setup-godot + if: ${{ env.BLEEDING_EDGE_GODOT }} + run: | + set -eux + + GODOT_BIN=./godot-artifacts/godot.windows.editor.x86_64.mono + GDEXTENSION_DIR=./gdextension_api + ls godot-artifacts + + chmod +x $GODOT_BIN + $GODOT_BIN --headless --version + + mkdir $GDEXTENSION_DIR && pushd $GDEXTENSION_DIR + $GODOT_BIN --headless --dump-extension-api + mkdir godot && pushd godot + $GODOT_BIN --headless --dump-gdextension-interface + popd && popd + + echo "EXTRA_MESON_SETUP_ARGS='-D gdextension_path=$GDEXTENSION_DIR'" >> $GITHUB_OUTPUT + echo "EXTRA_RUN_TESTS_ARGS='--godot-binary=$GODOT_BIN'" >> $GITHUB_OUTPUT + - name: 'Setup project' - run: python .github/scripts/meson_setup_or_dump_log.py build/ + run: python .github/scripts/meson_setup_or_dump_log.py build/ ${{ steps.setup-godot.outputs.EXTRA_MESON_SETUP_ARGS }} + - name: 'Build project' run: meson compile -C build/ + - name: 'Run tests' shell: bash run: | set -eux - python tests/run.py 0-gdscript --build-dir build/ -- --headless - python tests/run.py 1-gdextension --build-dir build/ -- --headless - python tests/run.py 2-pythonscript-init --build-dir build/ -- --headless - python tests/run.py 3-pythonscript-cython-only --build-dir build/ -- --headless + ARGS=--build-dir=build/ ${{ steps.setup-godot.outputs.EXTRA_RUN_TESTS_ARGS }} -- --headless + python tests/run.py 0-gdscript $ARGS + python tests/run.py 1-gdextension $ARGS + python tests/run.py 2-pythonscript-init $ARGS + python tests/run.py 3-pythonscript-cython-only $ARGS + # - name: 'Install Mesa3D OpenGL' # shell: bash # run: | @@ -140,10 +238,13 @@ jobs: # 7z.exe x mesa.7z # ls -lh opengl32.dll # Sanity check # popd + # - name: 'Run tests' # run: python tests/run.py --build-dir build/ --godot-binary ${{ GODOT_BINARY_VERSION }} + # - name: 'Generate artifact archive' # run: meson compile -C build/ release + # - name: 'Export release artifact' # uses: actions/upload-artifact@11830c9f4d30053679cb8904e3b3ce1b8c00bf40 # pin@v2 # with: diff --git a/meson.build b/meson.build index baeb20c2..1b3d7e7c 100644 --- a/meson.build +++ b/meson.build @@ -246,6 +246,13 @@ endif if get_option('gdextension_path') != '' # GDExtension already exists gdextension_path = join_paths(meson.project_source_root(), get_option('gdextension_path')) + run_command( + python, + 'scripts/symlink.py', + gdextension_path, + join_paths(meson.project_build_root(), 'gdextension_api'), + check: true, + ) else # Download Godot and generate it GDextension API message('Fetching Godot v@0@ binary and generating GDExtension...'.format(get_option('godot_version'))) diff --git a/misc/release_pythonscript.gdextension b/misc/release_pythonscript.gdextension index 2feb547c..fc4bd8d0 100644 --- a/misc/release_pythonscript.gdextension +++ b/misc/release_pythonscript.gdextension @@ -1,6 +1,7 @@ [configuration] entry_symbol = "pythonscript_init" +compatibility_minimum = "4.1" [libraries] diff --git a/scripts/extension_api_parser/classes.py b/scripts/extension_api_parser/classes.py index c509741e..9c03734d 100644 --- a/scripts/extension_api_parser/classes.py +++ b/scripts/extension_api_parser/classes.py @@ -58,6 +58,7 @@ class ClassMethodSpec: is_virtual: bool is_property_accessor: bool hash: Optional[int] + hash_compatibility: Optional[int] return_type: TypeInUse arguments: List[ClassMethodArgumentSpec] @@ -72,6 +73,7 @@ def parse(cls, item: dict) -> "ClassMethodSpec": item["return_type"] = TypeInUse.parse(return_value["type"]) item.setdefault("arguments", []) item.setdefault("hash", None) + item.setdefault("hash_compatibility", None) item.setdefault("is_property_accessor", False) assert_api_consistency(cls, item) return cls( @@ -83,6 +85,7 @@ def parse(cls, item: dict) -> "ClassMethodSpec": is_virtual=item["is_virtual"], is_property_accessor=item["is_property_accessor"], hash=item["hash"], + hash_compatibility=item["hash_compatibility"], return_type=item["return_type"], arguments=[ClassMethodArgumentSpec.parse(x) for x in item["arguments"]], ) diff --git a/scripts/symlink.py b/scripts/symlink.py new file mode 100644 index 00000000..126a758a --- /dev/null +++ b/scripts/symlink.py @@ -0,0 +1,43 @@ +#! /usr/bin/env python3 + +import sys +import os + + +def symlink(src, dst): + try: + os.unlink(dst) + except Exception: + pass + + if sys.platform == "win32": + try: + import _winapi + + _winapi.CreateJunction(src, dst) + except Exception as e: + raise SystemExit( + f"Can't do a NTFS junction as symlink fallback ({src} -> {dst})" + ) from e + + else: + try: + os.symlink(src, dst) + except Exception as e: + raise SystemExit(f"Can't create symlink ({src} -> {dst})") from e + + +USAGE = "usage: symlink.py SRC1 SRC2 ... DST1 DST2 ..." + + +srcs_and_dsts = sys.argv[1:] +srcs = srcs_and_dsts[: len(srcs_and_dsts) // 2] +dsts = srcs_and_dsts[len(srcs_and_dsts) // 2 :] + + +if len(srcs) != len(dsts): + raise SystemExit(USAGE) + + +for src, dst in zip(srcs, dsts): + symlink(src, dst) diff --git a/src/godot/classes_pyx/class.pyx.j2 b/src/godot/classes_pyx/class.pyx.j2 index 860b3b30..3cfee164 100644 --- a/src/godot/classes_pyx/class.pyx.j2 +++ b/src/godot/classes_pyx/class.pyx.j2 @@ -5,7 +5,7 @@ from cpython.object cimport PyObject_GenericGetAttr, PyObject_GenericSetAttr {% endif %} cdef class {{ cls.cy_type }}({{ cls.inherits.cy_type if cls.inherits else "" }}): -{% if cls.inherits is none %} +{% if cls.inherits is none %} {# @staticmethod cpdef inline {{ cls.cy_type}} new(): @@ -122,9 +122,7 @@ cdef class {{ cls.cy_type }}({{ cls.inherits.cy_type if cls.inherits else "" }}) def call(self, name, *args): return self.callv(name, GDArray(args)) -{% else %} - pass -{% endif %} +{% endif %} # if cls.inherits is none @staticmethod cdef {{ cls.cy_type }} from_ptr(gd_object_t ptr): @@ -134,5 +132,60 @@ cdef class {{ cls.cy_type }}({{ cls.inherits.cy_type if cls.inherits else "" }}) # Note if the object is a reference, we stole it from the caller given we # don't call `Reference.reference` here return wrapper +{# +{% if cls.is_instantiable %} + +{% if cls.is_refcounted %} + def __init__(self): + if __{{ cls.name }}_constructor == NULL: + raise NotImplementedError(__ERR_MSG_BINDING_NOT_AVAILABLE) + cdef godot_bool __ret + with nogil: + self._gd_ptr = __{{ cls["name"] }}_constructor() + + if self._gd_ptr is NULL: + raise MemoryError + + gdapi10.godot_method_bind_ptrcall( + __methbind__Reference__init_ref, + self._gd_ptr, + NULL, + &__ret + ) +{% else %} # if cls.is_refcounted + @staticmethod + def new(): + if __{{ cls.name }}_constructor == NULL: + raise NotImplementedError(__ERR_MSG_BINDING_NOT_AVAILABLE) + # Call to __new__ bypasses __init__ constructor + cdef {{ cls.name }} wrapper = {{ cls.name }}.__new__({{ cls.name }}) + with nogil: + wrapper._gd_ptr = __{{ cls.name }}_constructor() + if wrapper._gd_ptr is NULL: + raise MemoryError + return wrapper +{% endif %} # if cls.is_refcounted + +{% if cls.name == "RefCounted" %} + @classmethod + def new(cls): + raise RuntimeError(f"Refcounted Godot object must be created with `{ cls.__name__ }()`") + + def __dealloc__(self): + cdef godot_bool __ret + if self._gd_ptr == NULL: + return + with nogil: + gdapi10.godot_method_bind_ptrcall( + __methbind__Reference__unreference, + self._gd_ptr, + NULL, + &__ret + ) + if __ret: + gdapi10.godot_object_destroy(self._gd_ptr) +{% endif %} + +{% endif %} # if cls.is_instantiable #} {% endmacro %} diff --git a/src/godot/hazmat/gdnative_ptrs.pxd.j2 b/src/godot/hazmat/gdnative_ptrs.pxd.j2 index 6417fbf8..d3557e4c 100644 --- a/src/godot/hazmat/gdnative_ptrs.pxd.j2 +++ b/src/godot/hazmat/gdnative_ptrs.pxd.j2 @@ -7,6 +7,148 @@ from libc.stdint cimport * from .gdextension_interface cimport * +cdef struct LoadedGDExtensionInterface: + void (*get_godot_version)(GDExtensionGodotVersion *r_godot_version) + void *(*mem_alloc)(size_t p_bytes) + void *(*mem_realloc)(void *p_ptr, size_t p_bytes) + void (*mem_free)(void *p_ptr) + void (*print_error)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line, GDExtensionBool p_editor_notify) + void (*print_error_with_message)(const char *p_description, const char *p_message, const char *p_function, const char *p_file, int32_t p_line, GDExtensionBool p_editor_notify) + void (*print_warning)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line, GDExtensionBool p_editor_notify) + void (*print_warning_with_message)(const char *p_description, const char *p_message, const char *p_function, const char *p_file, int32_t p_line, GDExtensionBool p_editor_notify) + void (*print_script_error)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line, GDExtensionBool p_editor_notify) + void (*print_script_error_with_message)(const char *p_description, const char *p_message, const char *p_function, const char *p_file, int32_t p_line, GDExtensionBool p_editor_notify) + uint64_t (*get_native_struct_size)(GDExtensionConstStringNamePtr p_name) + void (*variant_new_copy)(GDExtensionUninitializedVariantPtr r_dest, GDExtensionConstVariantPtr p_src) + void (*variant_new_nil)(GDExtensionUninitializedVariantPtr r_dest) + void (*variant_destroy)(GDExtensionVariantPtr p_self) + void (*variant_call)(GDExtensionVariantPtr p_self, GDExtensionConstStringNamePtr p_method, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionUninitializedVariantPtr r_return, GDExtensionCallError *r_error) + void (*variant_call_static)(GDExtensionVariantType p_type, GDExtensionConstStringNamePtr p_method, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionUninitializedVariantPtr r_return, GDExtensionCallError *r_error) + void (*variant_evaluate)(GDExtensionVariantOperator p_op, GDExtensionConstVariantPtr p_a, GDExtensionConstVariantPtr p_b, GDExtensionUninitializedVariantPtr r_return, GDExtensionBool *r_valid) + void (*variant_set)(GDExtensionVariantPtr p_self, GDExtensionConstVariantPtr p_key, GDExtensionConstVariantPtr p_value, GDExtensionBool *r_valid) + void (*variant_set_named)(GDExtensionVariantPtr p_self, GDExtensionConstStringNamePtr p_key, GDExtensionConstVariantPtr p_value, GDExtensionBool *r_valid) + void (*variant_set_keyed)(GDExtensionVariantPtr p_self, GDExtensionConstVariantPtr p_key, GDExtensionConstVariantPtr p_value, GDExtensionBool *r_valid) + void (*variant_set_indexed)(GDExtensionVariantPtr p_self, GDExtensionInt p_index, GDExtensionConstVariantPtr p_value, GDExtensionBool *r_valid, GDExtensionBool *r_oob) + void (*variant_get)(GDExtensionConstVariantPtr p_self, GDExtensionConstVariantPtr p_key, GDExtensionUninitializedVariantPtr r_ret, GDExtensionBool *r_valid) + void (*variant_get_named)(GDExtensionConstVariantPtr p_self, GDExtensionConstStringNamePtr p_key, GDExtensionUninitializedVariantPtr r_ret, GDExtensionBool *r_valid) + void (*variant_get_keyed)(GDExtensionConstVariantPtr p_self, GDExtensionConstVariantPtr p_key, GDExtensionUninitializedVariantPtr r_ret, GDExtensionBool *r_valid) + void (*variant_get_indexed)(GDExtensionConstVariantPtr p_self, GDExtensionInt p_index, GDExtensionUninitializedVariantPtr r_ret, GDExtensionBool *r_valid, GDExtensionBool *r_oob) + GDExtensionBool (*variant_iter_init)(GDExtensionConstVariantPtr p_self, GDExtensionUninitializedVariantPtr r_iter, GDExtensionBool *r_valid) + GDExtensionBool (*variant_iter_next)(GDExtensionConstVariantPtr p_self, GDExtensionVariantPtr r_iter, GDExtensionBool *r_valid) + void (*variant_iter_get)(GDExtensionConstVariantPtr p_self, GDExtensionVariantPtr r_iter, GDExtensionUninitializedVariantPtr r_ret, GDExtensionBool *r_valid) + GDExtensionInt (*variant_hash)(GDExtensionConstVariantPtr p_self) + GDExtensionInt (*variant_recursive_hash)(GDExtensionConstVariantPtr p_self, GDExtensionInt p_recursion_count) + GDExtensionBool (*variant_hash_compare)(GDExtensionConstVariantPtr p_self, GDExtensionConstVariantPtr p_other) + GDExtensionBool (*variant_booleanize)(GDExtensionConstVariantPtr p_self) + void (*variant_duplicate)(GDExtensionConstVariantPtr p_self, GDExtensionVariantPtr r_ret, GDExtensionBool p_deep) + void (*variant_stringify)(GDExtensionConstVariantPtr p_self, GDExtensionStringPtr r_ret) + GDExtensionVariantType (*variant_get_type)(GDExtensionConstVariantPtr p_self) + GDExtensionBool (*variant_has_method)(GDExtensionConstVariantPtr p_self, GDExtensionConstStringNamePtr p_method) + GDExtensionBool (*variant_has_member)(GDExtensionVariantType p_type, GDExtensionConstStringNamePtr p_member) + GDExtensionBool (*variant_has_key)(GDExtensionConstVariantPtr p_self, GDExtensionConstVariantPtr p_key, GDExtensionBool *r_valid) + void (*variant_get_type_name)(GDExtensionVariantType p_type, GDExtensionUninitializedStringPtr r_name) + GDExtensionBool (*variant_can_convert)(GDExtensionVariantType p_from, GDExtensionVariantType p_to) + GDExtensionBool (*variant_can_convert_strict)(GDExtensionVariantType p_from, GDExtensionVariantType p_to) + GDExtensionVariantFromTypeConstructorFunc (*get_variant_from_type_constructor)(GDExtensionVariantType p_type) + GDExtensionTypeFromVariantConstructorFunc (*get_variant_to_type_constructor)(GDExtensionVariantType p_type) + GDExtensionPtrOperatorEvaluator (*variant_get_ptr_operator_evaluator)(GDExtensionVariantOperator p_operator, GDExtensionVariantType p_type_a, GDExtensionVariantType p_type_b) + GDExtensionPtrBuiltInMethod (*variant_get_ptr_builtin_method)(GDExtensionVariantType p_type, GDExtensionConstStringNamePtr p_method, GDExtensionInt p_hash) + GDExtensionPtrConstructor (*variant_get_ptr_constructor)(GDExtensionVariantType p_type, int32_t p_constructor) + GDExtensionPtrDestructor (*variant_get_ptr_destructor)(GDExtensionVariantType p_type) + void (*variant_construct)(GDExtensionVariantType p_type, GDExtensionUninitializedVariantPtr r_base, const GDExtensionConstVariantPtr *p_args, int32_t p_argument_count, GDExtensionCallError *r_error) + GDExtensionPtrSetter (*variant_get_ptr_setter)(GDExtensionVariantType p_type, GDExtensionConstStringNamePtr p_member) + GDExtensionPtrGetter (*variant_get_ptr_getter)(GDExtensionVariantType p_type, GDExtensionConstStringNamePtr p_member) + GDExtensionPtrIndexedSetter (*variant_get_ptr_indexed_setter)(GDExtensionVariantType p_type) + GDExtensionPtrIndexedGetter (*variant_get_ptr_indexed_getter)(GDExtensionVariantType p_type) + GDExtensionPtrKeyedSetter (*variant_get_ptr_keyed_setter)(GDExtensionVariantType p_type) + GDExtensionPtrKeyedGetter (*variant_get_ptr_keyed_getter)(GDExtensionVariantType p_type) + GDExtensionPtrKeyedChecker (*variant_get_ptr_keyed_checker)(GDExtensionVariantType p_type) + void (*variant_get_constant_value)(GDExtensionVariantType p_type, GDExtensionConstStringNamePtr p_constant, GDExtensionUninitializedVariantPtr r_ret) + GDExtensionPtrUtilityFunction (*variant_get_ptr_utility_function)(GDExtensionConstStringNamePtr p_function, GDExtensionInt p_hash) + void (*string_new_with_latin1_chars)(GDExtensionUninitializedStringPtr r_dest, const char *p_contents) + void (*string_new_with_utf8_chars)(GDExtensionUninitializedStringPtr r_dest, const char *p_contents) + void (*string_new_with_utf16_chars)(GDExtensionUninitializedStringPtr r_dest, const char16_t *p_contents) + void (*string_new_with_utf32_chars)(GDExtensionUninitializedStringPtr r_dest, const char32_t *p_contents) + void (*string_new_with_wide_chars)(GDExtensionUninitializedStringPtr r_dest, const wchar_t *p_contents) + void (*string_new_with_latin1_chars_and_len)(GDExtensionUninitializedStringPtr r_dest, const char *p_contents, GDExtensionInt p_size) + void (*string_new_with_utf8_chars_and_len)(GDExtensionUninitializedStringPtr r_dest, const char *p_contents, GDExtensionInt p_size) + void (*string_new_with_utf16_chars_and_len)(GDExtensionUninitializedStringPtr r_dest, const char16_t *p_contents, GDExtensionInt p_size) + void (*string_new_with_utf32_chars_and_len)(GDExtensionUninitializedStringPtr r_dest, const char32_t *p_contents, GDExtensionInt p_size) + void (*string_new_with_wide_chars_and_len)(GDExtensionUninitializedStringPtr r_dest, const wchar_t *p_contents, GDExtensionInt p_size) + GDExtensionInt (*string_to_latin1_chars)(GDExtensionConstStringPtr p_self, char *r_text, GDExtensionInt p_max_write_length) + GDExtensionInt (*string_to_utf8_chars)(GDExtensionConstStringPtr p_self, char *r_text, GDExtensionInt p_max_write_length) + GDExtensionInt (*string_to_utf16_chars)(GDExtensionConstStringPtr p_self, char16_t *r_text, GDExtensionInt p_max_write_length) + GDExtensionInt (*string_to_utf32_chars)(GDExtensionConstStringPtr p_self, char32_t *r_text, GDExtensionInt p_max_write_length) + GDExtensionInt (*string_to_wide_chars)(GDExtensionConstStringPtr p_self, wchar_t *r_text, GDExtensionInt p_max_write_length) + char32_t *(*string_operator_index)(GDExtensionStringPtr p_self, GDExtensionInt p_index) + const char32_t *(*string_operator_index_const)(GDExtensionConstStringPtr p_self, GDExtensionInt p_index) + void (*string_operator_plus_eq_string)(GDExtensionStringPtr p_self, GDExtensionConstStringPtr p_b) + void (*string_operator_plus_eq_char)(GDExtensionStringPtr p_self, char32_t p_b) + void (*string_operator_plus_eq_cstr)(GDExtensionStringPtr p_self, const char *p_b) + void (*string_operator_plus_eq_wcstr)(GDExtensionStringPtr p_self, const wchar_t *p_b) + void (*string_operator_plus_eq_c32str)(GDExtensionStringPtr p_self, const char32_t *p_b) + GDExtensionInt (*xml_parser_open_buffer)(GDExtensionObjectPtr p_instance, const uint8_t *p_buffer, size_t p_size) + void (*file_access_store_buffer)(GDExtensionObjectPtr p_instance, const uint8_t *p_src, uint64_t p_length) + uint64_t (*file_access_get_buffer)(GDExtensionConstObjectPtr p_instance, uint8_t *p_dst, uint64_t p_length) + int64_t (*worker_thread_pool_add_native_group_task)(GDExtensionObjectPtr p_instance, void (*p_func)(void *, uint32_t), void *p_userdata, int p_elements, int p_tasks, GDExtensionBool p_high_priority, GDExtensionConstStringPtr p_description) + int64_t (*worker_thread_pool_add_native_task)(GDExtensionObjectPtr p_instance, void (*p_func)(void *), void *p_userdata, GDExtensionBool p_high_priority, GDExtensionConstStringPtr p_description) + uint8_t *(*packed_byte_array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index) + const uint8_t *(*packed_byte_array_operator_index_const)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index) + GDExtensionTypePtr (*packed_color_array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index) + GDExtensionTypePtr (*packed_color_array_operator_index_const)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index) + float *(*packed_float32_array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index) + const float *(*packed_float32_array_operator_index_const)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index) + double *(*packed_float64_array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index) + const double *(*packed_float64_array_operator_index_const)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index) + int32_t *(*packed_int32_array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index) + const int32_t *(*packed_int32_array_operator_index_const)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index) + int64_t *(*packed_int64_array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index) + const int64_t *(*packed_int64_array_operator_index_const)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index) + GDExtensionStringPtr (*packed_string_array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index) + GDExtensionStringPtr (*packed_string_array_operator_index_const)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index) + GDExtensionTypePtr (*packed_vector2_array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index) + GDExtensionTypePtr (*packed_vector2_array_operator_index_const)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index) + GDExtensionTypePtr (*packed_vector3_array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index) + GDExtensionTypePtr (*packed_vector3_array_operator_index_const)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index) + GDExtensionVariantPtr (*array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index) + GDExtensionVariantPtr (*array_operator_index_const)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index) + void (*array_ref)(GDExtensionTypePtr p_self, GDExtensionConstTypePtr p_from) + void (*array_set_typed)(GDExtensionTypePtr p_self, GDExtensionVariantType p_type, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstVariantPtr p_script) + GDExtensionVariantPtr (*dictionary_operator_index)(GDExtensionTypePtr p_self, GDExtensionConstVariantPtr p_key) + GDExtensionVariantPtr (*dictionary_operator_index_const)(GDExtensionConstTypePtr p_self, GDExtensionConstVariantPtr p_key) + void (*object_method_bind_call)(GDExtensionMethodBindPtr p_method_bind, GDExtensionObjectPtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_arg_count, GDExtensionUninitializedVariantPtr r_ret, GDExtensionCallError *r_error) + void (*object_method_bind_ptrcall)(GDExtensionMethodBindPtr p_method_bind, GDExtensionObjectPtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret) + void (*object_destroy)(GDExtensionObjectPtr p_o) + GDExtensionObjectPtr (*global_get_singleton)(GDExtensionConstStringNamePtr p_name) + void *(*object_get_instance_binding)(GDExtensionObjectPtr p_o, void *p_token, const GDExtensionInstanceBindingCallbacks *p_callbacks) + void (*object_set_instance_binding)(GDExtensionObjectPtr p_o, void *p_token, void *p_binding, const GDExtensionInstanceBindingCallbacks *p_callbacks) + void (*object_set_instance)(GDExtensionObjectPtr p_o, GDExtensionConstStringNamePtr p_classname, GDExtensionClassInstancePtr p_instance) + GDExtensionBool (*object_get_class_name)(GDExtensionConstObjectPtr p_object, GDExtensionClassLibraryPtr p_library, GDExtensionUninitializedStringNamePtr r_class_name) + GDExtensionObjectPtr (*object_cast_to)(GDExtensionConstObjectPtr p_object, void *p_class_tag) + GDExtensionObjectPtr (*object_get_instance_from_id)(GDObjectInstanceID p_instance_id) + GDObjectInstanceID (*object_get_instance_id)(GDExtensionConstObjectPtr p_object) + GDExtensionObjectPtr (*ref_get_object)(GDExtensionConstRefPtr p_ref) + void (*ref_set_object)(GDExtensionRefPtr p_ref, GDExtensionObjectPtr p_object) + GDExtensionScriptInstancePtr (*script_instance_create)(const GDExtensionScriptInstanceInfo *p_info, GDExtensionScriptInstanceDataPtr p_instance_data) + GDExtensionObjectPtr (*classdb_construct_object)(GDExtensionConstStringNamePtr p_classname) + GDExtensionMethodBindPtr (*classdb_get_method_bind)(GDExtensionConstStringNamePtr p_classname, GDExtensionConstStringNamePtr p_methodname, GDExtensionInt p_hash) + void *(*classdb_get_class_tag)(GDExtensionConstStringNamePtr p_classname) + void (*classdb_register_extension_class)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo *p_extension_funcs) + void (*classdb_register_extension_class_method)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionClassMethodInfo *p_method_info) + void (*classdb_register_extension_class_integer_constant)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_enum_name, GDExtensionConstStringNamePtr p_constant_name, GDExtensionInt p_constant_value, GDExtensionBool p_is_bitfield) + void (*classdb_register_extension_class_property)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionPropertyInfo *p_info, GDExtensionConstStringNamePtr p_setter, GDExtensionConstStringNamePtr p_getter) + void (*classdb_register_extension_class_property_group)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringPtr p_group_name, GDExtensionConstStringPtr p_prefix) + void (*classdb_register_extension_class_property_subgroup)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringPtr p_subgroup_name, GDExtensionConstStringPtr p_prefix) + void (*classdb_register_extension_class_signal)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_signal_name, const GDExtensionPropertyInfo *p_argument_info, GDExtensionInt p_argument_count) + void (*classdb_unregister_extension_class)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name) + void (*get_library_path)(GDExtensionClassLibraryPtr p_library, GDExtensionUninitializedStringPtr r_path) + void (*editor_add_plugin)(GDExtensionConstStringNamePtr p_class_name) + void (*editor_remove_plugin)(GDExtensionConstStringNamePtr p_class_name) + + +cdef LoadedGDExtensionInterface pythonscript_gdextension + + cdef extern from * nogil: # Global variables defined in `pythonscript.c` # Given `libpythonscript.so` is responsible for initializing the Python @@ -19,15 +161,15 @@ cdef extern from * nogil: #else # define DLL_IMPORT #endif - DLL_IMPORT extern const GDExtensionInterface *pythonscript_gdextension; + DLL_IMPORT extern GDExtensionInterfaceGetProcAddress pythonscript_gdextension_get_proc_address; DLL_IMPORT extern GDExtensionClassLibraryPtr pythonscript_gdextension_library; DLL_IMPORT extern void pythonscript_gdstringname_new(GDExtensionStringNamePtr ptr, const char *cstr); DLL_IMPORT extern void pythonscript_gdstringname_delete(GDExtensionStringNamePtr ptr); """ - cdef const GDExtensionInterface *pythonscript_gdextension; - cdef const GDExtensionClassLibraryPtr pythonscript_gdextension_library; - cdef void pythonscript_gdstringname_new(GDExtensionStringNamePtr ptr, const char *cstr); - cdef void pythonscript_gdstringname_delete(GDExtensionStringNamePtr ptr); + cdef const GDExtensionInterfaceGetProcAddress pythonscript_gdextension_get_proc_address; + cdef const GDExtensionClassLibraryPtr pythonscript_gdextension_library + cdef void pythonscript_gdstringname_new(GDExtensionStringNamePtr ptr, const char *cstr) + cdef void pythonscript_gdstringname_delete(GDExtensionStringNamePtr ptr) ############################################################################## diff --git a/src/godot/hazmat/gdnative_ptrs.pyx.j2 b/src/godot/hazmat/gdnative_ptrs.pyx.j2 index fcef6cfb..97b02c73 100644 --- a/src/godot/hazmat/gdnative_ptrs.pyx.j2 +++ b/src/godot/hazmat/gdnative_ptrs.pyx.j2 @@ -9,6 +9,152 @@ from .gdextension_interface cimport * cdef gd_string_name_t _gdname +############################################################################## +# GDExtension interface functions # +############################################################################## + + +cdef LoadedGDExtensionInterface pythonscript_gdextension + + +pythonscript_gdextension.get_godot_version = pythonscript_gdextension_get_proc_address("get_godot_version") +pythonscript_gdextension.mem_alloc = pythonscript_gdextension_get_proc_address("mem_alloc") +pythonscript_gdextension.mem_realloc = pythonscript_gdextension_get_proc_address("mem_realloc") +pythonscript_gdextension.mem_free = pythonscript_gdextension_get_proc_address("mem_free") +pythonscript_gdextension.print_error = pythonscript_gdextension_get_proc_address("print_error") +pythonscript_gdextension.print_error_with_message = pythonscript_gdextension_get_proc_address("print_error_with_message") +pythonscript_gdextension.print_warning = pythonscript_gdextension_get_proc_address("print_warning") +pythonscript_gdextension.print_warning_with_message = pythonscript_gdextension_get_proc_address("print_warning_with_message") +pythonscript_gdextension.print_script_error = pythonscript_gdextension_get_proc_address("print_script_error") +pythonscript_gdextension.print_script_error_with_message = pythonscript_gdextension_get_proc_address("print_script_error_with_message") +pythonscript_gdextension.get_native_struct_size = pythonscript_gdextension_get_proc_address("get_native_struct_size") +pythonscript_gdextension.variant_new_copy = pythonscript_gdextension_get_proc_address("variant_new_copy") +pythonscript_gdextension.variant_new_nil = pythonscript_gdextension_get_proc_address("variant_new_nil") +pythonscript_gdextension.variant_destroy = pythonscript_gdextension_get_proc_address("variant_destroy") +pythonscript_gdextension.variant_call = pythonscript_gdextension_get_proc_address("variant_call") +pythonscript_gdextension.variant_call_static = pythonscript_gdextension_get_proc_address("variant_call_static") +pythonscript_gdextension.variant_evaluate = pythonscript_gdextension_get_proc_address("variant_evaluate") +pythonscript_gdextension.variant_set = pythonscript_gdextension_get_proc_address("variant_set") +pythonscript_gdextension.variant_set_named = pythonscript_gdextension_get_proc_address("variant_set_named") +pythonscript_gdextension.variant_set_keyed = pythonscript_gdextension_get_proc_address("variant_set_keyed") +pythonscript_gdextension.variant_set_indexed = pythonscript_gdextension_get_proc_address("variant_set_indexed") +pythonscript_gdextension.variant_get = pythonscript_gdextension_get_proc_address("variant_get") +pythonscript_gdextension.variant_get_named = pythonscript_gdextension_get_proc_address("variant_get_named") +pythonscript_gdextension.variant_get_keyed = pythonscript_gdextension_get_proc_address("variant_get_keyed") +pythonscript_gdextension.variant_get_indexed = pythonscript_gdextension_get_proc_address("variant_get_indexed") +pythonscript_gdextension.variant_iter_init = pythonscript_gdextension_get_proc_address("variant_iter_init") +pythonscript_gdextension.variant_iter_next = pythonscript_gdextension_get_proc_address("variant_iter_next") +pythonscript_gdextension.variant_iter_get = pythonscript_gdextension_get_proc_address("variant_iter_get") +pythonscript_gdextension.variant_hash = pythonscript_gdextension_get_proc_address("variant_hash") +pythonscript_gdextension.variant_recursive_hash = pythonscript_gdextension_get_proc_address("variant_recursive_hash") +pythonscript_gdextension.variant_hash_compare = pythonscript_gdextension_get_proc_address("variant_hash_compare") +pythonscript_gdextension.variant_booleanize = pythonscript_gdextension_get_proc_address("variant_booleanize") +pythonscript_gdextension.variant_duplicate = pythonscript_gdextension_get_proc_address("variant_duplicate") +pythonscript_gdextension.variant_stringify = pythonscript_gdextension_get_proc_address("variant_stringify") +pythonscript_gdextension.variant_get_type = pythonscript_gdextension_get_proc_address("variant_get_type") +pythonscript_gdextension.variant_has_method = pythonscript_gdextension_get_proc_address("variant_has_method") +pythonscript_gdextension.variant_has_member = pythonscript_gdextension_get_proc_address("variant_has_member") +pythonscript_gdextension.variant_has_key = pythonscript_gdextension_get_proc_address("variant_has_key") +pythonscript_gdextension.variant_get_type_name = pythonscript_gdextension_get_proc_address("variant_get_type_name") +pythonscript_gdextension.variant_can_convert = pythonscript_gdextension_get_proc_address("variant_can_convert") +pythonscript_gdextension.variant_can_convert_strict = pythonscript_gdextension_get_proc_address("variant_can_convert_strict") +pythonscript_gdextension.get_variant_from_type_constructor = pythonscript_gdextension_get_proc_address("get_variant_from_type_constructor") +pythonscript_gdextension.get_variant_to_type_constructor = pythonscript_gdextension_get_proc_address("get_variant_to_type_constructor") +pythonscript_gdextension.variant_get_ptr_operator_evaluator = pythonscript_gdextension_get_proc_address("variant_get_ptr_operator_evaluator") +pythonscript_gdextension.variant_get_ptr_builtin_method = pythonscript_gdextension_get_proc_address("variant_get_ptr_builtin_method") +pythonscript_gdextension.variant_get_ptr_constructor = pythonscript_gdextension_get_proc_address("variant_get_ptr_constructor") +pythonscript_gdextension.variant_get_ptr_destructor = pythonscript_gdextension_get_proc_address("variant_get_ptr_destructor") +pythonscript_gdextension.variant_construct = pythonscript_gdextension_get_proc_address("variant_construct") +pythonscript_gdextension.variant_get_ptr_setter = pythonscript_gdextension_get_proc_address("variant_get_ptr_setter") +pythonscript_gdextension.variant_get_ptr_getter = pythonscript_gdextension_get_proc_address("variant_get_ptr_getter") +pythonscript_gdextension.variant_get_ptr_indexed_setter = pythonscript_gdextension_get_proc_address("variant_get_ptr_indexed_setter") +pythonscript_gdextension.variant_get_ptr_indexed_getter = pythonscript_gdextension_get_proc_address("variant_get_ptr_indexed_getter") +pythonscript_gdextension.variant_get_ptr_keyed_setter = pythonscript_gdextension_get_proc_address("variant_get_ptr_keyed_setter") +pythonscript_gdextension.variant_get_ptr_keyed_getter = pythonscript_gdextension_get_proc_address("variant_get_ptr_keyed_getter") +pythonscript_gdextension.variant_get_ptr_keyed_checker = pythonscript_gdextension_get_proc_address("variant_get_ptr_keyed_checker") +pythonscript_gdextension.variant_get_constant_value = pythonscript_gdextension_get_proc_address("variant_get_constant_value") +pythonscript_gdextension.variant_get_ptr_utility_function = pythonscript_gdextension_get_proc_address("variant_get_ptr_utility_function") +pythonscript_gdextension.string_new_with_latin1_chars = pythonscript_gdextension_get_proc_address("string_new_with_latin1_chars") +pythonscript_gdextension.string_new_with_utf8_chars = pythonscript_gdextension_get_proc_address("string_new_with_utf8_chars") +pythonscript_gdextension.string_new_with_utf16_chars = pythonscript_gdextension_get_proc_address("string_new_with_utf16_chars") +pythonscript_gdextension.string_new_with_utf32_chars = pythonscript_gdextension_get_proc_address("string_new_with_utf32_chars") +pythonscript_gdextension.string_new_with_wide_chars = pythonscript_gdextension_get_proc_address("string_new_with_wide_chars") +pythonscript_gdextension.string_new_with_latin1_chars_and_len = pythonscript_gdextension_get_proc_address("string_new_with_latin1_chars_and_len") +pythonscript_gdextension.string_new_with_utf8_chars_and_len = pythonscript_gdextension_get_proc_address("string_new_with_utf8_chars_and_len") +pythonscript_gdextension.string_new_with_utf16_chars_and_len = pythonscript_gdextension_get_proc_address("string_new_with_utf16_chars_and_len") +pythonscript_gdextension.string_new_with_utf32_chars_and_len = pythonscript_gdextension_get_proc_address("string_new_with_utf32_chars_and_len") +pythonscript_gdextension.string_new_with_wide_chars_and_len = pythonscript_gdextension_get_proc_address("string_new_with_wide_chars_and_len") +pythonscript_gdextension.string_to_latin1_chars = pythonscript_gdextension_get_proc_address("string_to_latin1_chars") +pythonscript_gdextension.string_to_utf8_chars = pythonscript_gdextension_get_proc_address("string_to_utf8_chars") +pythonscript_gdextension.string_to_utf16_chars = pythonscript_gdextension_get_proc_address("string_to_utf16_chars") +pythonscript_gdextension.string_to_utf32_chars = pythonscript_gdextension_get_proc_address("string_to_utf32_chars") +pythonscript_gdextension.string_to_wide_chars = pythonscript_gdextension_get_proc_address("string_to_wide_chars") +pythonscript_gdextension.string_operator_index = pythonscript_gdextension_get_proc_address("string_operator_index") +pythonscript_gdextension.string_operator_index_const = pythonscript_gdextension_get_proc_address("string_operator_index_const") +pythonscript_gdextension.string_operator_plus_eq_string = pythonscript_gdextension_get_proc_address("string_operator_plus_eq_string") +pythonscript_gdextension.string_operator_plus_eq_char = pythonscript_gdextension_get_proc_address("string_operator_plus_eq_char") +pythonscript_gdextension.string_operator_plus_eq_cstr = pythonscript_gdextension_get_proc_address("string_operator_plus_eq_cstr") +pythonscript_gdextension.string_operator_plus_eq_wcstr = pythonscript_gdextension_get_proc_address("string_operator_plus_eq_wcstr") +pythonscript_gdextension.string_operator_plus_eq_c32str = pythonscript_gdextension_get_proc_address("string_operator_plus_eq_c32str") +pythonscript_gdextension.xml_parser_open_buffer = pythonscript_gdextension_get_proc_address("xml_parser_open_buffer") +pythonscript_gdextension.file_access_store_buffer = pythonscript_gdextension_get_proc_address("file_access_store_buffer") +pythonscript_gdextension.file_access_get_buffer = pythonscript_gdextension_get_proc_address("file_access_get_buffer") +pythonscript_gdextension.worker_thread_pool_add_native_group_task = pythonscript_gdextension_get_proc_address("worker_thread_pool_add_native_group_task") +pythonscript_gdextension.worker_thread_pool_add_native_task = pythonscript_gdextension_get_proc_address("worker_thread_pool_add_native_task") +pythonscript_gdextension.packed_byte_array_operator_index = pythonscript_gdextension_get_proc_address("packed_byte_array_operator_index") +pythonscript_gdextension.packed_byte_array_operator_index_const = pythonscript_gdextension_get_proc_address("packed_byte_array_operator_index_const") +pythonscript_gdextension.packed_color_array_operator_index = pythonscript_gdextension_get_proc_address("packed_color_array_operator_index") +pythonscript_gdextension.packed_color_array_operator_index_const = pythonscript_gdextension_get_proc_address("packed_color_array_operator_index_const") +pythonscript_gdextension.packed_float32_array_operator_index = pythonscript_gdextension_get_proc_address("packed_float32_array_operator_index") +pythonscript_gdextension.packed_float32_array_operator_index_const = pythonscript_gdextension_get_proc_address("packed_float32_array_operator_index_const") +pythonscript_gdextension.packed_float64_array_operator_index = pythonscript_gdextension_get_proc_address("packed_float64_array_operator_index") +pythonscript_gdextension.packed_float64_array_operator_index_const = pythonscript_gdextension_get_proc_address("packed_float64_array_operator_index_const") +pythonscript_gdextension.packed_int32_array_operator_index = pythonscript_gdextension_get_proc_address("packed_int32_array_operator_index") +pythonscript_gdextension.packed_int32_array_operator_index_const = pythonscript_gdextension_get_proc_address("packed_int32_array_operator_index_const") +pythonscript_gdextension.packed_int64_array_operator_index = pythonscript_gdextension_get_proc_address("packed_int64_array_operator_index") +pythonscript_gdextension.packed_int64_array_operator_index_const = pythonscript_gdextension_get_proc_address("packed_int64_array_operator_index_const") +pythonscript_gdextension.packed_string_array_operator_index = pythonscript_gdextension_get_proc_address("packed_string_array_operator_index") +pythonscript_gdextension.packed_string_array_operator_index_const = pythonscript_gdextension_get_proc_address("packed_string_array_operator_index_const") +pythonscript_gdextension.packed_vector2_array_operator_index = pythonscript_gdextension_get_proc_address("packed_vector2_array_operator_index") +pythonscript_gdextension.packed_vector2_array_operator_index_const = pythonscript_gdextension_get_proc_address("packed_vector2_array_operator_index_const") +pythonscript_gdextension.packed_vector3_array_operator_index = pythonscript_gdextension_get_proc_address("packed_vector3_array_operator_index") +pythonscript_gdextension.packed_vector3_array_operator_index_const = pythonscript_gdextension_get_proc_address("packed_vector3_array_operator_index_const") +pythonscript_gdextension.array_operator_index = pythonscript_gdextension_get_proc_address("array_operator_index") +pythonscript_gdextension.array_operator_index_const = pythonscript_gdextension_get_proc_address("array_operator_index_const") +pythonscript_gdextension.array_ref = pythonscript_gdextension_get_proc_address("array_ref") +pythonscript_gdextension.array_set_typed = pythonscript_gdextension_get_proc_address("array_set_typed") +pythonscript_gdextension.dictionary_operator_index = pythonscript_gdextension_get_proc_address("dictionary_operator_index") +pythonscript_gdextension.dictionary_operator_index_const = pythonscript_gdextension_get_proc_address("dictionary_operator_index_const") +pythonscript_gdextension.object_method_bind_call = pythonscript_gdextension_get_proc_address("object_method_bind_call") +pythonscript_gdextension.object_method_bind_ptrcall = pythonscript_gdextension_get_proc_address("object_method_bind_ptrcall") +pythonscript_gdextension.object_destroy = pythonscript_gdextension_get_proc_address("object_destroy") +pythonscript_gdextension.global_get_singleton = pythonscript_gdextension_get_proc_address("global_get_singleton") +pythonscript_gdextension.object_get_instance_binding = pythonscript_gdextension_get_proc_address("object_get_instance_binding") +pythonscript_gdextension.object_set_instance_binding = pythonscript_gdextension_get_proc_address("object_set_instance_binding") +pythonscript_gdextension.object_set_instance = pythonscript_gdextension_get_proc_address("object_set_instance") +pythonscript_gdextension.object_get_class_name = pythonscript_gdextension_get_proc_address("object_get_class_name") +pythonscript_gdextension.object_cast_to = pythonscript_gdextension_get_proc_address("object_cast_to") +pythonscript_gdextension.object_get_instance_from_id = pythonscript_gdextension_get_proc_address("object_get_instance_from_id") +pythonscript_gdextension.object_get_instance_id = pythonscript_gdextension_get_proc_address("object_get_instance_id") +pythonscript_gdextension.ref_get_object = pythonscript_gdextension_get_proc_address("ref_get_object") +pythonscript_gdextension.ref_set_object = pythonscript_gdextension_get_proc_address("ref_set_object") +pythonscript_gdextension.script_instance_create = pythonscript_gdextension_get_proc_address("script_instance_create") +pythonscript_gdextension.classdb_construct_object = pythonscript_gdextension_get_proc_address("classdb_construct_object") +pythonscript_gdextension.classdb_get_method_bind = pythonscript_gdextension_get_proc_address("classdb_get_method_bind") +pythonscript_gdextension.classdb_get_class_tag = pythonscript_gdextension_get_proc_address("classdb_get_class_tag") +pythonscript_gdextension.classdb_register_extension_class = pythonscript_gdextension_get_proc_address("classdb_register_extension_class") +pythonscript_gdextension.classdb_register_extension_class_method = pythonscript_gdextension_get_proc_address("classdb_register_extension_class_method") +pythonscript_gdextension.classdb_register_extension_class_integer_constant = pythonscript_gdextension_get_proc_address("classdb_register_extension_class_integer_constant") +pythonscript_gdextension.classdb_register_extension_class_property = pythonscript_gdextension_get_proc_address("classdb_register_extension_class_property") +pythonscript_gdextension.classdb_register_extension_class_property_group = pythonscript_gdextension_get_proc_address("classdb_register_extension_class_property_group") +pythonscript_gdextension.classdb_register_extension_class_property_subgroup = pythonscript_gdextension_get_proc_address("classdb_register_extension_class_property_subgroup") +pythonscript_gdextension.classdb_register_extension_class_signal = pythonscript_gdextension_get_proc_address("classdb_register_extension_class_signal") +pythonscript_gdextension.classdb_unregister_extension_class = pythonscript_gdextension_get_proc_address("classdb_unregister_extension_class") +pythonscript_gdextension.get_library_path = pythonscript_gdextension_get_proc_address("get_library_path") +pythonscript_gdextension.editor_add_plugin = pythonscript_gdextension_get_proc_address("editor_add_plugin") +pythonscript_gdextension.editor_remove_plugin = pythonscript_gdextension_get_proc_address("editor_remove_plugin") + + ############################################################################## # Builtins methods function pointers # ############################################################################## diff --git a/src/godot/hazmat/meson.build b/src/godot/hazmat/meson.build index 539a4ca4..95e59b1b 100644 --- a/src/godot/hazmat/meson.build +++ b/src/godot/hazmat/meson.build @@ -87,6 +87,10 @@ endif shared_library( 'gdnative_ptrs', c_gdnative_ptrs, + # LoadedGDExtensionInterface's initialization code uses + # `pythonscript_gdextension_get_proc_address` which provide opaque function pointers, + # which we must then cast to the correct type before using them. + c_args: ['-Wno-cast-function-type'], dependencies : [dep_godot, dep_python, dep_pythonscript], install_rpath: gdnative_ptrs_rpath, # To find libpython name_prefix: python_native_module_name_prefix, diff --git a/src/pythonscript.c b/src/pythonscript.c index 028ed0af..209137f5 100644 --- a/src/pythonscript.c +++ b/src/pythonscript.c @@ -54,7 +54,7 @@ static PythonscriptState state = STALLED; static PyThreadState *gilstate = NULL; // Global variables used by Cython modules to access the Godot API -DLL_EXPORT const GDExtensionInterface *pythonscript_gdextension = NULL; +DLL_EXPORT GDExtensionInterfaceGetProcAddress pythonscript_gdextension_get_proc_address = NULL; DLL_EXPORT GDExtensionClassLibraryPtr pythonscript_gdextension_library = NULL; @@ -65,13 +65,14 @@ static GDExtensionPtrConstructor gdstring_constructor = NULL; static GDExtensionPtrDestructor gdstring_destructor = NULL; static GDExtensionPtrConstructor gdstringname_from_gdstring_constructor = NULL; static GDExtensionPtrDestructor gdstringname_destructor = NULL; +static void (*gdstring_new_with_utf8_chars)(GDExtensionUninitializedStringPtr, const char *) = NULL; DLL_EXPORT void pythonscript_gdstringname_new(GDExtensionStringNamePtr ptr, const char *cstr) { // Method name must be passed as a StringName object... which itself has // to be built from a String object :( char as_gdstring[GD_STRING_MAX_SIZE]; const GDExtensionConstTypePtr args[1] = {&as_gdstring}; - pythonscript_gdextension->string_new_with_utf8_chars(&as_gdstring, cstr); + gdstring_new_with_utf8_chars(&as_gdstring, cstr); gdstringname_from_gdstring_constructor(ptr, args); gdstring_destructor(&as_gdstring); } @@ -80,16 +81,32 @@ DLL_EXPORT void pythonscript_gdstringname_delete(GDExtensionStringNamePtr ptr) { gdstringname_destructor(ptr); } -#define GD_PRINT(msg) { \ - printf("%s\n", msg); \ -} - #define GD_PRINT_ERROR(msg) { \ - pythonscript_gdextension->print_error(msg, __func__, __FILE__, __LINE__, false); \ + { \ + _Pragma("GCC diagnostic ignored \"-Wincompatible-pointer-types\"") \ + void (*fn)(const char *, const char *, const char *, int32_t, GDExtensionBool); \ + fn = pythonscript_gdextension_get_proc_address("print_error"); \ + _Pragma("GCC diagnostic pop") \ + if (fn) { \ + fn(msg, __func__, __FILE__, __LINE__, false); \ + } else { \ + printf("ERROR: %s", msg); \ + } \ + } \ } #define GD_PRINT_WARNING(msg) { \ - pythonscript_gdextension->print_warning(msg, __func__, __FILE__, __LINE__, false); \ + { \ + _Pragma("GCC diagnostic ignored \"-Wincompatible-pointer-types\"") \ + void (*fn)(const char *, const char *, const char *, int32_t, GDExtensionBool); \ + fn = pythonscript_gdextension_get_proc_address("print_warning"); \ + _Pragma("GCC diagnostic pop") \ + if (fn) { \ + fn(msg, __func__, __FILE__, __LINE__, false); \ + } else { \ + printf("WARNING: %s", msg); \ + } \ + } \ } // Initialize Python interpreter & godot @@ -110,11 +127,18 @@ static void _initialize_python() { // 0) Retrieve Godot methods char method_name_as_gdstringname[GD_STRING_NAME_MAX_SIZE]; pythonscript_gdstringname_new(&method_name_as_gdstringname, "get_base_dir"); - GDExtensionPtrBuiltInMethod gdstring_get_base_dir = pythonscript_gdextension->variant_get_ptr_builtin_method( - GDEXTENSION_VARIANT_TYPE_STRING, - &method_name_as_gdstringname, - 3942272618 - ); + GDExtensionPtrBuiltInMethod gdstring_get_base_dir; + { + #pragma GCC diagnostic ignored "-Wincompatible-pointer-types" + GDExtensionPtrBuiltInMethod (*fn)(GDExtensionVariantType, GDExtensionConstStringNamePtr, GDExtensionInt); + fn = pythonscript_gdextension_get_proc_address("variant_get_ptr_builtin_method"); + #pragma GCC diagnostic pop + gdstring_get_base_dir = fn( + GDEXTENSION_VARIANT_TYPE_STRING, + &method_name_as_gdstringname, + 3942272618 + ); + } pythonscript_gdstringname_delete(&method_name_as_gdstringname); if (gdstring_get_base_dir == NULL) { GD_PRINT_ERROR("Pythonscript: Initialization error (cannot retrieve `String.get_base_dir` method)"); @@ -123,8 +147,13 @@ static void _initialize_python() { // 1) Retrieve library path char gd_library_path[GD_STRING_MAX_SIZE]; - gdstring_constructor(gd_library_path, NULL); - pythonscript_gdextension->get_library_path(pythonscript_gdextension_library, gd_library_path); + { + #pragma GCC diagnostic ignored "-Wincompatible-pointer-types" + void (*fn)(GDExtensionClassLibraryPtr, GDExtensionUninitializedStringPtr); + fn = pythonscript_gdextension_get_proc_address("get_library_path"); + #pragma GCC diagnostic pop + fn(pythonscript_gdextension_library, gd_library_path); + } // 2) Retrieve base dir from library path char gd_basedir_path[GD_STRING_MAX_SIZE]; @@ -133,21 +162,42 @@ static void _initialize_python() { gdstring_destructor(gd_library_path); // 3) Convert base dir into regular c string - GDExtensionInt basedir_path_size = pythonscript_gdextension->string_to_utf8_chars(gd_basedir_path, NULL, 0); + GDExtensionInt basedir_path_size; + { + #pragma GCC diagnostic ignored "-Wincompatible-pointer-types" + GDExtensionInt (*fn)(GDExtensionConstStringPtr, char *, GDExtensionInt); + fn = pythonscript_gdextension_get_proc_address("string_to_utf8_chars"); + #pragma GCC diagnostic pop + basedir_path_size = fn(gd_basedir_path, NULL, 0); + } // Why not using variable length array here ? Glad you asked Timmy ! // VLA are part of the C99 standard, but MSVC compiler is missing it :( // Because VLA were removed from the C11 standard, and the standards committee // decided it was no good, probably because you can't handle allocation errors // like we're about to do two lines down. - char *basedir_path = pythonscript_gdextension->mem_alloc(basedir_path_size + 1); + char *basedir_path; + { + #pragma GCC diagnostic ignored "-Wincompatible-pointer-types" + void *(*fn)(size_t); + fn = pythonscript_gdextension_get_proc_address("mem_alloc"); + #pragma GCC diagnostic pop + basedir_path = fn(basedir_path_size + 1); + } if (basedir_path == NULL) { GD_PRINT_ERROR("Pythonscript: Initialization error (memory allocation failed)"); goto error; } - pythonscript_gdextension->string_to_utf8_chars(gd_basedir_path, basedir_path, basedir_path_size); + { + #pragma GCC diagnostic ignored "-Wincompatible-pointer-types" + GDExtensionInt (*fn)(GDExtensionConstStringPtr, char *, GDExtensionInt); + fn = pythonscript_gdextension_get_proc_address("string_to_utf8_chars"); + #pragma GCC diagnostic pop + fn(gd_basedir_path, basedir_path, basedir_path_size); + } basedir_path[basedir_path_size] = '\0'; gdstring_destructor(gd_basedir_path); + // 4) Configure pythonhome with base dir { PyStatus status = PyConfig_SetBytesString( @@ -155,7 +205,13 @@ static void _initialize_python() { &config.home, basedir_path ); - pythonscript_gdextension->mem_free(basedir_path); + { + #pragma GCC diagnostic ignored "-Wincompatible-pointer-types" + void (*fn)(void*); + fn = pythonscript_gdextension_get_proc_address("mem_free"); + #pragma GCC diagnostic pop + fn(basedir_path); + } if (PyStatus_Exception(status)) { GD_PRINT_ERROR("Pythonscript: Cannot initialize Python interpreter"); GD_PRINT_ERROR(status.err_msg); @@ -297,7 +353,7 @@ static void _deinitialize(void *userdata, GDExtensionInitializationLevel p_level } DLL_EXPORT GDExtensionBool pythonscript_init( - const GDExtensionInterface *p_interface, + const GDExtensionInterfaceGetProcAddress p_get_proc_address, const GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization ) { @@ -308,62 +364,104 @@ DLL_EXPORT GDExtensionBool pythonscript_init( state = ENTRYPOINT_CALLED; (void) p_library; // acknowledge unreferenced parameter - if (p_interface == NULL || r_initialization == NULL) { + if (p_get_proc_address == NULL || r_initialization == NULL) { printf("Pythonscript: Invalid init parameters provided by Godot (this should never happen !)\n"); goto error; } // `pythonscript_gdextension` must be set as early as possible given it is never null-pointer // checked, especially in the Cython modules - pythonscript_gdextension = p_interface; + pythonscript_gdextension_get_proc_address = p_get_proc_address; pythonscript_gdextension_library = p_library; // Load GDString/GDStringName contructor/destructor needed for pythonscript_gdstringname_new/delete helpers - gdstring_constructor = pythonscript_gdextension->variant_get_ptr_constructor(GDEXTENSION_VARIANT_TYPE_STRING, 0); + + { + #pragma GCC diagnostic ignored "-Wincompatible-pointer-types" + GDExtensionPtrConstructor (*fn)(GDExtensionVariantType, int32_t); + fn = pythonscript_gdextension_get_proc_address("variant_get_ptr_constructor"); + #pragma GCC diagnostic pop + gdstring_constructor = fn(GDEXTENSION_VARIANT_TYPE_STRING, 0); + } if (gdstring_constructor == NULL) { GD_PRINT_ERROR("Pythonscript: Initialization error (cannot retrieve `String` constructor)"); goto error; } - gdstring_destructor = pythonscript_gdextension->variant_get_ptr_destructor(GDEXTENSION_VARIANT_TYPE_STRING); + + { + #pragma GCC diagnostic ignored "-Wincompatible-pointer-types" + GDExtensionPtrDestructor (*fn)(GDExtensionVariantType); + fn = pythonscript_gdextension_get_proc_address("variant_get_ptr_destructor"); + #pragma GCC diagnostic pop + gdstring_destructor = fn(GDEXTENSION_VARIANT_TYPE_STRING); + } if (gdstring_destructor == NULL) { GD_PRINT_ERROR("Pythonscript: Initialization error (cannot retrieve `String` destructor)"); goto error; } - gdstringname_from_gdstring_constructor = pythonscript_gdextension->variant_get_ptr_constructor(GDEXTENSION_VARIANT_TYPE_STRING_NAME, 2); + + { + #pragma GCC diagnostic ignored "-Wincompatible-pointer-types" + GDExtensionPtrConstructor (*fn)(GDExtensionVariantType, int32_t); + fn = pythonscript_gdextension_get_proc_address("variant_get_ptr_constructor"); + #pragma GCC diagnostic pop + gdstringname_from_gdstring_constructor = fn(GDEXTENSION_VARIANT_TYPE_STRING_NAME, 2); + } if (gdstringname_from_gdstring_constructor == NULL) { GD_PRINT_ERROR("Pythonscript: Initialization error (cannot retrieve `StringName` constructor)"); goto error; } - gdstringname_destructor = pythonscript_gdextension->variant_get_ptr_destructor(GDEXTENSION_VARIANT_TYPE_STRING_NAME); + + { + #pragma GCC diagnostic ignored "-Wincompatible-pointer-types" + GDExtensionPtrDestructor (*fn)(GDExtensionVariantType); + fn = pythonscript_gdextension_get_proc_address("variant_get_ptr_destructor"); + #pragma GCC diagnostic pop + gdstringname_destructor = fn(GDEXTENSION_VARIANT_TYPE_STRING_NAME); + } if (gdstringname_destructor == NULL) { GD_PRINT_ERROR("Pythonscript: Initialization error (cannot retrieve `StringName` destructor)"); goto error; } + { + #pragma GCC diagnostic ignored "-Wincompatible-pointer-types" + gdstring_new_with_utf8_chars = pythonscript_gdextension_get_proc_address("string_new_with_utf8_chars"); + #pragma GCC diagnostic pop + } + if (gdstring_new_with_utf8_chars == NULL) { + GD_PRINT_ERROR("Pythonscript: Initialization error (cannot retrieve `string_new_with_utf8_chars` destructor)"); + goto error; + } + // Check compatibility between the Godot version that has been used for building // (i.e. the bindings has been generated against) and the version currently executed. - if (p_interface->version_major != GODOT_VERSION_MAJOR) { + GDExtensionGodotVersion godot_version; + { + #pragma GCC diagnostic ignored "-Wincompatible-pointer-types" + void (*fn)(GDExtensionGodotVersion *); + fn = pythonscript_gdextension_get_proc_address("get_godot_version"); + #pragma GCC diagnostic pop + fn(&godot_version); + } + if (godot_version.major != GODOT_VERSION_MAJOR) { // Don't use GD_PRINT_ERROR here given we don't even know if it is available ! printf( - "Pythonscript: Incompatible Godot version (expected ~%d.%d, got %d.%d.%d)\n", + "Pythonscript: Incompatible Godot version (expected ~%d.%d, got %s)\n", GODOT_VERSION_MAJOR, GODOT_VERSION_MINOR, - p_interface->version_major, - p_interface->version_minor, - p_interface->version_patch + godot_version.string ); goto error; } - if (p_interface->version_minor != GODOT_VERSION_MINOR) { + if (godot_version.minor != GODOT_VERSION_MINOR) { char buff[256]; snprintf( buff, sizeof(buff), - "Pythonscript: extension is built for Godot ~%d.%d, but your are running %d.%d.%d. This may cause issues !\n", + "Pythonscript: extension is built for Godot ~%d.%d, but your are running %s. This may cause issues !\n", GODOT_VERSION_MAJOR, GODOT_VERSION_MINOR, - p_interface->version_major, - p_interface->version_minor, - p_interface->version_patch + godot_version.string ); GD_PRINT_WARNING(buff); } diff --git a/tests/1-gdextension/my.c b/tests/1-gdextension/my.c index e2b40eef..04f92447 100644 --- a/tests/1-gdextension/my.c +++ b/tests/1-gdextension/my.c @@ -24,7 +24,7 @@ static void _deinitialize(void *userdata, GDExtensionInitializationLevel p_level } DLL_EXPORT GDExtensionBool my_init( - const GDExtensionInterface *p_interface, + const GDExtensionInterfaceGetProcAddress p_get_proc_address, const GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization ) { diff --git a/tests/1-gdextension/my.gdextension b/tests/1-gdextension/my.gdextension index c1275f29..289d4284 100644 --- a/tests/1-gdextension/my.gdextension +++ b/tests/1-gdextension/my.gdextension @@ -1,6 +1,7 @@ [configuration] entry_symbol = "my_init" +compatibility_minimum = "4.1" [libraries] diff --git a/tests/2-pythonscript-init/pythonscript.gdextension b/tests/2-pythonscript-init/pythonscript.gdextension index 2feb547c..fc4bd8d0 100644 --- a/tests/2-pythonscript-init/pythonscript.gdextension +++ b/tests/2-pythonscript-init/pythonscript.gdextension @@ -1,6 +1,7 @@ [configuration] entry_symbol = "pythonscript_init" +compatibility_minimum = "4.1" [libraries] diff --git a/tests/3-pythonscript-cython-only/pythonscript.gdextension b/tests/3-pythonscript-cython-only/pythonscript.gdextension index 2feb547c..fc4bd8d0 100755 --- a/tests/3-pythonscript-cython-only/pythonscript.gdextension +++ b/tests/3-pythonscript-cython-only/pythonscript.gdextension @@ -1,6 +1,7 @@ [configuration] entry_symbol = "pythonscript_init" +compatibility_minimum = "4.1" [libraries] diff --git a/tests/run.py b/tests/run.py index bf4f8c64..d5ff34dc 100644 --- a/tests/run.py +++ b/tests/run.py @@ -171,7 +171,7 @@ def run_test( lower_line = line.lower() if b"error" in lower_line or b"warning" in lower_line: raise SystemExit( - f"{RED}{test_name}: stdout/stderr contains logs with error and/or warning ({line}){NO_COLOR}" + f"{RED}{test_name}: stdout/stderr contains logs with error and/or warning ({line!r}){NO_COLOR}" ) print(f"{GREEN}{test_name}: All good \\o/{NO_COLOR}", flush=True) @@ -215,7 +215,7 @@ def run_test( godot_extra_args = sys.argv[options_separator + 1 :] if args.tests: - tests_dirs = [x for x in collect_tests() if x.name in args.tests] + tests_dirs = [x for x in collect_tests() if any((x.name.startswith(t) for t in args.tests))] if not tests_dirs: raise SystemExit( f"No test selected, available tests: {[x.name for x in collect_tests()]}"