sm64

A Super Mario 64 decompilation
Log | Files | Refs | README | LICENSE

build.py (3252B)


      1 #!/usr/bin/env python3
      2 import sys
      3 from pathlib import Path
      4 import shlex
      5 import subprocess
      6 import tempfile
      7 import uuid
      8 import asm_processor
      9 
     10 # Boolean for debugging purposes
     11 # Preprocessed files are temporary, set to True to keep a copy
     12 keep_preprocessed_files = False
     13 
     14 dir_path = Path(__file__).resolve().parent
     15 asm_prelude_path = dir_path / "prelude.inc"
     16 
     17 all_args = sys.argv[1:]
     18 sep0 = next(index for index, arg in enumerate(all_args) if not arg.startswith("-"))
     19 sep1 = all_args.index("--")
     20 sep2 = all_args.index("--", sep1 + 1)
     21 
     22 asmproc_flags = all_args[:sep0]
     23 compiler = all_args[sep0:sep1]
     24 
     25 assembler_args = all_args[sep1 + 1 : sep2]
     26 assembler_sh = " ".join(shlex.quote(x) for x in assembler_args)
     27 
     28 
     29 compile_args = all_args[sep2 + 1 :]
     30 
     31 in_file = Path(compile_args[-1])
     32 del compile_args[-1]
     33 
     34 out_ind = compile_args.index("-o")
     35 out_file = Path(compile_args[out_ind + 1])
     36 del compile_args[out_ind + 1]
     37 del compile_args[out_ind]
     38 
     39 
     40 in_dir = in_file.resolve().parent
     41 opt_flags = [
     42     x for x in compile_args if x in {"-g3", "-g", "-O0", "-O1", "-O2", "-framepointer", "-KPIC"}
     43 ]
     44 if "-mips2" not in compile_args:
     45     opt_flags.append("-mips1")
     46 
     47 asmproc_flags += opt_flags + [str(in_file)]
     48 
     49 # Drop .mdebug and .gptab sections from resulting binaries. This makes
     50 # resulting .o files much smaller and speeds up builds, but loses line
     51 # number debug data.
     52 # asmproc_flags += ["--drop-mdebug-gptab"]
     53 
     54 # Convert encoding before compiling.
     55 # asmproc_flags += ["--input-enc", "utf-8", "--output-enc", "euc-jp"]
     56 
     57 with tempfile.TemporaryDirectory(prefix="asm_processor") as tmpdirname:
     58     tmpdir_path = Path(tmpdirname)
     59     preprocessed_filename = "preprocessed_" + uuid.uuid4().hex + in_file.suffix
     60     preprocessed_path = tmpdir_path / preprocessed_filename
     61 
     62     with preprocessed_path.open("wb") as f:
     63         functions, deps = asm_processor.run(asmproc_flags, outfile=f)
     64 
     65     if keep_preprocessed_files:
     66         import shutil
     67 
     68         keep_output_dir = Path("./asm_processor_preprocessed")
     69         keep_output_dir.mkdir(parents=True, exist_ok=True)
     70 
     71         shutil.copy(
     72             preprocessed_path,
     73             keep_output_dir / (in_file.stem + "_" + preprocessed_filename),
     74         )
     75 
     76     compile_cmdline = (
     77         compiler
     78         + compile_args
     79         + ["-I", str(in_dir), "-o", str(out_file), str(preprocessed_path)]
     80     )
     81 
     82     try:
     83         subprocess.check_call(compile_cmdline)
     84     except subprocess.CalledProcessError as e:
     85         print("Failed to compile file " + str(in_file) + ". Command line:")
     86         print()
     87         print(" ".join(shlex.quote(x) for x in compile_cmdline))
     88         print()
     89         sys.exit(55)
     90 
     91     asm_processor.run(
     92         asmproc_flags
     93         + [
     94             "--post-process",
     95             str(out_file),
     96             "--assembler",
     97             assembler_sh,
     98             "--asm-prelude",
     99             str(asm_prelude_path),
    100         ],
    101         functions=functions,
    102     )
    103 
    104     deps_file = out_file.with_suffix(".asmproc.d")
    105     if deps:
    106         with deps_file.open("w") as f:
    107             f.write(str(out_file) + ": " + " \\\n    ".join(deps) + "\n")
    108             for dep in deps:
    109                 f.write("\n" + dep + ":\n")
    110     else:
    111         try:
    112             deps_file.unlink()
    113         except OSError:
    114             pass