Skip to content

Commit

Permalink
Implement plugin creation to godot 4.3 for rc3
Browse files Browse the repository at this point in the history
  • Loading branch information
niklas2902 committed Aug 11, 2024
1 parent 4a3cec5 commit 2ce9f7e
Show file tree
Hide file tree
Showing 20 changed files with 235 additions and 77 deletions.
4 changes: 3 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
example
build
build
plugin
python_files
4 changes: 4 additions & 0 deletions build_resources/python.gdextension
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ compatibility_minimum="4.3.0"

windows.debug.x86_64 = "cpython-3.12.4-windows64/python/install/pythonscript.dll"
windows.release.x86_64 = "cpython-3.12.4-windows64/python/install/pythonscript.dll"
windows.debug.x86 = "cpython-3.12.4-windows32/python/install/pythonscript.dll"
windows.release.x86 = "cpython-3.12.4-windows32/python/install/pythonscript.dll"


linux.debug.x86_64 = "cpython-3.12.4-linux64/python/install/bin/pythonscript.so"
linux.release.x86_64 = "cpython-3.12.4-linux64/python/install/bin/pythonscript.so"
linux.debug.x86 = "cpython-3.12.4-linux32/python/install/bin/pythonscript.so"
linux.release.x86 = "cpython-3.12.4-linux32/python/install/bin/pythonscript.so"
95 changes: 60 additions & 35 deletions create_plugin.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,30 @@
import os
from dataclasses import dataclass
from os import path
import zipfile
from typing import List

import docker
import tarfile
import shutil

@dataclass
class DockerImageContainer:
image_name:str
container_name:str
platform:str
builds:List[DockerImageContainer] = [
DockerImageContainer("linux32_py4godot","py4godot_linux32_container" ,"linux32"),
DockerImageContainer("windows64_py4godot","py4godot_windows64_container" ,"windows64"),
DockerImageContainer("windows32_py4godot","py4godot_windows32_container" ,"windows32"),
DockerImageContainer("linux64_py4godot","py4godot_linux64_container" ,"linux64"),
]

def get_docker_build_name(name):
if name.endswith("64"):
return name[:-2]
return name

def untar_file(tar_file, extract_path):
with tarfile.open(tar_file, 'r') as tar:
tar.extractall(extract_path)
Expand All @@ -16,49 +36,54 @@ def unzip_zip(zip_file, extract_path):
def run_docker():
client = docker.from_env()
client.containers.prune()
client.containers.run(image = "windows_py4godot", name="windows64")
last_container = client.containers.get("windows64")

folder_path = "plugin"
if not os.path.exists(folder_path):
os.makedirs(folder_path)
print(f"Folder '{folder_path}' created.")
else:
print(f"Folder '{folder_path}' already exists.")
f = open('plugin/windows_build.tar', 'wb')

bits, stat = last_container.get_archive('/app/build/final/windows64/cpython-3.12.4-windows64')

print(stat)
for chunk in bits:
f.write(chunk)

f.close()


client.containers.run(image = "linux_py4godot", name="linux64")
last_container = client.containers.get("linux64")
f = open('plugin/linux_build.tar', 'wb')

bits, stat = last_container.get_archive('/app/build/final/linux64/cpython-3.12.4-linux64')


print(stat)
for chunk in bits:
f.write(chunk)

f.close()
for build in builds:
clean_up_image(build, client)
print(f"Running container {build.platform}...")
client.containers.run(image = build.image_name, name=build.platform)
last_container = client.containers.get(build.platform)

folder_path = "plugin"
if not os.path.exists(folder_path):
os.makedirs(folder_path)
print(f"Folder '{folder_path}' created.")
else:
print(f"Folder '{folder_path}' already exists.")
f = open(f'plugin/{build.platform[:-2]}.tar', 'wb')

bits, stat = last_container.get_archive(f'/app/build/final/{build.platform}/cpython-3.12.4-{build.platform}')

print(stat)
for chunk in bits:
f.write(chunk)
f.close()
print("Extracting build to plugin ...")
untar_file(f'plugin/{build.platform[:-2]}.tar', 'plugin/addons/py4godot')
print("Finished extracting")

def clean_up_image(build, client):
try:
print(f"Checking if the image {build.image_name} exists...")
image = client.images.get(build.image_name)
print(f"Image {build.image_name} exists, removing it...")
client.images.remove(image=build.image_name, force=True)
except docker.errors.ImageNotFound:
print(f"Image {build.image_name} does not exist, proceeding...")
print(f"Building Docker image {build.image_name}...")
client.images.build(path=".", dockerfile=f"dockerbuild/{get_docker_build_name(build.platform)}",
tag=build.image_name,
rm=True, # Remove intermediate containers after a successful build
forcerm=True # Always remove intermediate containers even if the build fails
)

