mirror of
https://github.com/zeldaret/st
synced 2026-09-04 10:12:27 -04:00
Update dsd to v0.12.0; dsprot OK (#135)
* `Actor::mType` field * Remove fake symbol `data_027e0254` * `dsd format` * eur: Enable dsprot decomp * jp: Enable dsprot decomp * dsprot OK * `dsd format` * Use new `weak` attribute * Add relocations for exception table link-time constants * Add exception table symbols * Bump dsd to v0.12.0 * `#define FALSE 1` ??? Why did I make it 1? * Truncate `data_ov001_020c27a8` That data belongs to dsprot
This commit is contained in:
+119
-2
@@ -4,8 +4,9 @@ import json
|
||||
import argparse
|
||||
import subprocess
|
||||
import glob
|
||||
import ninja_syntax
|
||||
|
||||
from typing import List, Dict, Any
|
||||
from typing import List, Dict, Any, Callable
|
||||
from pathlib import Path
|
||||
from project import ProjectConfig, Object, process_project
|
||||
|
||||
@@ -20,7 +21,7 @@ parser.add_argument("--noclangd", "-c", help='Do not create clangd config', requ
|
||||
args = parser.parse_args()
|
||||
|
||||
config = ProjectConfig("st", args.compiler, "dsi/1.2p1", args.wine, args.dsd, Path(__file__).resolve())
|
||||
config.dsd_tag = "v0.11.0"
|
||||
config.dsd_tag = "v0.12.0"
|
||||
config.wibo_tag = "1.1.0"
|
||||
config.objdiff_tag = "v3.7.1"
|
||||
config.sjiswrap_tag = "v1.2.2"
|
||||
@@ -65,6 +66,10 @@ config.cflags_base = [
|
||||
"-ipa file", # InterProcedural Analysis
|
||||
]
|
||||
|
||||
config.asflags = [
|
||||
"-proc arm5TE", # Target processor
|
||||
]
|
||||
|
||||
config.ldflags = [
|
||||
"-proc arm946e", # Target processor
|
||||
"-dead", # Strip unused code
|
||||
@@ -75,6 +80,8 @@ config.ldflags = [
|
||||
]
|
||||
|
||||
|
||||
type NinjaBuild = Callable[[ProjectConfig, str, ninja_syntax.Writer], None]
|
||||
|
||||
# Helper function for Nitro libraries
|
||||
def NitroLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]:
|
||||
return {
|
||||
@@ -96,6 +103,57 @@ def NNSLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]:
|
||||
"objects": objects,
|
||||
}
|
||||
|
||||
# Helper function for dsprot library
|
||||
DSPROT_SRC = "libs/dsprot/src"
|
||||
DSPROT_MW_VERSION = "2.0/sp2p3"
|
||||
def DSProtLib(lib_name: str, objects: List[Object], extra_builds: list[NinjaBuild]) -> Dict[str, Any]:
|
||||
return {
|
||||
"lib": lib_name,
|
||||
"mw_version": DSPROT_MW_VERSION,
|
||||
"src_dir": DSPROT_SRC,
|
||||
"cflags": [*config.cflags_base, "-lang c"],
|
||||
"objects": objects,
|
||||
"rules": [dsprot_asmwriter_rule],
|
||||
"extra_builds": extra_builds,
|
||||
}
|
||||
|
||||
def dsprot_asmwriter_rule(cfg: ProjectConfig, n: ninja_syntax.Writer):
|
||||
n.rule(
|
||||
name="dsprot_asmwriter",
|
||||
command=f"{cfg.python_path} libs/dsprot/tools/asmwriter.py -i $in -o $out $flags"
|
||||
)
|
||||
|
||||
def DSProtAsmwriter(asm_file: str, src_objects: list[str], *, flags: list[str]):
|
||||
def build(cfg: ProjectConfig, version: str, n: ninja_syntax.Writer):
|
||||
src_obj_path: list[Path] = [
|
||||
cfg.get_game_build(version) / DSPROT_SRC / src_object
|
||||
for src_object in src_objects
|
||||
]
|
||||
asm_path: Path = cfg.get_game_build(version) / DSPROT_SRC / asm_file
|
||||
asm_obj_path = asm_path.with_suffix(".o")
|
||||
n.build(
|
||||
inputs=list(map(str, src_obj_path)),
|
||||
implicit="libs/dsprot/tools/asmwriter.py",
|
||||
rule="dsprot_asmwriter",
|
||||
outputs=str(asm_path),
|
||||
variables={
|
||||
"flags": " ".join(flags)
|
||||
},
|
||||
)
|
||||
n.build(
|
||||
inputs=str(asm_path),
|
||||
rule="mwas",
|
||||
outputs=str(asm_obj_path),
|
||||
variables={
|
||||
"game_version": version.upper(),
|
||||
"mw_version": DSPROT_MW_VERSION,
|
||||
"as_flags": " ".join(cfg.asflags or []),
|
||||
"basedir": str(asm_obj_path.parent),
|
||||
"basefile": str(asm_obj_path.with_suffix("")),
|
||||
},
|
||||
)
|
||||
n.newline()
|
||||
return build
|
||||
|
||||
# Helper function for libc libraries
|
||||
def LibC(lib_name: str, objects: List[Object]) -> Dict[str, Any]:
|
||||
@@ -1494,6 +1552,65 @@ config.libs = [
|
||||
[
|
||||
Object("g3d/sbc.c"),
|
||||
]
|
||||
),
|
||||
DSProtLib(
|
||||
"dsprot",
|
||||
[
|
||||
Object("dsprot_main.c"),
|
||||
Object("integrity.c"),
|
||||
Object("encryptor.c"),
|
||||
Object("mac_owner.c"),
|
||||
Object("rom_util.c"),
|
||||
Object("rom_test.c"),
|
||||
Object("rc4.c"),
|
||||
Object("extra.c"),
|
||||
],
|
||||
extra_builds=[
|
||||
DSProtAsmwriter("dsprot_main_decryptor.s", ["dsprot_main.o"], flags=[
|
||||
"--key 0x2e8b",
|
||||
"--prefix DSProt_",
|
||||
"--symbols DetectFlashcart DetectNotFlashcart DetectEmulator DetectNotEmulator DetectDummy DetectNotDummy",
|
||||
]),
|
||||
DSProtAsmwriter("dsprot_main_decoder.s", ["dsprot_main_decryptor.o"], flags=[
|
||||
"--garbage DSProt_Garbage",
|
||||
"--prefix DSProt_",
|
||||
"--symbols DetectFlashcart DetectNotFlashcart DetectEmulator DetectNotEmulator DetectDummy DetectNotDummy",
|
||||
]),
|
||||
DSProtAsmwriter("integrity_decryptor.s", ["integrity.o"], flags=[
|
||||
"--key 0xbe28",
|
||||
"--symbols Integrity_MACOwner_IsBad Integrity_MACOwner_IsGood Integrity_ROMTest_IsBad Integrity_ROMTest_IsGood",
|
||||
]),
|
||||
DSProtAsmwriter("integrity_decoder.s", ["integrity_decryptor.o"], flags=[
|
||||
"--symbols Integrity_MACOwner_IsBad Integrity_MACOwner_IsGood Integrity_ROMTest_IsBad Integrity_ROMTest_IsGood",
|
||||
]),
|
||||
DSProtAsmwriter("encryptor_decryptor.s", ["encryptor.o"], flags=[
|
||||
"--prefix ''",
|
||||
"--symbols Encryptor_EncryptFunction Encryptor_DecryptFunction",
|
||||
]),
|
||||
DSProtAsmwriter("mac_owner_decryptor.s", ["mac_owner.o"], flags=[
|
||||
"--key 0xc7ea",
|
||||
"--symbols MACOwner_IsBad MACOwner_IsGood",
|
||||
]),
|
||||
DSProtAsmwriter("rom_util_decryptor.s", ["rom_util.o"], flags=[
|
||||
"--key 0xc7ea",
|
||||
"--symbols ROMUtil_Read ROMUtil_CRC32",
|
||||
]),
|
||||
DSProtAsmwriter("rom_test_decryptor.s", ["rom_test.o"], flags=[
|
||||
"--key 0xc7ea",
|
||||
"--symbols ROMTest_IsBad ROMTest_IsGood",
|
||||
]),
|
||||
DSProtAsmwriter(
|
||||
"coretests_decoder.s",
|
||||
["mac_owner_decryptor.o", "rom_util_decryptor.o", "rom_test_decryptor.o"],
|
||||
flags=[
|
||||
"--symbols ROMTest_IsBad ROMTest_IsGood MACOwner_IsBad MACOwner_IsGood ROMUtil_Read ROMUtil_CRC32",
|
||||
]
|
||||
),
|
||||
DSProtAsmwriter("rc4_decoder.s", ["rc4.o"], flags=[
|
||||
"--prefix ''",
|
||||
"--symbols RC4_Init RC4_Byte RC4_InitSBox RC4_EncryptInstructions RC4_DecryptInstructions RC4_InitAndEncryptInstructions RC4_InitAndDecryptInstructions",
|
||||
]),
|
||||
],
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ CXX_FLAGS = [
|
||||
'-Ilibs/runtime/include',
|
||||
'-Ilibs/nitro/include',
|
||||
'-Ilibs/nns/include',
|
||||
'-Ilibs/dsprotect/include',
|
||||
'-Ilibs/dsprot/include',
|
||||
f'-DVERSION={args.version}',
|
||||
'-D__MWERKS__',
|
||||
]
|
||||
|
||||
+125
-36
@@ -1,3 +1,4 @@
|
||||
from collections.abc import Generator
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
@@ -10,6 +11,7 @@ from get_platform import get_platform
|
||||
|
||||
|
||||
COMPILER_MAP = {
|
||||
"1.2/b56": "mwcc_20_56",
|
||||
"1.2/base": "mwcc_20_72",
|
||||
"1.2/sp2": "mwcc_20_79",
|
||||
"1.2/sp2p3": "mwcc_20_82",
|
||||
@@ -38,13 +40,25 @@ COMPILER_MAP = {
|
||||
|
||||
Library = Dict[str, Any]
|
||||
|
||||
def get_c_cpp_files(dirs: list[Path]):
|
||||
|
||||
def traverse_files(dirs: list[Path]) -> Generator[Path]:
|
||||
for dir in dirs:
|
||||
for root, _, files in os.walk(dir):
|
||||
root = Path(root)
|
||||
for file in files:
|
||||
if is_cpp(file) or is_c(file):
|
||||
yield root / file
|
||||
yield root / file
|
||||
|
||||
|
||||
def get_c_cpp_files(dirs: list[Path]) -> Generator[Path]:
|
||||
for file in traverse_files(dirs):
|
||||
if is_cpp(file) or is_c(file):
|
||||
yield file
|
||||
|
||||
|
||||
def get_asm_files(dirs: list[Path]) -> Generator[Path]:
|
||||
for file in traverse_files(dirs):
|
||||
if is_asm(file):
|
||||
yield file
|
||||
|
||||
|
||||
def is_cpp(name: str | Path):
|
||||
@@ -54,9 +68,15 @@ def is_cpp(name: str | Path):
|
||||
def is_c(name: str | Path):
|
||||
return Path(name).suffix in [".c"]
|
||||
|
||||
|
||||
def is_c_cpp(name: str | Path):
|
||||
return is_c(name) or is_cpp(name)
|
||||
|
||||
|
||||
def is_asm(name: str | Path):
|
||||
return Path(name).suffix in [".s"]
|
||||
|
||||
|
||||
class Object:
|
||||
def __init__(self, name: str, **options: Any):
|
||||
self.name = name
|
||||
@@ -132,8 +152,9 @@ class ProjectConfig:
|
||||
self.objdiff_path = (self.root_path / f"objdiff-cli{self.platform.exe}").resolve()
|
||||
self.sjiswrap_path = (self.root_path / "tools" / "sjiswrap.exe").resolve()
|
||||
self.cc_path = (self.mwcc_path / "mwccarm.exe").resolve()
|
||||
self.as_path = (self.mwcc_path / "mwasmarm.exe").resolve()
|
||||
self.ld_path = (self.mwcc_path / "mwldarm.exe").resolve()
|
||||
self.python_path = Path(sys.executable).resolve()
|
||||
self.python_path = Path(sys.executable)
|
||||
|
||||
self.dsd_base_flags = [
|
||||
"--force-color", # Force color output
|
||||
@@ -295,11 +316,15 @@ class ProjectConfig:
|
||||
return self.get_game_build(version) / "build" / "rom_config.yaml"
|
||||
|
||||
def source_object_files(self, version: str) -> list[str]:
|
||||
files: list[str] = []
|
||||
for source_file in get_c_cpp_files([self.src_path, self.libs_path]):
|
||||
def to_object(source_file: Path) -> str:
|
||||
src_obj_path = self.get_game_build(version) / source_file
|
||||
files.append(str(src_obj_path.with_suffix(".o")))
|
||||
return files
|
||||
return str(src_obj_path.with_suffix(".o"))
|
||||
|
||||
dirs = [self.src_path, self.libs_path]
|
||||
c_cpp_objects = list(map(to_object, get_c_cpp_files(dirs)))
|
||||
asm_objects = list(map(to_object, get_asm_files(dirs)))
|
||||
return c_cpp_objects + asm_objects
|
||||
|
||||
|
||||
def arm9_o(self, version: str) -> Path:
|
||||
return self.get_game_build(version) / "arm9.o"
|
||||
@@ -532,44 +557,40 @@ def add_disassemble_builds(cfg: ProjectConfig, version: str, n: ninja_syntax.Wri
|
||||
|
||||
|
||||
def add_mwcc_builds(cfg: ProjectConfig, version: str, objects: Dict[str, Object], n: ninja_syntax.Writer, mwcc_implicit: list[str]):
|
||||
file_map: dict[str, list[str] | None] = {}
|
||||
file_map: dict[str, Object] = {}
|
||||
|
||||
for object in objects.values():
|
||||
file_map[str(object.src_path)] = object.options["cflags"] + object.options["extra_cflags"]
|
||||
assert object.src_path is not None, f"Object '{object.name}' is not resolved"
|
||||
if is_asm(object.src_path):
|
||||
# file_map[str(object.src_path)] = object.options["asflags"] or [] + object.options["extra_asflags"] or []
|
||||
file_map[str(object.src_path)] = object
|
||||
else:
|
||||
# file_map[str(object.src_path)] = object.options["cflags"] or [] + object.options["extra_cflags"] or []
|
||||
file_map[str(object.src_path)] = object
|
||||
|
||||
if cfg.auto_add_sources:
|
||||
for source_file in get_c_cpp_files([cfg.src_path, cfg.libs_path]):
|
||||
if str(source_file) not in file_map:
|
||||
file_map[str(source_file)] = cfg.cflags_base
|
||||
source_file = str(source_file)
|
||||
if source_file not in file_map:
|
||||
# file_map[source_file] = cfg.cflags_base or []
|
||||
file_map[source_file] = Object(source_file, cflags=cfg.cflags_base)
|
||||
for source_file in get_asm_files([cfg.src_path, cfg.libs_path]):
|
||||
source_file = str(source_file)
|
||||
if source_file not in file_map:
|
||||
# file_map[source_file] = cfg.asflags or []
|
||||
file_map[source_file] = Object(source_file, asflags=cfg.asflags)
|
||||
|
||||
for src_file, cc_flags in file_map.items():
|
||||
for src_file, object in file_map.items():
|
||||
source_file = Path(src_file)
|
||||
src_obj_path = cfg.get_game_build(version) / source_file
|
||||
|
||||
if cfg.warn_missing_source and not source_file.exists():
|
||||
print(f"WARNING: path not found for `{source_file}`")
|
||||
|
||||
assert cc_flags is not None, "cc_flags is None"
|
||||
if "-lang=c++" not in cc_flags or "-lang=c" not in cc_flags:
|
||||
if is_cpp(source_file):
|
||||
cc_flags.append("-lang=c++")
|
||||
elif is_c(source_file):
|
||||
cc_flags.append("-lang=c")
|
||||
|
||||
n.build(
|
||||
inputs=str(source_file),
|
||||
implicit=mwcc_implicit,
|
||||
rule="mwcc",
|
||||
outputs=str(src_obj_path.with_suffix(".o")),
|
||||
variables={
|
||||
"game_version": version.upper(),
|
||||
"cc_flags": " ".join(cc_flags),
|
||||
"basedir": str(src_obj_path.parent),
|
||||
"basefile": str(src_obj_path.with_suffix("")),
|
||||
},
|
||||
# order_only="objdiff",
|
||||
)
|
||||
n.newline()
|
||||
if is_asm(src_file):
|
||||
add_mwas_build(cfg, version, n, source_file, object, mwcc_implicit)
|
||||
else:
|
||||
add_mwcc_build(cfg, version, n, source_file, object, mwcc_implicit)
|
||||
|
||||
extension = source_file.suffix
|
||||
ctx_file = str(src_obj_path.with_suffix(f".ctx{extension}"))
|
||||
@@ -584,6 +605,53 @@ def add_mwcc_builds(cfg: ProjectConfig, version: str, objects: Dict[str, Object]
|
||||
n.newline()
|
||||
|
||||
|
||||
def add_mwcc_build(cfg: ProjectConfig, version: str, n: ninja_syntax.Writer, source_file: Path, object: Object, mwcc_implicit: list[str]):
|
||||
src_obj_path = cfg.get_game_build(version) / source_file
|
||||
|
||||
cc_flags: list[str] = object.options["cflags"] or [] + object.options["extra_cflags"] or []
|
||||
if "-lang=c++" not in cc_flags or "-lang=c" not in cc_flags:
|
||||
if is_cpp(source_file):
|
||||
cc_flags.append("-lang=c++")
|
||||
elif is_c(source_file):
|
||||
cc_flags.append("-lang=c")
|
||||
|
||||
n.build(
|
||||
inputs=str(source_file),
|
||||
implicit=mwcc_implicit,
|
||||
rule="mwcc",
|
||||
outputs=str(src_obj_path.with_suffix(".o")),
|
||||
variables={
|
||||
"game_version": version.upper(),
|
||||
"mw_version": object.options["mw_version"],
|
||||
"cc_flags": " ".join(cc_flags),
|
||||
"basedir": str(src_obj_path.parent),
|
||||
"basefile": str(src_obj_path.with_suffix("")),
|
||||
},
|
||||
)
|
||||
n.newline()
|
||||
|
||||
|
||||
def add_mwas_build(cfg: ProjectConfig, version: str, n: ninja_syntax.Writer, source_file: Path, object: Object, mwcc_implicit: list[str]):
|
||||
src_obj_path = cfg.get_game_build(version) / source_file
|
||||
|
||||
as_flags: list[str] = object.options["asflags"] or [] + object.options["extra_asflags"] or []
|
||||
|
||||
n.build(
|
||||
inputs=str(source_file),
|
||||
implicit=mwcc_implicit,
|
||||
rule="mwas",
|
||||
outputs=str(src_obj_path.with_suffix(".o")),
|
||||
variables={
|
||||
"game_version": version.upper(),
|
||||
"mw_version": object.options["mw_version"],
|
||||
"as_flags": " ".join(as_flags),
|
||||
"basedir": str(src_obj_path.parent),
|
||||
"basefile": str(src_obj_path.with_suffix("")),
|
||||
},
|
||||
)
|
||||
n.newline()
|
||||
|
||||
|
||||
def add_mwld_and_rom_builds(cfg: ProjectConfig, version: str, n: ninja_syntax.Writer):
|
||||
n.comment("Run linker")
|
||||
objects_to_link = [file['object_to_link'] for file in cfg.files(version)]
|
||||
@@ -1025,11 +1093,14 @@ def process_project(cfg: ProjectConfig, args: Any):
|
||||
|
||||
# -MMD excludes all includes instead of just system includes for some reason, so use -MD instead.
|
||||
includes = " ".join(include for include in cfg.includes)
|
||||
mwcc_cmd = f'{cfg.wine_path} {cfg.sjiswrap_path} "{cfg.cc_path}" $cc_flags {includes} -DVERSION=$game_version -MD -c $in -o $basedir'
|
||||
mwcc_cmd = f'{cfg.wine_path} {cfg.sjiswrap_path} "{cfg.mwcc_root}/$mw_version/mwccarm.exe" $cc_flags {includes} -DVERSION=$game_version -MD -c $in -o $basedir'
|
||||
mwas_cmd = f'{cfg.wine_path} {cfg.sjiswrap_path} "{cfg.mwcc_root}/$mw_version/mwasmarm.exe" $as_flags {includes} -DVERSION=$game_version -MD -c $in -o $basedir'
|
||||
mwcc_implicit = [str(cfg.cc_path), str(cfg.sjiswrap_path)]
|
||||
if cfg.platform and cfg.platform.system != "windows":
|
||||
transform_dep = "tools/transform_dep.py"
|
||||
mwcc_cmd += f" && $python {transform_dep} $basefile.d $basefile.d"
|
||||
transform_dep_cmd = f" && $python {transform_dep} $basefile.d $basefile.d"
|
||||
mwcc_cmd += transform_dep_cmd
|
||||
mwas_cmd += transform_dep_cmd
|
||||
mwcc_implicit.append(transform_dep)
|
||||
if cfg.wine_path == cfg.default_wibo_path:
|
||||
mwcc_implicit.append(cfg.wine_path)
|
||||
@@ -1040,6 +1111,13 @@ def process_project(cfg: ProjectConfig, args: Any):
|
||||
)
|
||||
n.newline()
|
||||
|
||||
n.rule(
|
||||
name="mwas",
|
||||
command=mwas_cmd,
|
||||
depfile="$basefile.d",
|
||||
)
|
||||
n.newline()
|
||||
|
||||
n.rule(
|
||||
name="lcf",
|
||||
command=f"{cfg.dsd_path} {cfg.dsd_flags} lcf -c $config_path"
|
||||
@@ -1134,6 +1212,12 @@ def process_project(cfg: ProjectConfig, args: Any):
|
||||
)
|
||||
n.newline()
|
||||
|
||||
# Custom rules
|
||||
for lib in cfg.libs or []:
|
||||
for rule in lib.get("rules") or []:
|
||||
rule(cfg, n)
|
||||
n.newline()
|
||||
|
||||
add_download_tool_builds(cfg, n, args)
|
||||
add_configure_build(cfg, n)
|
||||
|
||||
@@ -1159,6 +1243,11 @@ def process_project(cfg: ProjectConfig, args: Any):
|
||||
|
||||
add_mwcc_builds(cfg, version, objects, n, mwcc_implicit)
|
||||
|
||||
# Custom builds
|
||||
for lib in cfg.libs or []:
|
||||
for extra_build in lib.get("extra_builds") or []:
|
||||
extra_build(cfg, version, n)
|
||||
|
||||
add_mwld_and_rom_builds(cfg, version, n)
|
||||
cmds_map["sha1"].append(f"sha1_{version}")
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
pre-commit
|
||||
pyelftools
|
||||
pyperclip
|
||||
requests
|
||||
|
||||
Reference in New Issue
Block a user