Files
SplitBit-Emulator/makefile
T
AnachronautandClaude Opus 5 3f95056eec Three papercuts a visitor would hit first
Found by a review, all three confirmed by trying them rather than by
reading.

1. THE STRICT BUILD CLAIM WAS FALSE. The README says the sources build clean
   under -std=c11 -pedantic with -Wall -Wextra, and they did not: realpath is
   an XSI interface, and _POSIX_C_SOURCE=200809L does not reach it, so the
   assembler would not compile. The ordinary -Os build never saw it, because
   without -std=c11 the compiler's own default declares realpath anyway.

   _XOPEN_SOURCE=700 is POSIX.1-2008 plus XSI, and covers every file on its
   own. Narrowed by compiling each source with each candidate macro rather
   than by adding one and hoping.

   And 'make strict' now checks it, as part of 'make test'. The README makes
   a claim somebody may check by typing it, so the suite types it. Verified
   the check bites by putting the old macro back.

2. THE COSMOS README HAD NOT CAUGHT UP WITH THIS WEEK. It said there were no
   breakpoints and proposed writing a spare byte over an instruction - two
   commits after SWI osBreak was built, which does it without overwriting
   anything and is described correctly further down the same file. Its
   Current Scope said there was no native assembler and that self-hosting
   was the intended long-term milestone. And the streaming section spoke of
   a machine "one day going to assemble itself".

   All three now say what is true. Self-hosting is described as done, with
   what is left of it named: a linker, and an editor that knows what
   assembly is.

3. 'make run-hello' DID NOT WORK, and it is the one command the makefile's
   own header advertises. It was a pattern rule against $(BUILD)/%.bin,
   which worked while every program sat at the top of Programs/ and broke
   the moment they were filed into Examples/ - which I did, four commits ago,
   without trying it.

   The name is looked up among the programs now, so it is the program's name
   rather than its path, and an unknown one lists what there is instead of
   saying "No rule to make target".

The same sweep was run across all four documents for other claims this week
invalidated. The remaining "not yet" phrases are about faults that genuinely
are not defined yet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
2026-08-21 16:17:24 -04:00

149 lines
5.1 KiB
Makefile

