mirror of
https://github.com/TheOnlyZac/sly1.git
synced 2024-11-23 05:39:54 +00:00
252 lines
6.7 KiB
Python
252 lines
6.7 KiB
Python
"""
|
|
Configure the project for building.
|
|
"""
|
|
#! /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
|
|
|
|
#MARK: Constants
|
|
ROOT = Path(__file__).parent.resolve()
|
|
TOOLS_DIR = ROOT / "tools"
|
|
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 = f"-x c++ -V 2.95.2 -O2 -G0"
|
|
|
|
WINE = "wine"
|
|
|
|
GAME_GCC_CMD = f"{CC_DIR}/ee-gcc.exe -c {COMMON_INCLUDES} {COMMON_COMPILE_FLAGS} $in"
|
|
COMPILE_CMD = f"{GAME_GCC_CMD}"
|
|
if sys.platform == "linux" or sys.platform == "linux2":
|
|
COMPILE_CMD = f"{WINE} {GAME_GCC_CMD}"
|
|
|
|
def clean():
|
|
"""
|
|
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)
|
|
|
|
shutil.rmtree("asm", ignore_errors=True)
|
|
shutil.rmtree("assets", ignore_errors=True)
|
|
shutil.rmtree("obj", ignore_errors=True)
|
|
shutil.rmtree("out", ignore_errors=True)
|
|
|
|
|
|
def write_permuter_settings():
|
|
"""
|
|
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__"
|
|
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"
|
|
""")
|
|
|
|
#MARK: Build
|
|
def build_stuff(linker_entries: List[LinkerEntry], skip_checksum=False):
|
|
"""
|
|
Build the objects and the final ELF file.
|
|
"""
|
|
built_objects: Set[Path] = set()
|
|
|
|
def build(
|
|
object_paths: Union[Path, List[Path]],
|
|
src_paths: List[Path],
|
|
task: str,
|
|
variables: Dict[str, str] = None,
|
|
implicit_outputs: List[str] = None,
|
|
):
|
|
"""
|
|
Helper function to build objects.
|
|
"""
|
|
# Handle none parameters
|
|
if variables is None:
|
|
variables = {}
|
|
|
|
if implicit_outputs is None:
|
|
implicit_outputs = []
|
|
|
|
# Convert object_paths to list if it is not already
|
|
if not isinstance(object_paths, list):
|
|
object_paths = [object_paths]
|
|
|
|
# Convert paths to strings
|
|
object_strs = [str(obj) for obj in object_paths]
|
|
|
|
# Add object paths to built_objects
|
|
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,
|
|
)
|
|
|
|
ninja = ninja_syntax.Writer(open(str(ROOT / "build.ninja"), "w", encoding="utf-8"), width=9999)
|
|
|
|
#MARK: Rules
|
|
cross = "mips-linux-gnu-"
|
|
|
|
ld_args = "-EL -T config/undefined_syms_auto.txt -T config/undefined_funcs_auto.txt -Map $mapfile -T $in -o $out"
|
|
|
|
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",
|
|
command=f"{COMPILE_CMD} -o $out && {cross}strip $out -N dummy-symbol-name",
|
|
)
|
|
|
|
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",
|
|
)
|
|
|
|
# Build all the objects
|
|
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")
|
|
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")
|
|
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,
|
|
)
|
|
|
|
if not skip_checksum:
|
|
ninja.build(
|
|
ELF_PATH + ".ok",
|
|
"sha1sum",
|
|
"checksum.sha1",
|
|
implicit=[ELF_PATH],
|
|
)
|
|
else:
|
|
print("Skipping checksum step")
|
|
|
|
#MARK: Main
|
|
def main():
|
|
"""
|
|
Main function, parses arguments and runs the configuration.
|
|
"""
|
|
parser = argparse.ArgumentParser(description="Configure the project")
|
|
parser.add_argument(
|
|
"-c",
|
|
"--clean",
|
|
help="Clean artifacts and build",
|
|
action="store_true",
|
|
)
|
|
parser.add_argument(
|
|
"-C",
|
|
"--only-clean",
|
|
help="Only clean artifacts",
|
|
action="store_true",
|
|
)
|
|
parser.add_argument(
|
|
"-s",
|
|
"--skip-checksum",
|
|
help="Skip the checksum step",
|
|
action="store_true",
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
if args.clean or args.only_clean:
|
|
clean()
|
|
if args.only_clean:
|
|
return
|
|
|
|
split.main([YAML_FILE], modes="all", verbose=False)
|
|
|
|
linker_entries = split.linker_writer.entries
|
|
|
|
if args.skip_checksum:
|
|
build_stuff(linker_entries, skip_checksum=True)
|
|
else:
|
|
build_stuff(linker_entries)
|
|
|
|
write_permuter_settings()
|
|
|
|
if __name__ == "__main__":
|
|
main()
|