Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions meson_scripts/copy_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@

def strip_platform(text):
text = text[1:]
return text.lstrip("linux64").lstrip("windows64").lstrip("windows32").lstrip("linux32").lstrip("darwin64")

return text.lstrip("linux64").lstrip("windows64").lstrip("windows32").lstrip("linux32").lstrip("darwin64").lstrip("linuxarm64").lstrip("windowsarm64")

def run(platform):
# copying all the files from build to the folder of the addon
Expand Down
2 changes: 1 addition & 1 deletion meson_scripts/download_python.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

platform_dict = {"windows64": "x86_64-pc-windows-msvc-install_only_stripped", "windows32": "i686-pc-windows-msvc-install_only_stripped",
"linux64": "x86_64-unknown-linux-gnu-install_only_stripped", "darwin64":"aarch64-apple-darwin-install_only_stripped",
"linuxarm64":"armv7-unknown-linux-gnueabi-install_only_stripped"}
"linuxarm64":"armv7-unknown-linux-gnueabi-install_only_stripped", "windowsarm64":"aarch64-pc-windows-msvc-install_only_stripped"}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file does not exist yet, the version is in process: astral-sh/python-build-standalone#387

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, thank you very much for investigating it. I finally got it working by using the interpreter from nuget. and uploading it to my repo here: prebuilt-windowsarm64

Like this, i needed to adapt download_file like this:

    if platform != "linux32" and platform != "linux64" and platform != "windowsarm64":
        url = f'https://github.com/indygreg/python-build-standalone/releases/download/20240726/{python_ver}+20240726-{platform_dict[platform]}.tar.gz'
        python_file = f'{python_files_dir}/{python_ver}-{platform_dict[platform]}.tar.gz'
    elif platform == "linux64":
        url = f'https://github.com/niklas2902/prebuild-python-linux64/releases/download/release-0.1/{python_ver}-linux64.zip'
        python_file = f'{python_files_dir}/{python_ver}-linux64.zip'
    elif platform == "windowsarm64":
        url = f'https://github.com/niklas2902/prebuilt-windowsarm64/releases/download/release-0.1/{python_ver}-windowsarm64.zip'
        python_file = f'{python_files_dir}/{python_ver}-windowsarm64.zip'
    else :
        url = f'https://github.com/niklas2902/prebuild-python-linux32/releases/download/release-0.1/{python_ver}-linux32.zip'
        python_file = f'{python_files_dir}/{python_ver}-linux32.zip'

Copy link
Author

@gr3vios gr3vios Jun 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@niklas2902 Thanks for the implementation details and the NuGet-based approach - that's a solid solution for the ARM64 Python dependency issue.

I've implemented your suggested download_file() modification and the MSVC ARM64 build changes. I went with a simpler approach for the MSVC configuration compared to your winarm64 branch - just the essential x64_arm64 targeting. Let me know if you'd prefer the more robust Visual Studio detection approach from your branch.

Also added the remaining pieces needed for complete Windows ARM64 support (library entries, cross-compilation config).

I merged with the latest master and resolved conflicts, but would appreciate validation of the conflict resolutions.

Ready for your review when convenient.

python_files_dir = "python_files"
copy_dir = "build/final"
python_ver = "cpython-3.12.4"
Expand Down
15 changes: 13 additions & 2 deletions meson_scripts/platform_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,16 @@
import platform

def get_platform():
"""Determining the current platform"""
return platform.system().lower()+("64" if struct.calcsize("P")*8 == 64 else "")
"""Return 'windows64' for Windows x86_64, 'windowsarm64' for Windows ARM64"""
system = platform.system().lower()
arch = platform.machine().lower()

if system == "windows":
if arch in ("aarch64", "arm64"):
return "windowsarm64"
elif struct.calcsize("P") * 8 == 64:
return "windows64"

# Fallback for other systems if needed
return f"{system}{struct.calcsize('P') * 8}"

13 changes: 13 additions & 0 deletions platforms/windowsarm64.cross
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[binaries]
ar = 'ar'
strip = 'strip'
exe_wrapper = '' # Empty unless you need to run ARM64 binaries on a different host.

[host_machine]
system = 'windows'
cpu_family = 'aarch64'
cpu = 'aarch64'
endian = 'little'

[properties]
current_platform = 'Windows'
6 changes: 5 additions & 1 deletion py4godot/godot_bindings/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
#include "Python.h"


#ifdef _WIN64
#if defined(_WIN64) && defined(_M_ARM64)
#define PYTHONHOME L"addons/py4godot/cpython-3.12.4-windowsarm64/python"
#define PYTHONPATH "addons/py4godot/cpython-3.12.4-windowsarm64/python/Lib/site-packages"