untar_file('plugin/windows_build.tar', 'plugin/addons/py4godot')
untar_file('plugin/linux_build.tar', 'plugin/addons/py4godot')

def copy_other_files(folder_path):
shutil.copy("build_resources/plugin.cfg", folder_path+"/plugin.cfg")
shutil.copy("example/addons/py4godot/py4godot.gd", folder_path + "/py4godot.gd")
shutil.copy("build_resources/python.gdextension", folder_path+"/python.gdextension")
shutil.copy("example/addons/py4godot/Python.svg", folder_path + "/Python.svg")
shutil.copy("build_resources/Python.svg", folder_path + "/Python.svg")
with open(folder_path+"/.gitignore", "w") as f:
pass
f.write("*")

if __name__ == "__main__":
run_docker()
Expand Down
19 changes: 19 additions & 0 deletions dockerbuild/linux32
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Use the official Ubuntu base image
FROM ubuntu:22.04

# Set the working directory in the container
WORKDIR /app

# Update the package list and install necessary dependencies
RUN apt-get update && \
apt-get install -y python3 python3-pip

RUN apt-get install gcc-multilib g++-multilib libc6-dev-i386 -y
# Copy the local files into the container at /app
COPY . /app

# Install any additional dependencies using pip, if needed
RUN pip3 install -r requirements.txt
RUN ln -s /usr/bin/python3 /usr/bin/python

CMD ["python3", "build.py", "--target_platform=linux32", "--compiler=gcc", "-run_tests=false", "-download_godot=false"]
32 changes: 32 additions & 0 deletions dockerbuild/windows32
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Use the official Ubuntu base image
FROM ubuntu:22.04

# Set the working directory in the container
WORKDIR /app

# Update the package list and install necessary dependencies
RUN apt-get update && \
apt-get install -y python3 python3-pip mingw-w64 build-essential

# Copy the local files into the container at /app
COPY . /app

# Install any additional dependencies using pip, if needed
RUN pip3 install -r requirements.txt

# Create a symbolic link for python to point to python3
RUN ln -s /usr/bin/python3 /usr/bin/python

# Ensure the correct toolchain is used
RUN ln -sf /usr/bin/i686-w64-mingw32-gcc /usr/bin/gcc-mingw && \
ln -sf /usr/bin/i686-w64-mingw32-g++ /usr/bin/g++-mingw32 && \
ln -sf /usr/bin/i686-w64-mingw32-ld /usr/bin/ld

# Export LD environment variable to ensure 32-bit linker is used
ENV LD=i686-w64-mingw32-ld

# Ensure the correct PATH is set
ENV PATH=/usr/local/bin:$PATH

# Command to execute when the container starts
CMD ["python3", "build.py", "--target_platform=windows32", "--compiler=g++-mingw32", "-run_tests=false", "-download_godot=false"]s
27 changes: 19 additions & 8 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ cc = meson.get_compiler('cpp')
message('system:'+build_machine.system())
message('cpu_familiy:'+build_machine.cpu_family())
platform_format = ''
machine = build_machine.system()
if build_machine.cpu_family()=='x86_64'
machine = host_machine.system()
platform_format='32'
if host_machine.cpu_family()=='x86_64'
platform_format='64'
endif

Expand All @@ -17,12 +18,22 @@ message(meson.get_compiler('cpp').get_id())

