diff options
author | obskyr <powpowd@gmail.com> | 2018-06-18 18:24:19 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-06-18 18:24:19 +0200 |
commit | 3ac4eb121faaa3a0a390034d90ec446047ff623d (patch) | |
tree | 353c24e4f9d9ce57ab6cd238168de5aea443109d | |
parent | 246f56fd6b882b637559647a943aed976cd9e191 (diff) | |
parent | d6f9ff5cf7d815d4ff1beb9fef2ec932f382da79 (diff) |
Merge pull request #23 from obskyr/build-nicely
Fix makefile dependencies and make_shim.py
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 21 | ||||
-rw-r--r-- | tools/Makefile | 3 | ||||
-rw-r--r-- | tools/make_shim.c | 179 | ||||
-rw-r--r-- | tools/make_shim.py | 38 | ||||
-rw-r--r-- | tools/scan_includes.py | 72 |
6 files changed, 105 insertions, 209 deletions
@@ -22,7 +22,6 @@ shim.asm # build utilities tools/scan_includes tools/pkmncompress -tools/make_shim tools/gfx *.exe *.pyc @@ -11,7 +11,7 @@ RGBFIX := rgbfix sort_sym := tools/sort_symfile.sh #sort_sym := $(PYTHON3) tools/sort_sym.py -RGBASMFLAGS := -h -E -i $(BUILD)/ -DGOLD -DDEBUG=1 +RGBASMFLAGS := -h -E -i build/ -DGOLD -DDEBUG=1 tools/gfx := ROM := pokegold-spaceworld.gb @@ -21,8 +21,9 @@ CORRECTEDROM := $(ROM:%.gb=%-correctheader.gb) rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2)) DIRS := home engine data audio +ASMFILES := $(call rwildcard, $(DIRS), *.asm) OBJS := $(addprefix $(BUILD)/, gfx.o vram.o sram.o wram.o hram.o shim.o) -OBJS += $(patsubst %.asm, $(BUILD)/%.o, $(call rwildcard, $(DIRS), *.asm)) +OBJS += $(patsubst %.asm, $(BUILD)/%.o, $(ASMFILES)) GFX := $(patsubst %.png, $(BUILD)/%.2bpp, \ $(patsubst %.1bpp.png, $(BUILD)/%.1bpp, \ @@ -53,7 +54,7 @@ clean: # Remove files except for graphics. .PHONY: mostlyclean mostlyclean: - rm -rf $(ROM) $(CORRECTEDROM) $(OBJS) $(OBJS:.o=.d) $(ROMS:.gb=.sym) $(ROMS:.gb=.map) + rm -rf $(ROM) $(CORRECTEDROM) $(OBJS) $(ROMS:.gb=.sym) $(ROMS:.gb=.map) # Utilities .PHONY: coverage @@ -82,14 +83,14 @@ $(BASEROM): @echo "Please obtain a copy of Gold_debug.sgb and put it in this directory as $@" @exit 1 -$(BUILD)/shim.asm: tools/make_shim $(SHIM) | $$(dir $$@) - tools/make_shim -w $(filter-out $<, $^) > $@ +$(BUILD)/shim.asm: tools/make_shim.py $(SHIM) | $$(dir $$@) + $(PYTHON3) tools/make_shim.py -w $(filter-out $<, $^) > $@ $(BUILD)/gfx.o: | $(GFX) $(BUILD)/%.o: $(BUILD)/%.asm | $$(dir $$@) - $(RGBASM) $(RGBASMFLAGS) -M $(@:.o=.d) $(OUTPUT_OPTION) $< + $(RGBASM) $(RGBASMFLAGS) $(OUTPUT_OPTION) $< $(BUILD)/%.o: %.asm | $$(dir $$@) - $(RGBASM) $(RGBASMFLAGS) -M $(@:.o=.d) $(OUTPUT_OPTION) $< + $(RGBASM) $(RGBASMFLAGS) $(OUTPUT_OPTION) $< $(BUILD)/gfx/sgb/sgb_border_alt.2bpp: tools/gfx += --trim-whitespace $(BUILD)/gfx/sgb/sgb_border_gold.2bpp: tools/gfx += --trim-whitespace @@ -123,4 +124,8 @@ $(BUILD)/%.tilemap: %.png | $$(dir $$@) %/: mkdir -p $@ --include $(OBJS:.o=.d) +DEPENDENCY_SCAN_EXIT_STATUS := $(shell $(PYTHON3) tools/scan_includes.py $(ASMFILES) > dependencies.d; echo $$?) +ifneq ($(DEPENDENCY_SCAN_EXIT_STATUS), 0) +$(error Dependency scan failed) +endif +include dependencies.d diff --git a/tools/Makefile b/tools/Makefile index c591d9c..6c49ccb 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -4,8 +4,7 @@ CFLAGS := -O3 -std=c99 -Wall -Wextra tools := \ pkmncompress \ - gfx \ - make_shim + gfx all: $(tools) diff --git a/tools/make_shim.c b/tools/make_shim.c deleted file mode 100644 index a025905..0000000 --- a/tools/make_shim.c +++ /dev/null @@ -1,179 +0,0 @@ -#include <stdio.h> -#include <getopt.h> -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - -struct Section { - unsigned short end; - bool invalid; - char * name; - bool banked; -}; - -typedef struct Section section_t; - -// These functions are like strspn and strcspn, but from the right of the string rather than the left. -size_t strrspn(const char *s1, const char *s2) { - const char * _s1 = s1; - const char * _s2; - - while (*_s1++); - _s1--; - while (_s1 > s1) { - for (_s2 = s2; *_s2; _s2++) { - if (_s1[-1] == *_s2) { - break; - } - } - if (*_s2 == 0) - break; - _s1--; - } - - return _s1 - s1; -} - -size_t strrcspn(const char *s1, const char *s2) { - const char * _s1 = s1; - const char * _s2; - - while (*_s1++); - _s1--; - while (_s1 > s1) { - for (_s2 = s2; *_s2; _s2++) { - if (_s1[-1] == *_s2) - break; - } - if (*_s2) - break; - _s1--; - } - - return _s1 - s1; -} - -#define RIP(errmsg) { \ - fprintf(stderr, "%s:%d:%s: %s\n", fname, lineno, eline, errmsg); \ - if (file) fclose(file); \ - return 1; \ -} - -int main(int argc, char * argv[]) { - int ch; - char line[16*1024]; - char eline[16*1024]; - char *lineptr = NULL; - char *fname; - int lineno; - - section_t section_list[] = { - {0x4000, false, "ROM0", false}, - {0x8000, false, "ROMX", true}, - {0xA000, false, "VRAM", true}, - {0xC000, false, "SRAM", true}, - {0xD000, false, "WRAM0", false}, - {0xE000, false, "WRAMX", true}, - {0xFE00, true, "Echo RAM", false}, - {0xFEA0, false, "OAM", false}, - {0xFF80, true, "FEXX / IO", false}, - {0xFFFF, false, "HRAM", false}, - {} - }; - - while ((ch = getopt(argc, argv, "wdt")) != -1) { - switch (ch) { - case 'w': - case 'd': - section_list[4].end = 0xE000; - break; - case 't': - section_list[0].end = 0x8000; - break; - } - } - - for (int arg_idx = optind; arg_idx < argc; arg_idx++) { - int last = -1; - int curr; - eline[0] = 0; - lineno = 0; - fname = argv[arg_idx]; - FILE * file = fopen(fname, "r"); - if (file == NULL) - RIP("Unable to open file"); - while ((lineptr = fgets(line, sizeof(line), file)) != NULL) { - // Assume it's already sorted - lineno++; - unsigned short bank = 0; - unsigned short pointer = 0; - char * symbol = NULL; - char * end; - char * addr_p; - strcpy(eline, line); // Unmodified copy for tracebacks - *strrchr(eline, '\n') = 0; - - // line = line.split(";")[0].strip() - lineptr += strspn(lineptr, " \t\n"); - end = strchr(lineptr, ';'); - if (end) *end = 0; - lineptr[strrspn(lineptr, " \t\n")] = 0; - if (!*lineptr) - continue; - - // Get the bank, address, and symbol - end = lineptr + strcspn(lineptr, " \t\n"); - symbol = end + strspn(end, " \t\n"); - if (!*symbol) - RIP("Declaration not in \"bank:addr Name\" format"); - *end = 0; - addr_p = strchr(lineptr, ':'); - if (!addr_p) - RIP("Pointer not in bank:addr format"); - *addr_p++ = 0; - pointer = strtoul(addr_p, &end, 16); - if (pointer == 0 && end == addr_p) - RIP("Unable to parse symbol address"); - bank = strtoul(lineptr, &end, 16); - if (bank == 0 && end == lineptr) - RIP("Unable to parse bank number"); - curr = (bank << 14) | (pointer & 0x3fff); - - // Main loop - const char * section = NULL; - section_t * section_type; - - for (section_type = section_list; section_type->end; section_type++) { - if (pointer < section_type->end) { - if (section_type->invalid) { - fprintf(stderr, "Warning: cannot shim '%s' in section type '%s'\n", symbol, section_type->name); - } else { - section = section_type->name; - if (!section_type->banked) - bank = 0; - } - break; - } - } - - if (section == NULL) - // Found section, but cannot shim it - continue; - - if (curr != last) { - if (last != -1) - fputc('\n', stdout); - printf("SECTION \"Shim for %s\", %s[$%04X]", symbol, section, pointer); - if (bank) - printf(", BANK[$%04X]", bank); - printf("\n%s::\n", symbol); - last = curr; - } else - printf("%s::\n", symbol); - fflush(stdout); - } - fclose(file); - } - return 0; -} diff --git a/tools/make_shim.py b/tools/make_shim.py index 65d9362..e2e4bf2 100644 --- a/tools/make_shim.py +++ b/tools/make_shim.py @@ -5,19 +5,19 @@ import argparse from sys import stderr from collections import OrderedDict, namedtuple -Section = namedtuple('Section', ('end', 'invalud', 'banked')) -section_list = OrderedDict( - ROM0=Section(0x4000, False, False), - ROMX=Section(0x8000, False, True), - VRAM=Section(0xA000, False, True), - SRAM=Section(0xC000, False, True), - WRAM0=Section(0xD000, False, False), - WRAMX=Section(0xE000, False, True), - EchoRAM=Section(0xFE00, True, False), - OAM=Section(0xFEA0, False, False), - IO=Section(0xFF80, True, False), - HRAM=Section(0xFFFF, False, False) -) +Section = namedtuple('Section', ('end', 'invalid', 'banked')) +section_list = OrderedDict(( + ('ROM0', Section(0x4000, False, False)), + ('ROMX', Section(0x8000, False, True)), + ('VRAM', Section(0xA000, False, True)), + ('SRAM', Section(0xC000, False, True)), + ('WRAM0', Section(0xD000, False, False)), + ('WRAMX', Section(0xE000, False, True)), + ('EchoRAM', Section(0xFE00, True, False)), + ('OAM', Section(0xFEA0, False, False)), + ('IO', Section(0xFF80, True, False)), + ('HRAM', Section(0xFFFF, False, False)) +)) parser = argparse.ArgumentParser() parser.add_argument('files', nargs='+', type=argparse.FileType()) @@ -28,14 +28,14 @@ args = parser.parse_args() if args.w or args.d: - section_list['WRAM0'].end = 0xE000 + section_list['WRAM0'] = Section(0xE000, *section_list['WRAM0'][1:]) if args.t: - section_list['ROM0'].end = 0x8000 + section_list['ROM0'] = Section(0x8000, *section_list['ROM0'][1:]) -for file_name in args.files: - for line in open(file_name, "rt"): +for f in args.files: + for line in f: # Strip out the comment line = line.split(";")[0].strip() @@ -50,13 +50,13 @@ for file_name in args.files: pointer = int(pointer, 16) except ValueError: print("Error: Cannot parse line: %s" % line, file=stderr) - raise from None + raise section = None for name, section_type in section_list.items(): if pointer < section_type.end: if section_type.invalid: - print("Warning: cannot shim '%s' in section type '%s'" % (symbol, section_type['name']), file=stderr) + print("Warning: cannot shim '%s' in section type '%s'" % (symbol, name), file=stderr) section = False else: section = name diff --git a/tools/scan_includes.py b/tools/scan_includes.py new file mode 100644 index 0000000..e659dca --- /dev/null +++ b/tools/scan_includes.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""Get all the dependencies of RGBDS assembly files recursively, +and output them using Make dependency syntax. +""" + +# Script from the Telefang disassembly / fan translation project. + +from __future__ import print_function +from __future__ import unicode_literals + +import os +import re +import sys +if sys.version_info[0] < 3: + from codecs import open + +INCLUDE_RE = re.compile(r"^(?:[a-zA-Z0-9_.]+:?:?)?\s*(INC(?:LUDE|BIN))", re.IGNORECASE) + +def dependencies_in(asm_file_paths): + asm_file_paths = list(asm_file_paths) + dependencies = {} + + for path in asm_file_paths: + if path not in dependencies: + asm_dependencies, bin_dependencies = shallow_dependencies_of(path) + dependencies[path] = asm_dependencies | bin_dependencies + asm_file_paths += asm_dependencies + + return dependencies + +def shallow_dependencies_of(asm_file_path): + asm_dependencies = set() + bin_dependencies = set() + + with open(asm_file_path, 'r', encoding='utf-8') as f: + for line in f: + m = INCLUDE_RE.match(line) + if m is None: + continue + + keyword = m.group(1).upper() + line = line.split(';', 1)[0] + # RGBDS treats absolute(-looking) paths as relative, + # so leading slashes should be stripped. + path = line[line.index('"') + 1:line.rindex('"')].lstrip('/') + if keyword == 'INCLUDE': + asm_dependencies.add(path) + else: + if not os.path.isfile(path): + path = 'build/' + path + bin_dependencies.add(path) + + return asm_dependencies, bin_dependencies + +def main(): + if not len(sys.argv) > 1: + print("Usage: {} <paths to assembly files...>".format(os.path.basename(__file__))) + sys.exit(1) + + for path, dependencies in dependencies_in(sys.argv[1:]).items(): + # It seems that if A depends on B which depends on C, and + # C is modified, Make needs you to change the modification + # time of B too. That's the reason for the "@touch $@". + # This does mean mtimes on .asm files are updated when building, + # but the alternative opens up a whole can of problems. + if dependencies: + print("{}: {}\n\t@touch $@".format(path, ' '.join(dependencies))) + +if __name__ == '__main__': + main() |