From 1e6af39797c19e98e40f308eafdb87c343df2418 Mon Sep 17 00:00:00 2001 From: Alex Bates Date: Thu, 14 Jan 2021 10:25:55 +0000 Subject: [PATCH] ninja *.bin --- Makefile | 18 ++++----- tools/build/build.py | 96 +++++++++++++++++++++++++++++++++++++------- 2 files changed, 91 insertions(+), 23 deletions(-) diff --git a/Makefile b/Makefile index b443762de2..1dbafc6723 100644 --- a/Makefile +++ b/Makefile @@ -156,19 +156,19 @@ test: $(ROM) %.Yay0: % @mkdir -p $(shell dirname $@) $(YAY0COMPRESS) $< $@ -$(BUILD_DIR)/%.bin.Yay0: %.bin - @mkdir -p $(shell dirname $@) - $(YAY0COMPRESS) $< $@ +# $(BUILD_DIR)/%.bin.Yay0: %.bin +# @mkdir -p $(shell dirname $@) +# $(YAY0COMPRESS) $< $@ # Data objects -$(BUILD_DIR)/%.bin.o: %.bin - @mkdir -p $(shell dirname $@) - $(LD) -r -b binary -o $@ $< +# $(BUILD_DIR)/%.bin.o: %.bin +# @mkdir -p $(shell dirname $@) +# $(LD) -r -b binary -o $@ $< # Compressed data objects -$(BUILD_DIR)/%.Yay0.o: $(BUILD_DIR)/%.bin.Yay0 - @mkdir -p $(shell dirname $@) - $(LD) -r -b binary -o $@ $< +# $(BUILD_DIR)/%.Yay0.o: $(BUILD_DIR)/%.bin.Yay0 +# @mkdir -p $(shell dirname $@) +# $(LD) -r -b binary -o $@ $< # Compile C files # $(BUILD_DIR)/%.c.o: %.c $(MDEPS) | $(GENERATED_HEADERS) diff --git a/tools/build/build.py b/tools/build/build.py index 49ff13ccbc..687db38eca 100644 --- a/tools/build/build.py +++ b/tools/build/build.py @@ -1,18 +1,49 @@ import re -import sys +import os, sys from glob import glob import ninja_syntax from argparse import ArgumentParser import asyncio from subprocess import PIPE -c_files = glob("src/**/*.c", recursive=True) +tools_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) +sys.path.append(tools_dir + "/n64splat") INCLUDE_ASM_RE = re.compile(r"_INCLUDE_ASM\([^,]+, ([^,]+), ([^,)]+)") # note _ prefix CPPFLAGS = "-Iinclude -Isrc -D _LANGUAGE_C -D _FINALROM -ffreestanding -DF3DEX_GBI_2 -D_MIPS_SZLONG=32" def obj(path: str): - return "$builddir/" + path + ".o" + if not path.startswith("$builddir/"): + path = "$builddir/" + path + return path + ".o" + +def list_objects(splat_config: str): + import argparse + import yaml + from pathlib import PurePath + + from split import initialize_segments + + # Load config + with open(splat_config) as f: + config = yaml.safe_load(f.read()) + + options = config.get("options") + assert options.get("ld_o_replace_extension", True) == False + + # Initialize segments + all_segments = initialize_segments(options, splat_config, config["segments"]) + + objects = set() + + for segment in all_segments: + for subdir, path, obj_type, start in segment.get_ld_files(): + path = PurePath(subdir) / PurePath(path) + #path = path.with_suffix(".o" if replace_ext else path.suffix + ".o") + + objects.add(str(path)) + + return objects async def shell(cmd: str): async with task_sem: @@ -23,7 +54,15 @@ async def shell(cmd: str): return stdout.decode("utf-8"), stderr.decode("utf-8") -async def build_c_file(c_file: str, rule: str, dsl_rule: str): +async def task(coro): + global num_tasks, num_tasks_done + + await coro + + num_tasks_done += 1 + print(f"\r{(num_tasks_done / num_tasks) * 100:.0f}%", end="") + +async def build_c_file(c_file: str): # preprocess c_file, but simply put an _ in front of INCLUDE_ASM and SCRIPT stdout, stderr = await shell(f"{cpp} {CPPFLAGS} '-DINCLUDE_ASM(...)=_INCLUDE_ASM(__VA_ARGS__)' '-DSCRIPT(...)=_SCRIPT(__VA_ARGS__)' {c_file} -o -") @@ -38,15 +77,15 @@ async def build_c_file(c_file: str, rule: str, dsl_rule: str): s_deps.append("asm/nonmatchings/" + eval(match[1]) + "/" + match[2] + ".s") # add build task to ninja - n.build(obj(c_file), dsl_rule if uses_dsl else rule, c_file, implicit=s_deps) + n.build(obj(c_file), "cc_dsl" if uses_dsl else "cc", c_file, implicit=s_deps) -async def task(coro): - global num_tasks, num_tasks_done +def build_yay0_file(bin_file: str): + yay0_file = f"$builddir/{os.path.splitext(bin_file)[0]}.Yay0" + n.build(yay0_file, "yay0compress", bin_file, implicit=["tools/Yay0compress"]) + build_bin_object(yay0_file) - await coro - - num_tasks_done += 1 - print(f"\r{(num_tasks_done / num_tasks) * 100:.0f}%", end="") +def build_bin_object(bin_file: str): + n.build(obj(bin_file), "bin", bin_file) async def main(): global n, cpp, task_sem, num_tasks, num_tasks_done @@ -86,14 +125,43 @@ async def main(): deps="gcc") n.newline() - # build all the things! concurrently! + n.rule("yay0compress", + command=f"tools/Yay0compress $in $out", + description="compress $in") + n.newline() + + n.rule("bin", + command="${cross}ld -r -b binary $in -o $out", + description="bin $in") + n.newline() + + objects = list_objects("tools/splat.yaml") # no .o extension! + + c_files = (f for f in objects if f.endswith(".c")) # glob("src/**/*.c", recursive=True) + yay0_files = (os.path.splitext(f)[0] + ".bin" for f in objects if f.endswith(".Yay0")) + bin_files = (f for f in objects if f.endswith(".bin")) + + # TODO: build elf + + n.comment("bin") + for f in bin_files: + build_bin_object(f) + n.newline() + + n.comment("yay0") + for f in yay0_files: + build_yay0_file(f) + n.newline() + + # build slow tasks concurrently + n.comment("c") tasks = [ - *(task(build_c_file(c_file, "cc", "cc_dsl")) for c_file in c_files), + *(task(build_c_file(f)) for f in c_files), ] num_tasks = len(tasks) num_tasks_done = 0 await asyncio.gather(*tasks) - print(" done") + print("") if __name__ == "__main__": asyncio.run(main())