link_args = []
if meson.get_compiler('cpp').get_id() == 'gcc'
add_global_arguments('-DMS_WIN64', language : 'cpp')
add_global_arguments('-DMS_WIN'+ platform_format, language : 'cpp')
cpp_args = ['-w', '-D LIBRARY_EXPORTS=1', '-fpermissive', '-g']
if platform_format == '32'
link_args = ['-m32']
#link_args = ['-L/usr/i686-w64-mingw32/lib', '-lmingw32', '-lmingwex']
cpp_args += ['-m32', '-std=c++14']
endif
endif
if meson.get_compiler('cpp').get_id() == 'g++'
add_global_arguments('-DMS_WIN64', language : 'cpp')
add_global_arguments('-DMS_WIN'+platform_format, language : 'cpp')
cpp_args = ['-w', '-D LIBRARY_EXPORTS=1', '-fpermissive' , '-g']
if platform_format == '32'
link_args = ['-m32']
#link_args = ['-L/usr/i686-w64-mingw32/lib', '-lmingw32', '-lmingwex']
cpp_args += ['-m32', '-std=c++14']
endif
endif
if meson.get_compiler('cpp').get_id() == 'msvc'
add_global_arguments('/bigobj', language : 'cpp')
Expand All @@ -45,17 +56,17 @@ if build_machine.system() == 'windows'
'py4godot/pluginscript_api/utils')
glob = run_command('python', files(meson.current_source_dir()+'/meson_scripts/glob_tools.py'))
glob_cpp = run_command('python', files(meson.current_source_dir()+'/meson_scripts/glob_tools_cpp.py'))
main_name = '~main' # This is a weird phenomenon of godot 4.2. It copies the dll and renames it. Thus, we have to change what we depend on to the real dll loaded
endif
if meson.has_external_property('is_mingw') and build_machine.system() == 'linux'
message('using mingw')
lib_py = cc.find_library('python311', dirs:meson.current_source_dir()+'/python_files/cpython-3.12.4-windows64/python/install')
message('dirs:')
message(meson.current_source_dir()+'/python_files/cpython-3.12.4-'+machine+platform_format + '/python/install')
lib_py = cc.find_library('python312', dirs:meson.current_source_dir()+'/python_files/cpython-3.12.4-'+machine+platform_format + '/python/install')
internal_inc = include_directories('py4godot','py4godot/gdextension-api/', 'py4godot/core', 'py4godot/enums',
'py4godot/classes', 'py4godot/pluginscript_api', 'py4godot/godot_bindings',
'py4godot/script_instance', 'py4godot/core/variant4', 'py4godot/cppcore', 'py4godot/cppenums',
'py4godot/cppclasses', 'py4godot/cpputils', 'py4godot/script_language', 'py4godot/pluginscript_api',
'py4godot/pluginscript_api/utils',
'py4godot/instance_data', 'python_files/cpython-3.12.4-windows64/python/install/include')
'py4godot/instance_data', 'python_files/cpython-3.12.4-'+machine+platform_format+'/python/install/include')
glob = run_command('python3', files(meson.current_source_dir()+'/meson_scripts/glob_tools.py'))
glob_cpp = run_command('python3', files(meson.current_source_dir()+'/meson_scripts/glob_tools_cpp.py'))
dep_py = lib_py
Expand Down
12 changes: 6 additions & 6 deletions meson_scripts/copy_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

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


def run(platform):
Expand All @@ -36,11 +36,11 @@ def run(platform):
replace(".dll", ".pyd")) # dst can be a folder; use copy2() to preserve timestamp
else:
os.makedirs(os.path.dirname(
f"build/final/{platform}/{config_data['python_ver']}-{platform}/python/install/lib/python3.11/" + strip_platform(
f"build/final/{platform}/{config_data['python_ver']}-{platform}/python/install/lib/python3.12/site-packages/" + strip_platform(
entry.lstrip("build").replace("#", "/"))),
exist_ok=True)
copy(entry,
f"build/final/{platform}/{config_data['python_ver']}-{platform}/python/install/lib/python3.11/" + strip_platform(
f"build/final/{platform}/{config_data['python_ver']}-{platform}/python/install/lib/python3.12/site-packages/" + strip_platform(
entry.lstrip("build").replace("#", "/")).
replace(".dll", ".pyd")) # dst can be a folder; use copy2() to preserve timestamp

Expand Down Expand Up @@ -103,10 +103,10 @@ def copy_stub_files(platform):
f"build/final/{platform}/{config_data['python_ver']}-{platform}/python/install/Lib/site-packages/" + file)
else:
os.makedirs(os.path.dirname(
f"build/final/{platform}/{config_data['python_ver']}-{platform}/python/install/lib/python3.11/" + file),
f"build/final/{platform}/{config_data['python_ver']}-{platform}/python/install/lib/python3.12/site-packages/" + file),
exist_ok=True)
copy(file,
f"build/final/{platform}/{config_data['python_ver']}-{platform}/python/install/lib/python3.11/" + file)
f"build/final/{platform}/{config_data['python_ver']}-{platform}/python/install/lib/python3.12/site-packages/" + file)


def copy_experimental(platform):
Expand All @@ -117,7 +117,7 @@ def copy_experimental(platform):
f"build/final/{platform}/{config_data['python_ver']}-{platform}/python/install/Lib/site-packages/" + file)
else:
copy(file,
f"build/final/{platform}/{config_data['python_ver']}-{platform}/python/install/lib/python3.11/" + file)
f"build/final/{platform}/{config_data['python_ver']}-{platform}/python/install/lib/python3.12/site-packages/" + file)


