summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorobskyr <powpowd@gmail.com>2018-06-18 18:24:19 +0200
committerGitHub <noreply@github.com>2018-06-18 18:24:19 +0200
commit3ac4eb121faaa3a0a390034d90ec446047ff623d (patch)
tree353c24e4f9d9ce57ab6cd238168de5aea443109d
parent246f56fd6b882b637559647a943aed976cd9e191 (diff)
parentd6f9ff5cf7d815d4ff1beb9fef2ec932f382da79 (diff)
Merge pull request #23 from obskyr/build-nicely
Fix makefile dependencies and make_shim.py
-rw-r--r--.gitignore1
-rw-r--r--Makefile21
-rw-r--r--tools/Makefile3
-rw-r--r--tools/make_shim.c179
-rw-r--r--tools/make_shim.py38
-rw-r--r--tools/scan_includes.py72
6 files changed, 105 insertions, 209 deletions
diff --git a/.gitignore b/.gitignore
index 0df1fa6..5b46e94 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,7 +22,6 @@ shim.asm
# build utilities
tools/scan_includes
tools/pkmncompress
-tools/make_shim
tools/gfx
*.exe
*.pyc
diff --git a/Makefile b/Makefile
index 37561a9..8888cb5 100644
--- a/Makefile
+++ b/Makefile
@@ -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()