Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
63 changes: 46 additions & 17 deletions binding_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,14 @@ def generate_bindings(


def _generate_bindings(
api, api_filepath, interface_filepath, use_template_get_node, bits="64", precision="single", output_dir="."
api,
api_filepath,
interface_filepath,
use_template_get_node,
bits="64",
precision="single",
output_dir=".",
hooks=None,
):
if "precision" in api["header"] and precision != api["header"]["precision"]:
raise Exception(
Expand All @@ -318,12 +325,12 @@ def _generate_bindings(

generate_gdextension_interface_loader(interface_filepath, target_dir)

generate_global_constants(api, target_dir)
generate_global_constants(api, target_dir, hooks)
generate_version_header(api, target_dir)
generate_global_constant_binds(api, target_dir)
generate_builtin_bindings(api, target_dir, real_t + "_" + bits)
generate_engine_classes_bindings(api, target_dir, use_template_get_node)
generate_utility_functions(api, target_dir)
generate_builtin_bindings(api, target_dir, real_t + "_" + bits, hooks)
generate_engine_classes_bindings(api, target_dir, use_template_get_node, hooks)
generate_utility_functions(api, target_dir, hooks)


def generate_gdextension_interface_loader(interface_filepath, output_dir):
Expand Down Expand Up @@ -502,7 +509,7 @@ def generate_gdextension_interface_loader_source(data):
singletons = []


def generate_builtin_bindings(api, output_dir, build_config):
def generate_builtin_bindings(api, output_dir, build_config, hooks=None):
global builtin_classes

core_gen_folder = Path(output_dir) / "include" / "godot_cpp" / "core"
Expand Down Expand Up @@ -606,10 +613,10 @@ def generate_builtin_bindings(api, output_dir, build_config):
fully_used_classes.sort()

with header_filename.open("w+", encoding="utf-8") as header_file:
header_file.write(generate_builtin_class_header(builtin_api, size, used_classes, fully_used_classes))
header_file.write(generate_builtin_class_header(builtin_api, size, used_classes, fully_used_classes, hooks))

with source_filename.open("w+", encoding="utf-8") as source_file:
source_file.write(generate_builtin_class_source(builtin_api, size, used_classes, fully_used_classes))
source_file.write(generate_builtin_class_source(builtin_api, size, used_classes, fully_used_classes, hooks))

# Create a header with all builtin types for convenience.
builtin_header_filename = include_gen_folder / "builtin_types.hpp"
Expand Down Expand Up @@ -685,7 +692,7 @@ def generate_builtin_class_vararg_method_implements_header(builtin_classes):
return "\n".join(result)


def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_classes):
def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_classes, hooks=None):
result = []

class_name = builtin_api["name"]
Expand Down Expand Up @@ -1175,10 +1182,13 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl

result.append("")

if hooks:
result = hooks.alter_builtin_class_header(builtin_api, result)

return "\n".join(result)


def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_classes):
def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_classes, hooks=None):
result = []

class_name = builtin_api["name"]
Expand Down Expand Up @@ -1490,10 +1500,13 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl
result.append("} //namespace godot")
result.append("")

if hooks:
result = hooks.alter_builtin_class_source(builtin_api, result)

return "\n".join(result)


def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
def generate_engine_classes_bindings(api, output_dir, use_template_get_node, hooks=None):
global engine_classes
global singletons
global native_structures
Expand Down Expand Up @@ -1685,12 +1698,12 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node):

with header_filename.open("w+", encoding="utf-8") as header_file:
header_file.write(
generate_engine_class_header(class_api, used_classes, fully_used_classes, use_template_get_node)
generate_engine_class_header(class_api, used_classes, fully_used_classes, use_template_get_node, hooks)
)

with source_filename.open("w+", encoding="utf-8") as source_file:
source_file.write(
generate_engine_class_source(class_api, used_classes, fully_used_classes, use_template_get_node)
generate_engine_class_source(class_api, used_classes, fully_used_classes, use_template_get_node, hooks)
)

for native_struct in api["native_structures"]:
Expand Down Expand Up @@ -1749,7 +1762,7 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
header_file.write("\n".join(result))


def generate_engine_class_header(class_api, used_classes, fully_used_classes, use_template_get_node):
def generate_engine_class_header(class_api, used_classes, fully_used_classes, use_template_get_node, hooks):
global singletons
result = []

Expand Down Expand Up @@ -2068,10 +2081,13 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us

result.append("")

if hooks:
result = hooks.alter_engine_class_header(class_api, result)

return "\n".join(result)


def generate_engine_class_source(class_api, used_classes, fully_used_classes, use_template_get_node):
def generate_engine_class_source(class_api, used_classes, fully_used_classes, use_template_get_node, hooks=None):
global singletons
result = []

