Skip to content

Commit 528b780

Browse files
Falessdsnopek
authored andcommitted
Add support for build profiles.
Allow enabling or disabling specific classes (which will not be built). (cherry picked from commit 1186c48)
1 parent 9da6ecd commit 528b780

File tree

3 files changed

+132
-5
lines changed

3 files changed

+132
-5
lines changed

binding_generator.py

Lines changed: 114 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,14 @@ def generate_wrappers(target):
7070
f.write(txt)
7171

7272

73-
def get_file_list(api_filepath, output_dir, headers=False, sources=False):
73+
def get_file_list(api_filepath, output_dir, headers=False, sources=False, profile_filepath=""):
7474
api = {}
7575
files = []
7676
with open(api_filepath, encoding="utf-8") as api_file:
7777
api = json.load(api_file)
7878

79+
build_profile = parse_build_profile(profile_filepath, api)
80+
7981
core_gen_folder = Path(output_dir) / "gen" / "include" / "godot_cpp" / "core"
8082
include_gen_folder = Path(output_dir) / "gen" / "include" / "godot_cpp"
8183
source_gen_folder = Path(output_dir) / "gen" / "src"
@@ -105,7 +107,7 @@ def get_file_list(api_filepath, output_dir, headers=False, sources=False):
105107
source_filename = source_gen_folder / "classes" / (camel_to_snake(engine_class["name"]) + ".cpp")
106108
if headers:
107109
files.append(str(header_filename.as_posix()))
108-
if sources:
110+
if sources and is_class_included(engine_class["name"], build_profile):
109111
files.append(str(source_filename.as_posix()))
110112

111113
for native_struct in api["native_structures"]:
@@ -137,12 +139,105 @@ def get_file_list(api_filepath, output_dir, headers=False, sources=False):
137139
return files
138140

139141

140-
def print_file_list(api_filepath, output_dir, headers=False, sources=False):
141-
print(*get_file_list(api_filepath, output_dir, headers, sources), sep=";", end=None)
142+
def print_file_list(api_filepath, output_dir, headers=False, sources=False, profile_filepath=""):
143+
print(*get_file_list(api_filepath, output_dir, headers, sources, profile_filepath), sep=";", end=None)
144+
145+
146+
def parse_build_profile(profile_filepath, api):
147+
if profile_filepath == "":
148+
return {}
149+
print("Using feature build profile: " + profile_filepath)
150+
151+
with open(profile_filepath, encoding="utf-8") as profile_file:
152+
profile = json.load(profile_file)
153+
154+
api_dict = {}
155+
parents = {}
156+
children = {}
157+
for engine_class in api["classes"]:
158+
api_dict[engine_class["name"]] = engine_class
159+
parent = engine_class.get("inherits", "")
160+
child = engine_class["name"]
161+
parents[child] = parent
162+
if parent == "":
163+
continue
164+
children[parent] = children.get(parent, [])
165+
children[parent].append(child)
166+
167+
# Parse methods dependencies
168+
deps = {}
169+
reverse_deps = {}
170+
for name, engine_class in api_dict.items():
171+
ref_cls = set()
172+
for method in engine_class.get("methods", []):
173+
rtype = method.get("return_value", {}).get("type", "")
174+
args = [a["type"] for a in method.get("arguments", [])]
175+
if rtype in api_dict:
176+
ref_cls.add(rtype)
177+
elif is_enum(rtype) and get_enum_class(rtype) in api_dict:
178+
ref_cls.add(get_enum_class(rtype))
179+
for arg in args:
180+
if arg in api_dict:
181+
ref_cls.add(arg)
182+
elif is_enum(arg) and get_enum_class(arg) in api_dict:
183+
ref_cls.add(get_enum_class(arg))
184+
deps[engine_class["name"]] = set(filter(lambda x: x != name, ref_cls))
185+
for acls in ref_cls:
186+
if acls == name:
187+
continue
188+
reverse_deps[acls] = reverse_deps.get(acls, set())
189+
reverse_deps[acls].add(name)
190+
191+
included = []
192+
front = list(profile.get("enabled_classes", []))
193+
if front:
194+
# These must always be included
195+
front.append("WorkerThreadPool")
196+
front.append("ClassDB")
197+
front.append("ClassDBSingleton")
198+
while front:
199+
cls = front.pop()
200+
if cls in included:
201+
continue
202+
included.append(cls)
203+
parent = parents.get(cls, "")
204+
if parent:
205+
front.append(parent)
206+
for rcls in deps.get(cls, set()):
207+
if rcls in included or rcls in front:
208+
continue
209+
front.append(rcls)
210+
211+
excluded = []
212+
front = list(profile.get("disabled_classes", []))
213+
while front:
214+
cls = front.pop()
215+
if cls in excluded:
216+
continue
217+
excluded.append(cls)
218+
front += children.get(cls, [])
219+
for rcls in reverse_deps.get(cls, set()):
220+
if rcls in excluded or rcls in front:
221+
continue
222+
front.append(rcls)
223+
224+
if included and excluded:
225+
print(
226+
"WARNING: Cannot specify both 'enabled_classes' and 'disabled_classes' in build profile. 'disabled_classes' will be ignored."
227+
)
228+
229+
return {
230+
"enabled_classes": included,
231+
"disabled_classes": excluded,
232+
}
142233

143234

144235
def scons_emit_files(target, source, env):
145-
files = [env.File(f) for f in get_file_list(str(source[0]), target[0].abspath, True, True)]
236+
profile_filepath = env.get("build_profile", "")
237+
if profile_filepath and not Path(profile_filepath).is_absolute():
238+
profile_filepath = str((Path(env.Dir("#").abspath) / profile_filepath).as_posix())
239+
240+
files = [env.File(f) for f in get_file_list(str(source[0]), target[0].abspath, True, True, profile_filepath)]
146241
env.Clean(target, files)
147242
env["godot_cpp_gen_dir"] = target[0].abspath
148243
return files, source
@@ -2411,6 +2506,20 @@ def is_refcounted(type_name):
24112506
return type_name in engine_classes and engine_classes[type_name]
24122507

24132508

2509+
def is_class_included(class_name, build_profile):
2510+
"""
2511+
Check if an engine class should be included.
2512+
This removes classes according to a build profile of enabled or disabled classes.
2513+
"""
2514+
included = build_profile.get("enabled_classes", [])
2515+
excluded = build_profile.get("disabled_classes", [])
2516+
if included:
2517+
return class_name in included
2518+
if excluded:
2519+
return class_name not in excluded
2520+
return True
2521+
2522+
24142523
def is_included(type_name, current_type):
24152524
"""
24162525
Check if a builtin type should be included.

test/build_profile.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"enabled_classes": [
3+
"Control",
4+
"Label",
5+
"OS",
6+
"TileMap",
7+
"InputEventKey"
8+
]
9+
}

tools/godotcpp.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,15 @@ def options(opts, env):
283283
)
284284
)
285285

286+
opts.Add(
287+
PathVariable(
288+
"build_profile",
289+
"Path to a file containing a feature build profile",
290+
default=env.get("build_profile", None),
291+
validator=validate_file,
292+
)
293+
)
294+
286295
opts.Add(
287296
BoolVariable(
288297
key="use_hot_reload",

0 commit comments

Comments
 (0)