summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorAetias <aetias@outlook.com>2025-02-04 21:30:00 +0100
committerAetias <aetias@outlook.com>2025-02-04 21:30:00 +0100
commitc380ac51a48d17348b1cdcbb615ce22be22f409e (patch)
tree6713ed5a1cd172f665e52ea0f995fc905ca3db2d /tools
parent8cda3ca2d7f5fe424cc1a649baec2ff992368e62 (diff)
parent3f7197110627adbbe7ff1f69db1f5a15f9b6c598 (diff)
Merge remote-tracking branch 'zeldaret/main' into decomp-PlayerControl
Diffstat (limited to 'tools')
-rw-r--r--tools/configure.py45
-rwxr-xr-xtools/m2ctx.py7
-rw-r--r--tools/mangle.py30
-rw-r--r--tools/setup.py4
-rw-r--r--tools/sha1.py29
-rw-r--r--tools/transform_dep.py84
6 files changed, 175 insertions, 24 deletions
diff --git a/tools/configure.py b/tools/configure.py
index b1416e0f..26f7e86e 100644
--- a/tools/configure.py
+++ b/tools/configure.py
@@ -27,7 +27,7 @@ CC_FLAGS = " ".join([
"-proc arm946e", # Target processor
"-gccext,on", # Enable GCC extensions
"-fp soft", # Compute float operations in software
- "-inline on,noauto", # Inline only functions marked with 'inline'
+ "-inline noauto", # Inline only functions marked with 'inline'
"-lang=c++", # Set language to C++
"-Cpp_exceptions off", # Disable C++ exceptions
"-RTTI off", # Disable runtime type information
@@ -82,7 +82,7 @@ CC_INCLUDES = " ".join(f"-i {include}" for include in includes)
EXE = ""
WINE = ""
system = platform.system()
-if system == "Windows" or system.startswith("MSYS") or system.startswith("MINGW"):
+if system == "Windows":
system = "windows"
EXE = ".exe"
elif system == "Linux":
@@ -129,9 +129,17 @@ def main():
)
n.newline()
+ # -MMD excludes all includes instead of just system includes for some reason, so use -MD instead.
+ mwcc_cmd = f'{WINE} "{mwcc_path}/mwccarm.exe" {CC_FLAGS} {CC_INCLUDES} $cc_flags -d $game_version -MD -c $in -o $basedir'
+ mwcc_implicit = []
+ if system != "windows":
+ transform_dep = "tools/transform_dep.py"
+ mwcc_cmd += f" && $python {transform_dep} $basefile.d $basefile.d"
+ mwcc_implicit.append(transform_dep)
n.rule(
name="mwcc",
- command=f'{WINE} "{mwcc_path}/mwccarm.exe" {CC_FLAGS} {CC_INCLUDES} $cc_flags -d $game_version $in -o $out'
+ command=mwcc_cmd,
+ depfile="$basefile.d",
)
n.newline()
@@ -171,12 +179,18 @@ def main():
)
n.newline()
+ n.rule(
+ name="sha1",
+ command=f"{PYTHON} tools/sha1.py $in -c $sha1_file"
+ )
+ n.newline()
+
game_build = build_path / game_version
game_extract = extract_path / game_version
add_extract_build(n, game_extract, game_version)
add_delink_and_lcf_builds(n, game_config, game_build, game_extract)
- add_mwcc_builds(n, game_version, game_build)
+ add_mwcc_builds(n, game_version, game_build, mwcc_implicit)
add_mwld_and_rom_builds(n, game_build, game_config, game_version)
@@ -241,21 +255,34 @@ def add_mwld_and_rom_builds(n: ninja_syntax.Writer, game_build: Path, game_confi
)
n.newline()
+ n.build(
+ inputs=rom_file,
+ rule="sha1",
+ variables={
+ "sha1_file": str(Path(rom_file).with_suffix(".sha1"))
+ },
+ outputs="sha1",
+ )
+ n.newline()
+
-def add_mwcc_builds(n: ninja_syntax.Writer, game_version: str, game_build: Path):
+def add_mwcc_builds(n: ninja_syntax.Writer, game_version: str, game_build: Path, mwcc_implicit: list[Path]):
for source_file in get_c_cpp_files([src_path, libs_path]):
- output_file = str(game_build / source_file.with_suffix(".o"))
+ src_obj_path = game_build / source_file
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),
rule="mwcc",
- outputs=output_file,
+ outputs=str(src_obj_path.with_suffix(".o")),
variables={
"game_version": game_version,
- "cc_flags": " ".join(cc_flags)
- }
+ "cc_flags": " ".join(cc_flags),
+ "basedir": os.path.dirname(src_obj_path),
+ "basefile": str(src_obj_path.with_suffix("")),
+ },
+ implicit=mwcc_implicit,
)
n.newline()
diff --git a/tools/m2ctx.py b/tools/m2ctx.py
index dc43f326..f2275e33 100755
--- a/tools/m2ctx.py
+++ b/tools/m2ctx.py
@@ -21,7 +21,8 @@ CXX_FLAGS = [
'-nostdinc',
'-Iinclude',
'-Ilibs/c/include',
- '-Ilibs/cpp/include'
+ '-Ilibs/cpp/include',
+ '-Ilibs/nds/include'
]
script_dir = Path(os.path.dirname(os.path.realpath(__file__)))
@@ -37,8 +38,8 @@ COMMENT_REGEX = r'\/\/.*$|\/\*(?:.|\r|\n)+?\*\/'
with open(args.file, 'r') as f:
contents = f.read()
-contents = re.sub(COMMENT_REGEX, '', contents, 0, re.MULTILINE)
-includes = re.findall(INCLUDE_REGEX, contents, re.MULTILINE)
+contents = re.sub(COMMENT_REGEX, '', contents, count=0, flags=re.MULTILINE)
+includes = re.findall(INCLUDE_REGEX, contents, flags=re.MULTILINE)
_, suffix = os.path.splitext(args.file)
diff --git a/tools/mangle.py b/tools/mangle.py
index 68d2aeb3..0d173788 100644
--- a/tools/mangle.py
+++ b/tools/mangle.py
@@ -15,6 +15,7 @@ include_dir = root_dir / 'include'
libs_dir = root_dir / 'libs'
libc_include_dir = libs_dir / 'c' / 'include'
libcpp_include_dir = libs_dir / 'cpp' / 'include'
+libnds_include_dir = libs_dir / 'nds' / 'include'
if platform.system() == 'Windows': cc = [str(cc_path)]
else: cc = ['wine', str(cc_path)]
@@ -27,7 +28,7 @@ cc.extend([
'-proc', 'arm946e',
'-gccext,on',
'-fp', 'soft',
- '-inline', 'on,noauto',
+ '-inline', 'noauto',
'-Cpp_exceptions', 'off',
'-RTTI', 'off',
'-interworking',
@@ -38,6 +39,7 @@ cc.extend([
'-i', include_dir,
'-i', libc_include_dir,
'-i', libcpp_include_dir,
+ '-i', libnds_include_dir,
args.file
])
@@ -52,19 +54,27 @@ output = output.decode()
# print(output)
mangled_funcs: list[str] = re.findall(r'.text +([^\$ ]\S+)', output)
-mangled_data: list[str] = re.findall(r'(?:.data|.bss) +([^\. ]\S+)', output)
+init_funcs: list[str] = re.findall(r'.init +([^\$ ]\S+)', output)
+mangled_data: list[str] = re.findall(r'.data +([^\. ]\S+)', output)
+mangled_bss: list[str] = re.findall(r'.bss +([^\. ]\S+)', output)
if len(mangled_funcs) > 0:
- print('Functions:')
- print()
+ print('.text:\n')
for func in mangled_funcs:
print(func)
- print()
- print()
+ print('\n')
+if len(init_funcs) > 0:
+ print('.init:\n')
+ for func in init_funcs:
+ print(func)
+ print('\n')
if len(mangled_data) > 0:
- print('Data:')
- print()
+ print('.data:\n')
for data in mangled_data:
print(data)
- print()
- print()
+ print('\n')
+if len(mangled_bss) > 0:
+ print('.bss:\n')
+ for bss in mangled_bss:
+ print(bss)
+ print('\n')
diff --git a/tools/setup.py b/tools/setup.py
index 44d146f7..bc322e1d 100644
--- a/tools/setup.py
+++ b/tools/setup.py
@@ -4,7 +4,7 @@ import io
from pathlib import Path
import platform
-DSD_VERSION = 'v0.2.3'
+DSD_VERSION = 'v0.4.0'
tools_path = Path(__file__).parent
@@ -13,7 +13,7 @@ root_path = tools_path.parent
EXE = ""
system = platform.system()
-if system == "Windows" or system.startswith("MSYS") or system.startswith("MINGW"):
+if system == "Windows":
system = "windows"
EXE = ".exe"
elif system == "Linux":
diff --git a/tools/sha1.py b/tools/sha1.py
new file mode 100644
index 00000000..8cd6edd8
--- /dev/null
+++ b/tools/sha1.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+from pathlib import Path
+import argparse
+import hashlib
+import sys
+
+def eprint(*args, **kwargs):
+ print(*args, file=sys.stderr, **kwargs)
+
+parser = argparse.ArgumentParser(description="Computes and verifies a SHA1 checksum")
+parser.add_argument('file', help="Input file to verify")
+parser.add_argument('-c', type=str, dest='checksum_file', required=False, help='Checksum file')
+args = parser.parse_args()
+
+file_path = Path(args.file)
+checksum_path = Path(args.checksum_file)
+
+with checksum_path.open('r') as file:
+ target_sha1, _ = file.readline().split(' ', 1)
+
+with file_path.open('rb') as file:
+ file_sha1 = hashlib.sha1(file.read()).hexdigest()
+
+if target_sha1 != file_sha1:
+ eprint(f"{file_path}: FAILED")
+ exit(1)
+else:
+ eprint(f"{file_path}: OK")
diff --git a/tools/transform_dep.py b/tools/transform_dep.py
new file mode 100644
index 00000000..124de04b
--- /dev/null
+++ b/tools/transform_dep.py
@@ -0,0 +1,84 @@
+#!/usr/bin/env python3
+
+###
+# Transforms .d files, converting Windows paths to Unix paths.
+# Allows usage of the mwcc -MMD flag on platforms other than Windows.
+#
+# Usage:
+# python3 tools/transform_dep.py build/src/file.d build/src/file.d
+#
+# If changes are made, please submit a PR to
+# https://github.com/encounter/dtk-template
+###
+
+import argparse
+import os
+from platform import uname
+
+wineprefix = os.path.join(os.environ["HOME"], ".wine")
+if "WINEPREFIX" in os.environ:
+ wineprefix = os.environ["WINEPREFIX"]
+winedevices = os.path.join(wineprefix, "dosdevices")
+
+
+def in_wsl() -> bool:
+ return "microsoft-standard" in uname().release
+
+
+def import_d_file(in_file: str) -> str:
+ out_text = ""
+
+ with open(in_file) as file:
+ for idx, line in enumerate(file):
+ if idx == 0:
+ if line.endswith(" \\\n"):
+ out_text += line[:-3].replace("\\", "/") + " \\\n"
+ else:
+ out_text += line.replace("\\", "/")
+ else:
+ suffix = ""
+ if line.endswith(" \\\n"):
+ suffix = " \\"
+ path = line.lstrip()[:-3]
+ else:
+ path = line.strip()
+ # lowercase drive letter
+ path = path[0].lower() + path[1:]
+ if path[0] == "z":
+ # shortcut for z:
+ path = path[2:].replace("\\", "/")
+ elif in_wsl():
+ path = path[0:1] + path[2:]
+ path = os.path.join("/mnt", path.replace("\\", "/"))
+ else:
+ # use $WINEPREFIX/dosdevices to resolve path
+ path = os.path.realpath(
+ os.path.join(winedevices, path.replace("\\", "/"))
+ )
+ out_text += "\t" + path + suffix + "\n"
+
+ return out_text
+
+
+def main() -> None:
+ parser = argparse.ArgumentParser(
+ description="""Transform a .d file from Wine paths to normal paths"""
+ )
+ parser.add_argument(
+ "d_file",
+ help="""Dependency file in""",
+ )
+ parser.add_argument(
+ "d_file_out",
+ help="""Dependency file out""",
+ )
+ args = parser.parse_args()
+
+ output = import_d_file(args.d_file)
+
+ with open(args.d_file_out, "w", encoding="UTF-8") as f:
+ f.write(output)
+
+
+if __name__ == "__main__":
+ main()