mirror of
https://github.com/godotengine/webrtc-native.git
synced 2025-12-31 01:48:26 +03:00
298 lines
9.6 KiB
Diff
298 lines
9.6 KiB
Diff
diff --git a/godot-cpp/binding_generator.py b/godot-cpp/binding_generator.py
|
|
index 18db9fd..e0c8caf 100644
|
|
--- a/godot-cpp/binding_generator.py
|
|
+++ b/godot-cpp/binding_generator.py
|
|
@@ -72,9 +72,13 @@ def generate_wrappers(target):
|
|
|
|
def get_file_list(api_filepath, output_dir, headers=False, sources=False):
|
|
api = {}
|
|
- files = []
|
|
with open(api_filepath, encoding="utf-8") as api_file:
|
|
api = json.load(api_file)
|
|
+ return _get_file_list(api, output_dir, headers, sources)
|
|
+
|
|
+
|
|
+def _get_file_list(api, output_dir, headers=False, sources=False):
|
|
+ files = []
|
|
|
|
core_gen_folder = Path(output_dir) / "gen" / "include" / "godot_cpp" / "core"
|
|
include_gen_folder = Path(output_dir) / "gen" / "include" / "godot_cpp"
|
|
@@ -158,13 +162,15 @@ def scons_generate_bindings(target, source, env):
|
|
return None
|
|
|
|
|
|
-def generate_bindings(api_filepath, use_template_get_node, bits="64", precision="single", output_dir="."):
|
|
- api = None
|
|
-
|
|
- target_dir = Path(output_dir) / "gen"
|
|
-
|
|
+def _generate_bindings(api_filepath, use_template_get_node, bits="64", precision="single", output_dir="."):
|
|
+ api = {}
|
|
with open(api_filepath, encoding="utf-8") as api_file:
|
|
api = json.load(api_file)
|
|
+ _generate_bindings(api, use_template_get_node, bits, precision, output_dir)
|
|
+
|
|
+
|
|
+def _generate_bindings(api, use_template_get_node, bits="64", precision="single", output_dir="."):
|
|
+ target_dir = Path(output_dir) / "gen"
|
|
|
|
shutil.rmtree(target_dir, ignore_errors=True)
|
|
target_dir.mkdir(parents=True)
|
|
diff --git a/godot-cpp/build_profile.py b/godot-cpp/build_profile.py
|
|
new file mode 100644
|
|
index 0000000..b4d19de
|
|
--- /dev/null
|
|
+++ b/godot-cpp/build_profile.py
|
|
@@ -0,0 +1,183 @@
|
|
+import json
|
|
+import sys
|
|
+
|
|
+
|
|
+def parse_build_profile(profile_filepath, api):
|
|
+ if profile_filepath == "":
|
|
+ return {}
|
|
+
|
|
+ with open(profile_filepath, encoding="utf-8") as profile_file:
|
|
+ profile = json.load(profile_file)
|
|
+
|
|
+ api_dict = {}
|
|
+ parents = {}
|
|
+ children = {}
|
|
+ for engine_class in api["classes"]:
|
|
+ api_dict[engine_class["name"]] = engine_class
|
|
+ parent = engine_class.get("inherits", "")
|
|
+ child = engine_class["name"]
|
|
+ parents[child] = parent
|
|
+ if parent == "":
|
|
+ continue
|
|
+ children[parent] = children.get(parent, [])
|
|
+ children[parent].append(child)
|
|
+
|
|
+ included = []
|
|
+ front = list(profile.get("enabled_classes", []))
|
|
+ if front:
|
|
+ # These must always be included
|
|
+ front.append("WorkerThreadPool")
|
|
+ front.append("ClassDB")
|
|
+ front.append("ClassDBSingleton")
|
|
+ # In src/classes/low_level.cpp
|
|
+ front.append("FileAccess")
|
|
+ front.append("Image")
|
|
+ front.append("XMLParser")
|
|
+ # In include/godot_cpp/templates/thread_work_pool.hpp
|
|
+ front.append("Semaphore")
|
|
+ while front:
|
|
+ cls = front.pop()
|
|
+ if cls in included:
|
|
+ continue
|
|
+ included.append(cls)
|
|
+ parent = parents.get(cls, "")
|
|
+ if parent:
|
|
+ front.append(parent)
|
|
+
|
|
+ excluded = []
|
|
+ front = list(profile.get("disabled_classes", []))
|
|
+ while front:
|
|
+ cls = front.pop()
|
|
+ if cls in excluded:
|
|
+ continue
|
|
+ excluded.append(cls)
|
|
+ front += children.get(cls, [])
|
|
+
|
|
+ if included and excluded:
|
|
+ print(
|
|
+ "WARNING: Cannot specify both 'enabled_classes' and 'disabled_classes' in build profile. 'disabled_classes' will be ignored."
|
|
+ )
|
|
+
|
|
+ return {
|
|
+ "enabled_classes": included,
|
|
+ "disabled_classes": excluded,
|
|
+ }
|
|
+
|
|
+
|
|
+def generate_trimmed_api(source_api_filepath, profile_filepath):
|
|
+ with open(source_api_filepath, encoding="utf-8") as api_file:
|
|
+ api = json.load(api_file)
|
|
+
|
|
+ if profile_filepath == "":
|
|
+ return api
|
|
+
|
|
+ build_profile = parse_build_profile(profile_filepath, api)
|
|
+
|
|
+ engine_classes = {}
|
|
+ for class_api in api["classes"]:
|
|
+ engine_classes[class_api["name"]] = class_api["is_refcounted"]
|
|
+ for native_struct in api["native_structures"]:
|
|
+ if native_struct["name"] == "ObjectID":
|
|
+ continue
|
|
+ engine_classes[native_struct["name"]] = False
|
|
+
|
|
+ classes = []
|
|
+ for class_api in api["classes"]:
|
|
+ if not is_class_included(class_api["name"], build_profile):
|
|
+ continue
|
|
+ if "methods" in class_api:
|
|
+ methods = []
|
|
+ for method in class_api["methods"]:
|
|
+ if not is_method_included(method, build_profile, engine_classes):
|
|
+ continue
|
|
+ methods.append(method)
|
|
+ class_api["methods"] = methods
|
|
+ classes.append(class_api)
|
|
+ api["classes"] = classes
|
|
+
|
|
+ return api
|
|
+
|
|
+
|
|
+def is_class_included(class_name, build_profile):
|
|
+ """
|
|
+ Check if an engine class should be included.
|
|
+ This removes classes according to a build profile of enabled or disabled classes.
|
|
+ """
|
|
+ included = build_profile.get("enabled_classes", [])
|
|
+ excluded = build_profile.get("disabled_classes", [])
|
|
+ if included:
|
|
+ return class_name in included
|
|
+ if excluded:
|
|
+ return class_name not in excluded
|
|
+ return True
|
|
+
|
|
+
|
|
+def is_method_included(method, build_profile, engine_classes):
|
|
+ """
|
|
+ Check if an engine class method should be included.
|
|
+ This removes methods according to a build profile of enabled or disabled classes.
|
|
+ """
|
|
+ included = build_profile.get("enabled_classes", [])
|
|
+ excluded = build_profile.get("disabled_classes", [])
|
|
+ ref_cls = set()
|
|
+ rtype = get_base_type(method.get("return_value", {}).get("type", ""))
|
|
+ args = [get_base_type(a["type"]) for a in method.get("arguments", [])]
|
|
+ if rtype in engine_classes:
|
|
+ ref_cls.add(rtype)
|
|
+ elif is_enum(rtype) and get_enum_class(rtype) in engine_classes:
|
|
+ ref_cls.add(get_enum_class(rtype))
|
|
+ for arg in args:
|
|
+ if arg in engine_classes:
|
|
+ ref_cls.add(arg)
|
|
+ elif is_enum(arg) and get_enum_class(arg) in engine_classes:
|
|
+ ref_cls.add(get_enum_class(arg))
|
|
+ for acls in ref_cls:
|
|
+ if len(included) > 0 and acls not in included:
|
|
+ return False
|
|
+ elif len(excluded) > 0 and acls in excluded:
|
|
+ return False
|
|
+ return True
|
|
+
|
|
+
|
|
+def is_enum(type_name):
|
|
+ return type_name.startswith("enum::") or type_name.startswith("bitfield::")
|
|
+
|
|
+
|
|
+def get_enum_class(enum_name: str):
|
|
+ if "." in enum_name:
|
|
+ if is_bitfield(enum_name):
|
|
+ return enum_name.replace("bitfield::", "").split(".")[0]
|
|
+ else:
|
|
+ return enum_name.replace("enum::", "").split(".")[0]
|
|
+ else:
|
|
+ return "GlobalConstants"
|
|
+
|
|
+
|
|
+def get_base_type(type_name):
|
|
+ if type_name.startswith("const "):
|
|
+ type_name = type_name[6:]
|
|
+ if type_name.endswith("*"):
|
|
+ type_name = type_name[:-1]
|
|
+ if type_name.startswith("typedarray::"):
|
|
+ type_name = type_name.replace("typedarray::", "")
|
|
+ return type_name
|
|
+
|
|
+
|
|
+def is_bitfield(type_name):
|
|
+ return type_name.startswith("bitfield::")
|
|
+
|
|
+
|
|
+if __name__ == "__main__":
|
|
+ if len(sys.argv) < 3 or len(sys.argv) > 4:
|
|
+ print("Usage: %s BUILD_PROFILE INPUT_JSON [OUTPUT_JSON]" % (sys.argv[0]))
|
|
+ sys.exit(1)
|
|
+ profile = sys.argv[1]
|
|
+ infile = sys.argv[2]
|
|
+ outfile = sys.argv[3] if len(sys.argv) > 3 else ""
|
|
+ api = generate_trimmed_api(infile, profile)
|
|
+
|
|
+ if outfile:
|
|
+ with open(outfile, "w", encoding="utf-8") as f:
|
|
+ json.dump(api, f)
|
|
+ else:
|
|
+ json.dump(api, sys.stdout)
|
|
diff --git a/godot-cpp/tools/godotcpp.py b/godot-cpp/tools/godotcpp.py
|
|
index efe632a..993aa81 100644
|
|
--- a/godot-cpp/tools/godotcpp.py
|
|
+++ b/godot-cpp/tools/godotcpp.py
|
|
@@ -5,7 +5,8 @@ from SCons.Tool import Tool
|
|
from SCons.Builder import Builder
|
|
from SCons.Errors import UserError
|
|
|
|
-from binding_generator import scons_generate_bindings, scons_emit_files
|
|
+from binding_generator import _generate_bindings, _get_file_list, get_file_list
|
|
+from build_profile import generate_trimmed_api
|
|
|
|
|
|
def add_sources(sources, dir, extension):
|
|
@@ -14,6 +15,37 @@ def add_sources(sources, dir, extension):
|
|
sources.append(dir + "/" + f)
|
|
|
|
|
|
+def scons_emit_files(target, source, env):
|
|
+ profile_filepath = env.get("build_profile", "")
|
|
+ if profile_filepath:
|
|
+ profile_filepath = normalize_path(profile_filepath, env)
|
|
+
|
|
+ # Always clean all files
|
|
+ env.Clean(target, [env.File(f) for f in get_file_list(str(source[0]), target[0].abspath, True, True)])
|
|
+
|
|
+ api = generate_trimmed_api(str(source[0]), profile_filepath)
|
|
+ files = [env.File(f) for f in _get_file_list(api, target[0].abspath, True, True)]
|
|
+ env["godot_cpp_gen_dir"] = target[0].abspath
|
|
+ return files, source
|
|
+
|
|
+
|
|
+def scons_generate_bindings(target, source, env):
|
|
+ profile_filepath = env.get("build_profile", "")
|
|
+ if profile_filepath:
|
|
+ profile_filepath = normalize_path(profile_filepath, env)
|
|
+
|
|
+ api = generate_trimmed_api(str(source[0]), profile_filepath)
|
|
+
|
|
+ _generate_bindings(
|
|
+ api,
|
|
+ env["generate_template_get_node"],
|
|
+ "32" if "32" in env["arch"] else "64",
|
|
+ env["precision"],
|
|
+ env["godot_cpp_gen_dir"],
|
|
+ )
|
|
+ return None
|
|
+
|
|
+
|
|
def normalize_path(val, env):
|
|
return val if os.path.isabs(val) else os.path.join(env.Dir("#").abspath, val)
|
|
|
|
@@ -175,6 +207,15 @@ def options(opts, env):
|
|
)
|
|
)
|
|
|
|
+ opts.Add(
|
|
+ PathVariable(
|
|
+ "build_profile",
|
|
+ "Path to a file containing a feature build profile",
|
|
+ default=env.get("build_profile", None),
|
|
+ validator=validate_file,
|
|
+ )
|
|
+ )
|
|
+
|
|
opts.Add(
|
|
BoolVariable(
|
|
"disable_exceptions",
|