mirror of https://github.com/PrimeDecomp/prime.git
Merge branch 'link-order'
This commit is contained in:
commit
76ea68dbc1
15
configure.py
15
configure.py
|
@ -15,8 +15,10 @@
|
||||||
import argparse
|
import argparse
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import List, Sequence, Union
|
||||||
|
|
||||||
from tools.project import (
|
from tools.project import (
|
||||||
|
BuildConfigUnit,
|
||||||
Object,
|
Object,
|
||||||
ProgressCategory,
|
ProgressCategory,
|
||||||
ProjectConfig,
|
ProjectConfig,
|
||||||
|
@ -767,6 +769,7 @@ config.libs = [
|
||||||
Object(NonMatching, "MetroidPrime/ScriptObjects/CEnergyBall.cpp"),
|
Object(NonMatching, "MetroidPrime/ScriptObjects/CEnergyBall.cpp"),
|
||||||
Object(MatchingFor("GM8E01_00", "GM8E01_01"), "MetroidPrime/Enemies/CMetroidPrimeProjectile.cpp"),
|
Object(MatchingFor("GM8E01_00", "GM8E01_01"), "MetroidPrime/Enemies/CMetroidPrimeProjectile.cpp"),
|
||||||
Object(MatchingFor("GM8E01_00", "GM8E01_01"), "MetroidPrime/Enemies/SPositionHistory.cpp"),
|
Object(MatchingFor("GM8E01_00", "GM8E01_01"), "MetroidPrime/Enemies/SPositionHistory.cpp"),
|
||||||
|
Object(Equivalent, "dummy.c"),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
RetroLib(
|
RetroLib(
|
||||||
|
@ -1414,6 +1417,18 @@ for lib in config.libs:
|
||||||
obj.options["extra_clang_flags"].append("-Wno-return-type")
|
obj.options["extra_clang_flags"].append("-Wno-return-type")
|
||||||
|
|
||||||
|
|
||||||
|
def link_order_callback(
|
||||||
|
module_id: int, units: List[str]
|
||||||
|
) -> Sequence[Union[str, BuildConfigUnit]]:
|
||||||
|
if module_id == 0: # DOL
|
||||||
|
return units + [
|
||||||
|
{"object": "dummy.o", "name": "dummy.c", "autogenerated": False}
|
||||||
|
]
|
||||||
|
return units
|
||||||
|
|
||||||
|
|
||||||
|
config.link_order_callback = link_order_callback
|
||||||
|
|
||||||
# Optional extra categories for progress tracking
|
# Optional extra categories for progress tracking
|
||||||
config.progress_categories = [
|
config.progress_categories = [
|
||||||
ProgressCategory("game", "Game"),
|
ProgressCategory("game", "Game"),
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
void custom_tu_smiley() {}
|
100
tools/project.py
100
tools/project.py
|
@ -17,7 +17,21 @@ import os
|
||||||
import platform
|
import platform
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import IO, Any, Dict, Iterable, List, Optional, Set, Tuple, Union, cast
|
from typing import (
|
||||||
|
Any,
|
||||||
|
Callable,
|
||||||
|
Sequence,
|
||||||
|
cast,
|
||||||
|
Dict,
|
||||||
|
IO,
|
||||||
|
Iterable,
|
||||||
|
List,
|
||||||
|
Optional,
|
||||||
|
Set,
|
||||||
|
Tuple,
|
||||||
|
TypedDict,
|
||||||
|
Union,
|
||||||
|
)
|
||||||
|
|
||||||
from . import ninja_syntax
|
from . import ninja_syntax
|
||||||
from .ninja_syntax import serialize_path
|
from .ninja_syntax import serialize_path
|
||||||
|
@ -179,6 +193,9 @@ class ProjectConfig:
|
||||||
self.scratch_preset_id: Optional[int] = (
|
self.scratch_preset_id: Optional[int] = (
|
||||||
None # Default decomp.me preset ID for scratches
|
None # Default decomp.me preset ID for scratches
|
||||||
)
|
)
|
||||||
|
self.link_order_callback: Optional[
|
||||||
|
Callable[[int, List[str]], Sequence[Union[str, BuildConfigUnit]]]
|
||||||
|
] = None # Callback to add/remove/reorder units within a module
|
||||||
|
|
||||||
# Progress output, progress.json and report.json config
|
# Progress output, progress.json and report.json config
|
||||||
self.progress = True # Enable report.json generation and CLI progress output
|
self.progress = True # Enable report.json generation and CLI progress output
|
||||||
|
@ -294,10 +311,38 @@ def make_flags_str(flags: Optional[List[str]]) -> str:
|
||||||
return " ".join(flags)
|
return " ".join(flags)
|
||||||
|
|
||||||
|
|
||||||
|
# Unit configuration
|
||||||
|
class BuildConfigUnit(TypedDict):
|
||||||
|
object: Optional[str]
|
||||||
|
name: str
|
||||||
|
autogenerated: bool
|
||||||
|
|
||||||
|
|
||||||
|
# Module configuration
|
||||||
|
class BuildConfigModule(TypedDict):
|
||||||
|
name: str
|
||||||
|
module_id: int
|
||||||
|
ldscript: str
|
||||||
|
entry: str
|
||||||
|
units: List[BuildConfigUnit]
|
||||||
|
|
||||||
|
|
||||||
|
# Module link configuration
|
||||||
|
class BuildConfigLink(TypedDict):
|
||||||
|
modules: List[str]
|
||||||
|
|
||||||
|
|
||||||
|
# Build configuration generated by decomp-toolkit
|
||||||
|
class BuildConfig(BuildConfigModule):
|
||||||
|
version: str
|
||||||
|
modules: List[BuildConfigModule]
|
||||||
|
links: List[BuildConfigLink]
|
||||||
|
|
||||||
|
|
||||||
# Load decomp-toolkit generated config.json
|
# Load decomp-toolkit generated config.json
|
||||||
def load_build_config(
|
def load_build_config(
|
||||||
config: ProjectConfig, build_config_path: Path
|
config: ProjectConfig, build_config_path: Path
|
||||||
) -> Optional[Dict[str, Any]]:
|
) -> Optional[BuildConfig]:
|
||||||
if not build_config_path.is_file():
|
if not build_config_path.is_file():
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -305,7 +350,7 @@ def load_build_config(
|
||||||
return tuple(map(int, (v.split("."))))
|
return tuple(map(int, (v.split("."))))
|
||||||
|
|
||||||
f = open(build_config_path, "r", encoding="utf-8")
|
f = open(build_config_path, "r", encoding="utf-8")
|
||||||
build_config: Dict[str, Any] = json.load(f)
|
build_config: BuildConfig = json.load(f)
|
||||||
config_version = build_config.get("version")
|
config_version = build_config.get("version")
|
||||||
if config_version is None:
|
if config_version is None:
|
||||||
print("Invalid config.json, regenerating...")
|
print("Invalid config.json, regenerating...")
|
||||||
|
@ -321,6 +366,27 @@ def load_build_config(
|
||||||
return None
|
return None
|
||||||
|
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
# Apply link order callback
|
||||||
|
if config.link_order_callback:
|
||||||
|
modules: List[BuildConfigModule] = [build_config, *build_config["modules"]]
|
||||||
|
for module in modules:
|
||||||
|
unit_names = list(map(lambda u: u["name"], module["units"]))
|
||||||
|
new_units = config.link_order_callback(module["module_id"], unit_names)
|
||||||
|
units: List[BuildConfigUnit] = []
|
||||||
|
for new_unit in new_units:
|
||||||
|
if isinstance(new_unit, str):
|
||||||
|
units.append(
|
||||||
|
# Find existing unit or create a new one
|
||||||
|
next(
|
||||||
|
(u for u in module["units"] if u["name"] == new_unit),
|
||||||
|
{"object": None, "name": new_unit, "autogenerated": False},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
units.append(new_unit)
|
||||||
|
module["units"] = units
|
||||||
|
|
||||||
return build_config
|
return build_config
|
||||||
|
|
||||||
|
|
||||||
|
@ -338,7 +404,7 @@ def generate_build(config: ProjectConfig) -> None:
|
||||||
def generate_build_ninja(
|
def generate_build_ninja(
|
||||||
config: ProjectConfig,
|
config: ProjectConfig,
|
||||||
objects: Dict[str, Object],
|
objects: Dict[str, Object],
|
||||||
build_config: Optional[Dict[str, Any]],
|
build_config: Optional[BuildConfig],
|
||||||
) -> None:
|
) -> None:
|
||||||
out = io.StringIO()
|
out = io.StringIO()
|
||||||
n = ninja_syntax.Writer(out)
|
n = ninja_syntax.Writer(out)
|
||||||
|
@ -699,9 +765,9 @@ def generate_build_ninja(
|
||||||
return path.parent / (path.name + ".MAP")
|
return path.parent / (path.name + ".MAP")
|
||||||
|
|
||||||
class LinkStep:
|
class LinkStep:
|
||||||
def __init__(self, config: Dict[str, Any]) -> None:
|
def __init__(self, config: BuildConfigModule) -> None:
|
||||||
self.name: str = config["name"]
|
self.name = config["name"]
|
||||||
self.module_id: int = config["module_id"]
|
self.module_id = config["module_id"]
|
||||||
self.ldscript: Optional[Path] = Path(config["ldscript"])
|
self.ldscript: Optional[Path] = Path(config["ldscript"])
|
||||||
self.entry = config["entry"]
|
self.entry = config["entry"]
|
||||||
self.inputs: List[str] = []
|
self.inputs: List[str] = []
|
||||||
|
@ -907,13 +973,14 @@ def generate_build_ninja(
|
||||||
|
|
||||||
return obj_path
|
return obj_path
|
||||||
|
|
||||||
def add_unit(build_obj, link_step: LinkStep):
|
def add_unit(build_obj: BuildConfigUnit, link_step: LinkStep):
|
||||||
obj_path, obj_name = build_obj["object"], build_obj["name"]
|
obj_path, obj_name = build_obj["object"], build_obj["name"]
|
||||||
obj = objects.get(obj_name)
|
obj = objects.get(obj_name)
|
||||||
if obj is None:
|
if obj is None:
|
||||||
if config.warn_missing_config and not build_obj["autogenerated"]:
|
if config.warn_missing_config and not build_obj["autogenerated"]:
|
||||||
print(f"Missing configuration for {obj_name}")
|
print(f"Missing configuration for {obj_name}")
|
||||||
link_step.add(obj_path)
|
if obj_path is not None:
|
||||||
|
link_step.add(Path(obj_path))
|
||||||
return
|
return
|
||||||
|
|
||||||
link_built_obj = obj.completed
|
link_built_obj = obj.completed
|
||||||
|
@ -942,12 +1009,7 @@ def generate_build_ninja(
|
||||||
link_step.add(built_obj_path)
|
link_step.add(built_obj_path)
|
||||||
elif obj_path is not None:
|
elif obj_path is not None:
|
||||||
# Use the original (extracted) object
|
# Use the original (extracted) object
|
||||||
link_step.add(obj_path)
|
link_step.add(Path(obj_path))
|
||||||
else:
|
|
||||||
lib_name = obj.options["lib"]
|
|
||||||
sys.exit(
|
|
||||||
f"Missing object for {obj_name}: {obj.src_path} {lib_name} {obj}"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Add DOL link step
|
# Add DOL link step
|
||||||
link_step = LinkStep(build_config)
|
link_step = LinkStep(build_config)
|
||||||
|
@ -1268,7 +1330,7 @@ def generate_build_ninja(
|
||||||
def generate_objdiff_config(
|
def generate_objdiff_config(
|
||||||
config: ProjectConfig,
|
config: ProjectConfig,
|
||||||
objects: Dict[str, Object],
|
objects: Dict[str, Object],
|
||||||
build_config: Optional[Dict[str, Any]],
|
build_config: Optional[BuildConfig],
|
||||||
) -> None:
|
) -> None:
|
||||||
if build_config is None:
|
if build_config is None:
|
||||||
return
|
return
|
||||||
|
@ -1333,7 +1395,7 @@ def generate_objdiff_config(
|
||||||
}
|
}
|
||||||
|
|
||||||
def add_unit(
|
def add_unit(
|
||||||
build_obj: Dict[str, Any], module_name: str, progress_categories: List[str]
|
build_obj: BuildConfigUnit, module_name: str, progress_categories: List[str]
|
||||||
) -> None:
|
) -> None:
|
||||||
obj_path, obj_name = build_obj["object"], build_obj["name"]
|
obj_path, obj_name = build_obj["object"], build_obj["name"]
|
||||||
base_object = Path(obj_name).with_suffix("")
|
base_object = Path(obj_name).with_suffix("")
|
||||||
|
@ -1481,7 +1543,7 @@ def generate_objdiff_config(
|
||||||
def generate_compile_commands(
|
def generate_compile_commands(
|
||||||
config: ProjectConfig,
|
config: ProjectConfig,
|
||||||
objects: Dict[str, Object],
|
objects: Dict[str, Object],
|
||||||
build_config: Optional[Dict[str, Any]],
|
build_config: Optional[BuildConfig],
|
||||||
) -> None:
|
) -> None:
|
||||||
if build_config is None or not config.generate_compile_commands:
|
if build_config is None or not config.generate_compile_commands:
|
||||||
return
|
return
|
||||||
|
@ -1570,7 +1632,7 @@ def generate_compile_commands(
|
||||||
|
|
||||||
clangd_config = []
|
clangd_config = []
|
||||||
|
|
||||||
def add_unit(build_obj: Dict[str, Any]) -> None:
|
def add_unit(build_obj: BuildConfigUnit) -> None:
|
||||||
obj = objects.get(build_obj["name"])
|
obj = objects.get(build_obj["name"])
|
||||||
if obj is None:
|
if obj is None:
|
||||||
return
|
return
|
||||||
|
|
Loading…
Reference in New Issue