#elif defined(_WIN64)
#define PYTHONHOME L"addons/py4godot/cpython-3.12.4-windows64/python"
#define PYTHONPATH "addons/py4godot/cpython-3.12.4-windows64/python/Lib/site-packages"

Expand Down
80 changes: 49 additions & 31 deletions py4godot/godot_bindings/pythonscript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,64 +3,82 @@

#if defined(__linux__) || defined(__APPLE__)
#include <iostream>
#include <dlfcn.h> // For dlopen, dlsym, dlclose on Linux
#include <dlfcn.h> // For dlopen, dlsym, dlclose on Linux/macOS
#elif defined(_WIN32) || defined(_WIN64)
#include <iostream>
#include <windows.h> // For LoadLibrary, GetProcAddress, FreeLibrary on Windows
#endif

typedef GDExtensionBool (*Py4GodotInitFunc)(GDExtensionInterfaceGetProcAddress p_get_proc_address,
GDExtensionClassLibraryPtr p_library,
GDExtensionInitialization *r_initialization);

std::string get_library_path() {
#if defined(__linux__)
return "addons/py4godot/cpython-3.12.4-linux64/python/bin/main.so";
#elif defined(__APPLE__)
return "addons/py4godot/cpython-3.12.4-darwin64/python/bin/main.dylib";
#elif defined(_WIN32) || defined(_WIN64)
#if defined(_M_ARM64)
return "addons\\py4godot\\cpython-3.12.4-windowsarm64\\python\\main.dll";
#else
return "addons\\py4godot\\cpython-3.12.4-windows64\\python\\main.dll";
#endif
#else
return ""; // Unsupported platform
#endif
}

extern "C" {
// Entry point for initializing Python script extension
GDExtensionBool GDN_EXPORT initialize_pythonscript(GDExtensionInterfaceGetProcAddress p_get_proc_address,
GDExtensionClassLibraryPtr p_library,
GDExtensionInitialization *r_initialization) {

#if defined(__linux__)
// Load the shared library on Linux
void* handle = dlopen("addons/py4godot/cpython-3.12.4-linux64/python/bin/main.so", RTLD_NOW | RTLD_GLOBAL);
#elif defined(__APPLE__)
// Load the shared library on macOS
void* handle = dlopen("addons/py4godot/cpython-3.12.4-darwin64/python/bin/main.dylib", RTLD_NOW | RTLD_GLOBAL);
#endif
std::string library_path = get_library_path();
if (library_path.empty()) {
std::cerr << "Unsupported platform or architecture." << std::endl;
return 1;
}

#if defined(__linux__) || defined(__APPLE__)
void* handle = dlopen(library_path.c_str(), RTLD_NOW | RTLD_GLOBAL);
if (!handle) {
std::cerr << "Cannot load library: " << dlerror() << std::endl;
return 1;
}

// Clear any existing errors
dlerror();

// Load the py4godot_init symbol
Py4GodotInitFunc load_function_handle = (Py4GodotInitFunc) dlsym(handle, "py4godot_init");

// Check for dlsym errors
dlerror(); // Clear any existing errors
Py4GodotInitFunc load_function_handle = (Py4GodotInitFunc)dlsym(handle, "py4godot_init");
const char* dlsym_error = dlerror();
if (dlsym_error) {
std::cerr << "Cannot load symbol 'py4godot_init': " << dlsym_error << std::endl;
dlclose(handle); // Close the library before exiting
dlclose(handle);
return 1;
}

// Call the loaded function
int result = load_function_handle(p_get_proc_address, p_library, r_initialization);

// Close the library handle only on linux (crash on macos)
#if defined(__linux__)
// dlclose(handle);
// Uncomment if safe to close the library on Linux
// dlclose(handle);
#endif
return result;

#endif
#ifdef _WIN64
// Direct call on Windows, where dynamic linking is handled differently
py4godot_init(p_get_proc_address, p_library, r_initialization);
return 1;
#endif

}
}
#elif defined(_WIN32) || defined(_WIN64)
HMODULE handle = LoadLibraryA(library_path.c_str());
if (!handle) {
std::cerr << "Cannot load library: " << GetLastError() << std::endl;
return 1;
}

Py4GodotInitFunc load_function_handle = (Py4GodotInitFunc)GetProcAddress(handle, "py4godot_init");
if (!load_function_handle) {
std::cerr << "Cannot load symbol 'py4godot_init': " << GetLastError() << std::endl;
FreeLibrary(handle);
return 1;
}

int result = load_function_handle(p_get_proc_address, p_library, r_initialization);
// Keep the library loaded for the application's lifetime
return result;
#endif
}
}