sly1/configure.py

224 lines
6.0 KiB
Python
Raw Normal View History

2024-06-28 04:34:52 +00:00
"""
Configure the project for building.
"""
2024-06-28 03:16:37 +00:00
#! /usr/bin/env python3
import argparse
import os
import shutil
import sys
from pathlib import Path
from typing import Dict, List, Set, Union
import ninja_syntax
import splat
import splat.scripts.split as split
from splat.segtypes.linker_entry import LinkerEntry
2024-06-28 04:34:52 +00:00
#MARK: Constants
2024-06-28 03:16:37 +00:00
ROOT = Path(__file__).parent.resolve()
TOOLS_DIR = ROOT / "tools"
2024-06-28 03:16:37 +00:00
OUTDIR = "out"
YAML_FILE = "config/sly1.yaml"
BASENAME = "SCUS_971.98"
LD_PATH = f"{BASENAME}.ld"
ELF_PATH = f"{OUTDIR}/{BASENAME}"
MAP_PATH = f"{OUTDIR}/{BASENAME}.map"
PRE_ELF_PATH = f"{OUTDIR}/{BASENAME}.elf"
COMMON_INCLUDES = "-Iinclude -isystem include/sdk/ee -isystem include/gcc"
CC_DIR = f"{TOOLS_DIR}/cc/ee-gcc2.9-991111/bin"
COMMON_COMPILE_FLAGS = "-O2 -G0"
2024-06-28 03:16:37 +00:00
2024-06-28 04:09:58 +00:00
WINE = "wine"
GAME_GCC_CMD = f"{CC_DIR}/ee-gcc.exe -c {COMMON_INCLUDES} {COMMON_COMPILE_FLAGS} $in"
COMPILE_CMD = f"{WINE} {GAME_GCC_CMD}"
2024-06-28 03:16:37 +00:00
def clean():
2024-06-28 04:34:52 +00:00
"""
Clean all products of the build process.
"""
files_to_clean = [
".splache",
".ninja_log",
"build.ninja",
LD_PATH
]
for filename in files_to_clean:
if os.path.exists(filename):
os.remove(filename)
2024-06-28 03:16:37 +00:00
shutil.rmtree("asm", ignore_errors=True)
shutil.rmtree("assets", ignore_errors=True)
2024-06-28 04:09:58 +00:00
shutil.rmtree("obj", ignore_errors=True)
2024-06-28 03:16:37 +00:00
shutil.rmtree("out", ignore_errors=True)
def write_permuter_settings():
2024-06-28 04:34:52 +00:00
"""
Write the permuter settings file, comprising the compiler and assembler commands.
"""
with open("permuter_settings.toml", "w", encoding="utf-8") as f:
f.write(f"""compiler_command = "{COMPILE_CMD} -D__GNUC__"
2024-06-28 03:16:37 +00:00
assembler_command = "mips-linux-gnu-as -march=r5900 -mabi=eabi -Iinclude"
compiler_type = "gcc"
[preserve_macros]
[decompme.compilers]
"tools/build/cc/gcc/gcc" = "ee-gcc2.96"
2024-06-28 04:34:52 +00:00
""")
2024-06-28 03:16:37 +00:00
2024-06-28 04:34:52 +00:00
#MARK: Build
2024-06-28 03:16:37 +00:00
def build_stuff(linker_entries: List[LinkerEntry]):
2024-06-28 04:34:52 +00:00
"""
Build the objects and the final ELF file.
"""
2024-06-28 03:16:37 +00:00
built_objects: Set[Path] = set()
def build(
object_paths: Union[Path, List[Path]],
src_paths: List[Path],
task: str,
2024-06-28 04:09:58 +00:00
variables: Dict[str, str] = None,
2024-06-28 04:34:52 +00:00
implicit_outputs: List[str] = None,
2024-06-28 03:16:37 +00:00
):
2024-06-28 04:34:52 +00:00
"""
Helper function to build objects.
"""
# Handle none parameters
2024-06-28 04:09:58 +00:00
if variables is None:
variables = {}
2024-06-28 04:34:52 +00:00
if implicit_outputs is None:
implicit_outputs = []
# Convert object_paths to list if it is not already
2024-06-28 03:16:37 +00:00
if not isinstance(object_paths, list):
object_paths = [object_paths]
2024-06-28 04:34:52 +00:00
# Convert paths to strings
2024-06-28 03:16:37 +00:00
object_strs = [str(obj) for obj in object_paths]
2024-06-28 04:34:52 +00:00
# Add object paths to built_objects
2024-06-28 03:16:37 +00:00
for object_path in object_paths:
if object_path.suffix == ".o":
built_objects.add(object_path)
ninja.build(
outputs=object_strs,
rule=task,
inputs=[str(s) for s in src_paths],
variables=variables,
implicit_outputs=implicit_outputs,
)
2024-06-28 04:09:58 +00:00
ninja = ninja_syntax.Writer(open(str(ROOT / "build.ninja"), "w", encoding="utf-8"), width=9999)
2024-06-28 03:16:37 +00:00
2024-06-28 04:34:52 +00:00
#MARK: Rules
2024-06-28 03:16:37 +00:00
cross = "mips-linux-gnu-"
2024-06-28 04:09:58 +00:00
ld_args = "-EL -T config/undefined_syms_auto.txt -T config/undefined_funcs_auto.txt -Map $mapfile -T $in -o $out"
2024-06-28 03:16:37 +00:00
ninja.rule(
"as",
description="as $in",
command=f"cpp {COMMON_INCLUDES} $in -o - | {cross}as -no-pad-sections -EL -march=5900 -mabi=eabi -Iinclude -o $out",
)
ninja.rule(
"cc",
description="cc $in",
2024-06-28 04:34:52 +00:00
command=f"{COMPILE_CMD} -o $out && {cross}strip $out -N dummy-symbol-name",
2024-06-28 03:16:37 +00:00
)
ninja.rule(
"ld",
description="link $out",
command=f"{cross}ld {ld_args}",
)
ninja.rule(
"sha1sum",
description="sha1sum $in",
command="sha1sum -c $in && touch $out",
)
ninja.rule(
"elf",
description="elf $out",
command=f"{cross}objcopy $in $out -O binary",
)
2024-06-28 04:34:52 +00:00
# Build all the objects
2024-06-28 03:16:37 +00:00
for entry in linker_entries:
seg = entry.segment
if seg.type[0] == ".":
continue
if entry.object_path is None:
continue
if isinstance(seg, splat.segtypes.common.asm.CommonSegAsm) or isinstance(
seg, splat.segtypes.common.data.CommonSegData
):
build(entry.object_path, entry.src_paths, "as")
elif isinstance(seg, splat.segtypes.common.c.CommonSegC):
build(entry.object_path, entry.src_paths, "cc")
2024-06-28 03:16:37 +00:00
elif isinstance(seg, splat.segtypes.common.databin.CommonSegDatabin):
build(entry.object_path, entry.src_paths, "as")
elif isinstance(seg, splat.segtypes.common.rodatabin.CommonSegRodatabin):
build(entry.object_path, entry.src_paths, "as")
elif isinstance(seg, splat.segtypes.common.textbin.CommonSegTextbin):
build(entry.object_path, entry.src_paths, "as")
elif isinstance(seg, splat.segtypes.common.bin.CommonSegBin):
build(entry.object_path, entry.src_paths, "as")
2024-06-28 03:16:37 +00:00
else:
print(f"ERROR: Unsupported build segment type {seg.type}")
sys.exit(1)
ninja.build(
PRE_ELF_PATH,
"ld",
LD_PATH,
implicit=[str(obj) for obj in built_objects],
variables={"mapfile": MAP_PATH},
)
ninja.build(
ELF_PATH,
"elf",
PRE_ELF_PATH,
)
2024-06-28 04:34:52 +00:00
#MARK: Main
2024-06-28 04:09:58 +00:00
def main():
2024-06-28 04:34:52 +00:00
"""
Main function, parses arguments and runs the configuration.
"""
2024-06-28 03:16:37 +00:00
parser = argparse.ArgumentParser(description="Configure the project")
parser.add_argument(
"-c",
"--clean",
help="Clean extraction and build artifacts",
action="store_true",
)
args = parser.parse_args()
if args.clean:
clean()
2024-06-28 04:09:58 +00:00
return
2024-06-28 03:16:37 +00:00
split.main([YAML_FILE], modes="all", verbose=False)
linker_entries = split.linker_writer.entries
build_stuff(linker_entries)
write_permuter_settings()
2024-06-28 04:09:58 +00:00
if __name__ == "__main__":
main()