build: replace premake with a hand-written Makefile; optimize FFT
Build system - Add a single hand-written Makefile (GNU make + gcc, pure C). Builds raylib from vendored source and links rspektrum with no premake/lua. Targets: all/run/test/bench/clean; release default, DEBUG=1 for debug; ARCH overridable (defaults to -march=x86-64-v3). - Remove premake entirely: rspektrum.make, raylib.make, build/premake5* binaries, build/premake5.lua, build/ecc/*. The generated top-level Makefile was gitignored, so hand-edits to it were silently lost. - Vendor raylib src/ into the repo (was gitignored -> fresh clones could not build). Commit only src/ (~16MB); examples/projects stay local. Verified: a build from the git-tracked tree alone succeeds offline. - Release flags bumped to -O3 -ffast-math with a portable arch baseline (x86-64-v3 = AVX2+FMA on x64, SSE2 on x86). Confirmed FMA/AVX codegen in fft.o. FFT optimization (src/fft.c) - Precompute twiddle factors and the bit-reversal permutation once per size, cached as a small plan table (FFTW's idea, lightweight). Removes the per-butterfly cexpf() and per-element bit-twiddling that dominated. - 3.6x faster on the mlnl_samples.wav STFT workload (2048-pt, -O2 same flags both sides): 81us -> 22us per FFT. With the new -O3/-ffast-math/ AVX2 release flags stacked: ~15us (5.5x vs the old -O2 baseline). - Verified vs a double-precision reference DFT: 1e-6 relative error, round-trip 2.4e-7. Drop-in: same FFT() signature. Tests/bench (bench/) - fft_verify.c: FFT vs reference DFT + round-trip check (make test). - fft_bench.c: times the real STFT workload (make bench). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
# rspektrum - hand-written Makefile (GNU make + gcc, no premake/lua).
|
||||
#
|
||||
# Quick start:
|
||||
# make # release build -> bin/Release/rspektrum
|
||||
# make DEBUG=1 # debug build -> bin/Debug/rspektrum
|
||||
# make run # build + launch
|
||||
# make test # build + run the DSP correctness tests
|
||||
# make bench # build + run the FFT benchmark over mlnl_samples.wav
|
||||
# make clean # remove build artifacts for the current config
|
||||
#
|
||||
# Override the toolchain or flags on the command line, e.g.
|
||||
# make CC=clang
|
||||
# make ARCH="-march=native" # bleeding-edge tune for your own machine
|
||||
#
|
||||
# Pure C project (raylib is vendored as source and compiled in). Linux/X11.
|
||||
|
||||
# ---- toolchain ----------------------------------------------------------
|
||||
CC ?= gcc
|
||||
AR ?= ar
|
||||
|
||||
# ---- config: release (default) or DEBUG=1 -------------------------------
|
||||
# ARCH is the portable baseline tune; override to -march=native for a local
|
||||
# build. x86-64-v3 == AVX2 + FMA (~2013+), the sweet spot for the float FFT.
|
||||
ARCH ?= -march=x86-64-v3
|
||||
|
||||
ifdef DEBUG
|
||||
BUILD := Debug
|
||||
OPT := -g
|
||||
DEFCONFIG := -DDEBUG
|
||||
else
|
||||
BUILD := Release
|
||||
OPT := -O3 -ffast-math $(ARCH)
|
||||
DEFCONFIG := -DNDEBUG
|
||||
STRIP := -s
|
||||
endif
|
||||
|
||||
BINDIR := bin/$(BUILD)
|
||||
OBJDIR := obj/$(BUILD)
|
||||
TARGET := $(BINDIR)/rspektrum
|
||||
RAYLIB := $(BINDIR)/libraylib.a
|
||||
|
||||
# ---- shared flags -------------------------------------------------------
|
||||
RAYLIB_SRC := build/external/raylib-master/src
|
||||
DEFINES := $(DEFCONFIG) -DPLATFORM_DESKTOP -DGRAPHICS_API_OPENGL_33 -D_GLFW_X11
|
||||
INCLUDES := -Isrc -Iinclude -I$(RAYLIB_SRC) -I$(RAYLIB_SRC)/external/glfw/include
|
||||
CFLAGS := -std=c17 -Wall -Wshadow $(OPT) $(DEFINES) $(INCLUDES)
|
||||
DEPFLAGS = -MMD -MP
|
||||
LDLIBS := -lpthread -lm -ldl -lrt -lX11
|
||||
LDFLAGS := $(STRIP)
|
||||
|
||||
# ---- sources ------------------------------------------------------------
|
||||
# App: every src/*.c except the non-Linux platform backends.
|
||||
APP_SRC := $(filter-out src/platform_win32.c src/platform_web.c,$(wildcard src/*.c))
|
||||
APP_OBJ := $(patsubst src/%.c,$(OBJDIR)/app/%.o,$(APP_SRC))
|
||||
|
||||
# raylib: explicit list of the modules we link (matches the vendored tree).
|
||||
RAY_MODULES := rcore rshapes rtextures rtext rmodels raudio rglfw
|
||||
RAY_OBJ := $(patsubst %,$(OBJDIR)/raylib/%.o,$(RAY_MODULES))
|
||||
|
||||
DEPS := $(APP_OBJ:.o=.d) $(RAY_OBJ:.o=.d)
|
||||
|
||||
# ---- top-level targets --------------------------------------------------
|
||||
.PHONY: all run test bench clean help
|
||||
.DEFAULT_GOAL := all
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(APP_OBJ) $(RAYLIB) | $(BINDIR)
|
||||
@echo "Linking $@"
|
||||
$(CC) $(LDFLAGS) -o $@ $(APP_OBJ) $(RAYLIB) $(LDLIBS)
|
||||
|
||||
$(RAYLIB): $(RAY_OBJ) | $(BINDIR)
|
||||
@echo "Archiving $@"
|
||||
$(AR) rcs $@ $(RAY_OBJ)
|
||||
|
||||
# ---- compile rules ------------------------------------------------------
|
||||
$(OBJDIR)/app/%.o: src/%.c | $(OBJDIR)/app
|
||||
@echo " CC $<"
|
||||
$(CC) $(CFLAGS) $(DEPFLAGS) -c $< -o $@
|
||||
|
||||
$(OBJDIR)/raylib/%.o: $(RAYLIB_SRC)/%.c | $(OBJDIR)/raylib
|
||||
@echo " CC $<"
|
||||
$(CC) $(CFLAGS) $(DEPFLAGS) -c $< -o $@
|
||||
|
||||
# ---- dirs ---------------------------------------------------------------
|
||||
$(BINDIR) $(OBJDIR)/app $(OBJDIR)/raylib:
|
||||
@mkdir -p $@
|
||||
|
||||
# ---- convenience --------------------------------------------------------
|
||||
run: $(TARGET)
|
||||
./$(TARGET)
|
||||
|
||||
# DSP tests/benchmarks (fft.c is standalone, so they link it directly with the
|
||||
# same release flags this Makefile uses).
|
||||
test:
|
||||
$(MAKE) -C bench test CC="$(CC)" CFLAGS="-O3 -ffast-math $(ARCH) -Wall"
|
||||
|
||||
bench:
|
||||
$(MAKE) -C bench bench CC="$(CC)" CFLAGS="-O3 -ffast-math $(ARCH) -Wall"
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJDIR) $(TARGET) $(RAYLIB)
|
||||
$(MAKE) -C bench clean
|
||||
|
||||
help:
|
||||
@echo "Targets: all (default), run, test, bench, clean"
|
||||
@echo "Configs: release (default), or 'make DEBUG=1'"
|
||||
@echo "Vars: CC, AR, ARCH (e.g. ARCH=-march=native)"
|
||||
|
||||
-include $(DEPS)
|
||||
Reference in New Issue
Block a user