def onerror(func, path, exc_info):
Expand Down
30 changes: 21 additions & 9 deletions meson_scripts/download_python.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import pathlib
import zipfile

import wget
import zstandard
import tarfile
import os
from shutil import copytree, ignore_patterns

platform_dict = {"windows64": "x86_64-pc-windows-msvc-shared-pgo", "windows": "i686-pc-windows-msvc-shared-pgo",
"linux64": "x86_64-unknown-linux-gnu-pgo+lto", "linux": "i686-unknown-linux-gnu-pgo"}
platform_dict = {"windows64": "x86_64-pc-windows-msvc-shared-pgo", "windows32": "i686-pc-windows-msvc-shared-pgo",
"linux64": "x86_64-unknown-linux-gnu-pgo+lto"}
python_files_dir = "python_files"
copy_dir = "build/final"
python_ver = "cpython-3.12.4"
Expand All @@ -26,8 +28,13 @@ def download_file(platform, allow_copy=False):

print("download:" + platform)

url = f'https://github.com/indygreg/python-build-standalone/releases/download/20240713/{python_ver}+20240713-{platform_dict[platform]}-full.tar.zst'
python_file = f'{python_files_dir}/{python_ver}-{platform_dict[platform]}.tar.zst'
if platform != "linux32":
url = f'https://github.com/indygreg/python-build-standalone/releases/download/20240713/{python_ver}+20240713-{platform_dict[platform]}-full.tar.zst'
python_file = f'{python_files_dir}/{python_ver}-{platform_dict[platform]}.tar.zst'
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'

export_name = f"{python_ver}-" + platform

if (not os.path.isfile(python_file)): # checking whether file was already downloaded
Expand All @@ -41,7 +48,7 @@ def download_file(platform, allow_copy=False):
decompress_zstandard_to_folder(python_file)
if (not os.path.isdir(python_files_dir + "/" + export_name)): # extracting the files from the tar folder
print("extracting .tar file")
extract_tar(python_file.replace(".zst", ""), export_name)
extract_archive(python_file.replace(".zst", ""), export_name)

if (allow_copy):
create_sitecustomization(export_name, platform)
Expand All @@ -58,12 +65,17 @@ def decompress_zstandard_to_folder(input_file):
decomp.copy_stream(compressed, destination)


def extract_tar(file, export_name):
def extract_archive(file, export_name):
"""function for extracting .tar archieve"""
if (not os.path.isdir(python_files_dir + "/" + export_name)):
my_tar = tarfile.open(file)
my_tar.extractall(python_files_dir + "/" + export_name) # specify which folder to extract to
my_tar.close()
print("File:", file)
if file.endswith("tar"):
my_tar = tarfile.open(file)
my_tar.extractall(python_files_dir + "/" + export_name) # specify which folder to extract to
my_tar.close()
else:
with zipfile.ZipFile(file, 'r') as zip_ref:
zip_ref.extractall(python_files_dir + "/" + export_name)


def copy_to_build(export_folder, platform):
Expand Down
4 changes: 2 additions & 2 deletions meson_scripts/generate_init_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ def create_init_file(platform):
with open(f"{build_folder}/{platform}/{config_data['python_ver']}-{platform}/python/install/Lib/site-packages/py4godot/__init__.py", "w") as init_file:
init_file.write(import_string_py4godot)
else:
with open(f"{build_folder}/{platform}/{config_data['python_ver']}-{platform}/python/install/lib/python3.11/py4godot/{core_folder}/__init__.py", "w") as init_file:
with open(f"{build_folder}/{platform}/{config_data['python_ver']}-{platform}/python/install/lib/python3.12/site-packages/py4godot/{core_folder}/__init__.py", "w") as init_file:
init_file.write(import_string_core)

"""generate the __init__ file needed for the py4godot module"""
with open(f"{build_folder}/{platform}/{config_data['python_ver']}-{platform}/python/install/lib/python3.11/py4godot/__init__.py", "w") as init_file:
with open(f"{build_folder}/{platform}/{config_data['python_ver']}-{platform}/python/install/lib/python3.12/site-packages/py4godot/__init__.py", "w") as init_file:
init_file.write(import_string_py4godot)


Expand Down
5 changes: 5 additions & 0 deletions platforms/compilers/g++-mingw32_compiler.native
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[binaries]
cpp = ['i686-w64-mingw32-g++']

[properties]
is_mingw = true
2 changes: 2 additions & 0 deletions platforms/compilers/g++_compiler.native
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[binaries]
cpp = ['g++']
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 2ce9f7e

Please sign in to comment.