# SplitBit Emulator and Assembler Makefile
# Anachronaut
# 10/16/2024
# Compiler and flags
CC ?= gcc
CFLAGS ?= -Wall -Os
PREFIX ?= /usr/local
# Have the compiler write out which headers each object depends on, so that
# editing a header rebuilds everything that includes it.
DEPFLAGS = -MMD -MP
# Both tools use POSIX interfaces that ISO C does not have: realpath, clock_gettime,
# strdup, dirname and getopt. Asking for POSIX.1-2008 by name means the build does
# not rely on the compiler happening to default to a mode where those are visible,
# and it survives someone overriding CFLAGS, which is why it is kept separate.
#
# _XOPEN_SOURCE=700 IS POSIX.1-2008, plus the XSI extensions. The plain
# _POSIX_C_SOURCE=200809L was here and is not quite enough: realpath is an XSI interface,
# so under -std=c11 -pedantic it went undeclared and the assembler would not compile. The
# ordinary build never noticed, because without -std=c11 the compiler's own default
# already declares it. The README makes a claim about the strict build, so 'make strict'
# below settles it rather than leaving it to be discovered.
POSIXFLAGS = -D_XOPEN_SOURCE=700
# Directories
SRC_DIR_EMU = Source/Emulator
SRC_DIR_ASM = Source/Assembler
SRC_DIR_DSK = Source/DiskTool
OBJ_DIR = Object
# Source files
EMU_SRCS = emulator.c io.c controller.c utility.c cpu.c bootstrap.c assembly.c
ASM_SRCS = Assembler.c assembly.c firstPass.c Assm-util.c secondPass.c
DSK_SRCS = SplitDisk.c
EMU_OBJS = $(EMU_SRCS:%.c=$(OBJ_DIR)/%.o)
ASM_OBJS = $(ASM_SRCS:%.c=$(OBJ_DIR)/%.o)
DSK_OBJS = $(DSK_SRCS:%.c=$(OBJ_DIR)/%.o)
# Output binary names
EMU_TARGET = SplitBit
ASM_TARGET = Assembler
DSK_TARGET = SplitDisk
# Default target: build both emulator and assembler
all: $(EMU_TARGET) $(ASM_TARGET) $(DSK_TARGET)
# Emulator binary
$(EMU_TARGET): $(EMU_OBJS)
$(CC) $(CFLAGS) -o $(EMU_TARGET) $(EMU_OBJS)
# Assembler binary
$(ASM_TARGET): $(ASM_OBJS)
$(CC) $(CFLAGS) -o $(ASM_TARGET) $(ASM_OBJS)
# Compile emulator source files to object files
$(OBJ_DIR)/%.o: $(SRC_DIR_EMU)/%.c
mkdir -p $(OBJ_DIR)
$(CC) $(CFLAGS) $(POSIXFLAGS) $(DEPFLAGS) -c $< -o $@
# Disk tool binary
$(DSK_TARGET): $(DSK_OBJS)
$(CC) $(CFLAGS) -o $(DSK_TARGET) $(DSK_OBJS)
# Compile disk tool source files to object files
$(OBJ_DIR)/%.o: $(SRC_DIR_DSK)/%.c
@mkdir -p $(OBJ_DIR)
$(CC) $(CFLAGS) $(POSIXFLAGS) $(DEPFLAGS) -c $< -o $@
# Compile assembler source files to object files
$(OBJ_DIR)/%.o: $(SRC_DIR_ASM)/%.c
mkdir -p $(OBJ_DIR)
$(CC) $(CFLAGS) $(POSIXFLAGS) $(DEPFLAGS) -c $< -o $@
# Pull in the header dependencies written out by the compiler above.
-include $(EMU_OBJS:.o=.d) $(ASM_OBJS:.o=.d) $(DSK_OBJS:.o=.d)
# ---- The strict build the README promises ----
#
# "The sources are ISO C and build clean under -std=c11 -pedantic with -Wall -Wextra."
# That is a claim somebody may check by typing it, so the suite checks it first. It was
# false when this target was written: realpath went undeclared under a feature test macro
# that did not reach far enough, which the ordinary -Os build never saw.
STRICT = -std=c11 -pedantic -Wall -Wextra -Werror $(POSIXFLAGS)
strict:
@for source in $(SRC_DIR_EMU)/*.c $(SRC_DIR_ASM)/*.c $(SRC_DIR_DSK)/*.c; do \
$(CC) $(STRICT) -c $$source -o /dev/null || exit 1; \
done
@echo "The sources build clean under -std=c11 -pedantic."
# Run the test suite against the programs in Programs/
test: $(EMU_TARGET) $(ASM_TARGET) $(DSK_TARGET) strict
@echo
@./Tests/run.sh
@echo
@./Tests/disk.sh
@echo
@./Tests/terminal.sh
@echo
@./Tests/native.sh
@echo
@./Tests/docs.sh
# Rebuild both tools with the address and undefined behaviour sanitizers and run
# the test suite under them. Slower than 'make test', and worth running before a
# release or after anything that touches memory handling.
#
# The sanitizers catch reads and writes off the end of an array, use after free,
# leaks, and undefined arithmetic. They also fill fresh allocations with a junk
# pattern, which is what turns a read of uninitialised memory from something that
# quietly works into something the tests notice.
#
# If the suite fails, the sanitizer binaries are deliberately left in place so
# that the failing case can be run again by hand. 'make' puts the normal ones back.
SANITIZE_FLAGS = -Wall -Wextra -g -O1 -fsanitize=address,undefined -fno-omit-frame-pointer
sanitize:
@$(MAKE) --no-print-directory clean
@$(MAKE) --no-print-directory CFLAGS="$(SANITIZE_FLAGS)"
@echo "Running the test suite under AddressSanitizer and UndefinedBehaviorSanitizer."
@./Tests/run.sh
@echo
@./Tests/terminal.sh
@$(MAKE) --no-print-directory clean
@$(MAKE) --no-print-directory
@echo "Sanitizer run finished cleanly. Normal binaries rebuilt."
# Record the current output of every test as the expected result.
# Only do this when the current output is known to be correct.
bless: $(EMU_TARGET) $(ASM_TARGET)
@./Tests/run.sh --bless
# Clean up object and binary files
clean:
rm -rf $(OBJ_DIR)
rm -rf Tests/build
rm -f $(EMU_TARGET) $(ASM_TARGET) $(DSK_TARGET)
# Install compiled binaries
install: $(EMU_TARGET) $(ASM_TARGET) $(DSK_TARGET)
mkdir -p "$(PREFIX)/bin"
install -m 755 $^ "$(PREFIX)/bin/"
# Phony targets
.PHONY: all clean install test bless sanitize