Expand Down Expand Up @@ -2246,10 +2262,13 @@ def generate_engine_class_source(class_api, used_classes, fully_used_classes, us
result.append("} // namespace godot")
result.append("")

if hooks:
result = hooks.alter_engine_class_source(class_api, result)

return "\n".join(result)


def generate_global_constants(api, output_dir):
def generate_global_constants(api, output_dir, hooks=None):
include_gen_folder = Path(output_dir) / "include" / "godot_cpp" / "classes"
source_gen_folder = Path(output_dir) / "src" / "classes"

Expand Down Expand Up @@ -2310,6 +2329,9 @@ def generate_global_constants(api, output_dir):

header.append("")

if hooks:
header = hooks.alter_global_constants(api, header)

with header_filename.open("w+", encoding="utf-8") as header_file:
header_file.write("\n".join(header))

Expand Down Expand Up @@ -2376,7 +2398,7 @@ def generate_global_constant_binds(api, output_dir):
header_file.write("\n".join(header))


def generate_utility_functions(api, output_dir):
def generate_utility_functions(api, output_dir, hooks=None):
include_gen_folder = Path(output_dir) / "include" / "godot_cpp" / "variant"
source_gen_folder = Path(output_dir) / "src" / "variant"

Expand Down Expand Up @@ -2430,6 +2452,9 @@ def generate_utility_functions(api, output_dir):
header.append("} // namespace godot")
header.append("")

if hooks:
header = hooks.alter_utility_functions_header(api, header)

with header_filename.open("w+", encoding="utf-8") as header_file:
header_file.write("\n".join(header))

Expand Down Expand Up @@ -2509,6 +2534,10 @@ def generate_utility_functions(api, output_dir):
source.append("")

source.append("} // namespace godot")
source.append("")

if hooks:
header = hooks.alter_utility_functions_source(api, source)

with source_filename.open("w+", encoding="utf-8") as source_file:
source_file.write("\n".join(source))
Expand Down
23 changes: 23 additions & 0 deletions binding_generator_hooks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
class BindingGeneratorHooks:
def alter_engine_class_header(self, class_api, lines):
return lines

def alter_engine_class_source(self, class_api, lines):
return lines

def alter_global_constants(self, api, lines):
return lines

def alter_utility_functions_header(self, api, lines):
return lines

def alter_utility_functions_source(self, api, lines):
return lines

def alter_builtin_class_header(self, builtin_api, lines):
return lines

def alter_builtin_class_source(self, builtin_api, lines):
return lines

# and more...
19 changes: 19 additions & 0 deletions custom_generator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from binding_generator_hooks import BindingGeneratorHooks


class BindingGeneratorHooksExtension(BindingGeneratorHooks):
def alter_engine_class_header(self, class_api, lines):
signals = []
if "signals" in class_api:
for signal_api in class_api["signals"]:
name = signal_api["name"]
signal_constant = "\tstatic constexpr char SIGNAL_" + name.upper() + '[] = "' + name + '";'
signals.append(signal_constant)
try:
idx = lines.index("public:") + 1
for signal_const in signals:
lines.insert(idx, signal_const)
idx += 1
except ValueError:
print("no public keyword found, not adding signals")
return lines
23 changes: 23 additions & 0 deletions tools/godotcpp.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import importlib.util
import os
import platform
import sys
Expand All @@ -13,6 +14,7 @@
from SCons.Variables.BoolVariable import _text2bool

from binding_generator import _generate_bindings, _get_file_list, get_file_list
from binding_generator_hooks import BindingGeneratorHooks
from build_profile import generate_trimmed_api
from doc_source_generator import scons_generate_doc_source

Expand Down Expand Up @@ -164,6 +166,17 @@ def scons_generate_bindings(target, source, env):

api = generate_trimmed_api(str(source[0]), profile_filepath)

custom_hooks: BindingGeneratorHooks = None
if "binding_hook_file" in env:
binding_hook_file = env["binding_hook_file"]
# yes apparently this is how you import a file dynamically ._.
spec = importlib.util.spec_from_file_location("custom_binding_generator", binding_hook_file)
loaded_module = importlib.util.module_from_spec(spec)
sys.modules["custom_binding_generator"] = loaded_module
spec.loader.exec_module(loaded_module)
# assume the name 'BindingGeneratorHooksExtension' for the class
custom_hooks = loaded_module.BindingGeneratorHooksExtension()

_generate_bindings(
api,
str(source[0]),
Expand All @@ -172,6 +185,7 @@ def scons_generate_bindings(target, source, env):
"32" if "32" in env["arch"] else "64",
env["precision"],
env["godot_cpp_gen_dir"],
custom_hooks,
)
return None

Expand Down Expand Up @@ -230,6 +244,15 @@ def options(opts, env):
else:
raise ValueError("Could not detect platform automatically, please specify with platform=<platform>")

opts.Add(
PathVariable(
key="binding_hook_file",
help="Path to python file containing custom binding generator hooks",
default=env.get("binding_hook_file", None),
validator=validate_file,
)
)

opts.Add(
PathVariable(
key="custom_tools",
Expand Down