Replace build scripts with a Makefile

Single Makefile supports native builds (pkg-config) and cross-compilation
(CROSS_COMPILE/PREFIX env vars). Fixes -Wformat-truncation and
-Wstringop-truncation warnings at -O2 by sizing current_file to match
audio_files (256) and replacing strncpy with snprintf.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Michael Smith 2026-02-13 11:54:36 +01:00
parent 2fd764f60f
commit cbe3d67132
6 changed files with 50 additions and 40 deletions

View File

@ -10,17 +10,23 @@ See `docs/sdlamp2-fsd.md` for the full functional specification and changelog.
## Build and Run ## Build and Run
**Dependencies:** SDL2, SDL2_image, FFmpeg libraries (libavformat, libavcodec, libavutil, libswresample). Installed via system package manager; resolved at build time with `sdl2-config` and `pkgconf`. **Dependencies:** SDL2, SDL2_image, FFmpeg libraries (libavformat, libavcodec, libavutil, libswresample). Installed via system package manager (native) or into the Buildroot sysroot (cross-compile).
```sh ```sh
./build.sh # macOS — builds to build/sdlamp2 make # native build — uses pkg-config
./build_aarch64.sh # Linux aarch64 variant make clean # remove build artifacts
./build/sdlamp2 [audio_directory] ./build/sdlamp2 [audio_directory]
``` ```
Cross-compilation inside the Docker toolchain container (where `CROSS_COMPILE` and `PREFIX` are set by the environment):
```sh
make # picks up CROSS_COMPILE and PREFIX automatically
```
The controls spritesheet (`controls.png`) is embedded in the binary. If an external `controls.png` exists in the current working directory it takes precedence, allowing custom skins. Audio directory defaults to cwd if not specified. The controls spritesheet (`controls.png`) is embedded in the binary. If an external `controls.png` exists in the current working directory it takes precedence, allowing custom skins. Audio directory defaults to cwd if not specified.
No test suite, no linter, no Makefile/CMake. No test suite, no linter.
## Architecture ## Architecture

32
Makefile Normal file
View File

@ -0,0 +1,32 @@
CC = $(CROSS_COMPILE)gcc
CFLAGS = -Wall -Wno-unused -O2
LDLIBS = -lSDL2 -lSDL2_image -lavformat -lavcodec -lavutil -lswresample
ifdef PREFIX
# Cross-compile: headers and libraries live under PREFIX
CFLAGS += -I$(PREFIX)/include -I$(PREFIX)/include/SDL2
LDLIBS := -L$(PREFIX)/lib $(LDLIBS)
else
# Native: use pkg-config
PKG_CONFIG ?= pkg-config
PKGS = sdl2 SDL2_image libavformat libavcodec libavutil libswresample
CFLAGS += $(shell $(PKG_CONFIG) --cflags $(PKGS))
LDLIBS = $(shell $(PKG_CONFIG) --libs $(PKGS))
endif
BUILD_DIR = build
TARGET = $(BUILD_DIR)/sdlamp2
.PHONY: all clean
all: $(TARGET)
$(TARGET): src/sdlamp2.c src/controls_png.h | $(BUILD_DIR)
$(CC) $(CFLAGS) -o $@ $< $(LDLIBS)
$(BUILD_DIR):
mkdir -p $@
clean:
rm -f $(TARGET)

View File

@ -1,15 +0,0 @@
#!/bin/sh
pushd build 2>&1 >/dev/null
gcc -Wall -Wno-unused -O0 -ggdb3 \
-o sdlamp2 \
`sdl2-config --cflags --libs` \
`pkgconf --cflags --libs libavformat` \
`pkgconf --cflags --libs libavcodec` \
`pkgconf --cflags --libs libavutil` \
`pkgconf --cflags --libs libswresample` \
-lSDL2_image \
../src/sdlamp2.c
popd 2>&1 >/dev/null

View File

@ -1,15 +0,0 @@
#!/bin/bash
pushd build 2>&1 >/dev/null
gcc -Wall -Wno-unused \
-o sdlamp2 \
`sdl2-config --cflags --libs` \
-I/usr/include/aarch64-linux-gnu -L/usr/lib/aarch64-linux-gnu -lavformat \
-I/usr/include/aarch64-linux-gnu -L/usr/lib/aarch64-linux-gnu -lavcodec \
-I/usr/include/aarch64-linux-gnu -L/usr/lib/aarch64-linux-gnu -lavutil \
-I/usr/include/aarch64-linux-gnu -L/usr/lib/aarch64-linux-gnu -lswresample \
-lSDL2_image \
../src/sdlamp2.c
popd 2>&1 >/dev/null

View File

@ -30,7 +30,7 @@ This document specifies the functional requirements for an SDL2 based media play
## 4. Design principles ## 4. Design principles
- Version control (git) must be used - Version control (git) must be used
- Compilation should be performed by a simple shell script or batch file, not a complicated build system like make or cmake - Compilation should be performed by a simple Makefile supporting both native and cross-compilation
- C source code files should be formatted using "Google" style with an additional change of `ColumnLimit` set to 100 - C source code files should be formatted using "Google" style with an additional change of `ColumnLimit` set to 100
- Less is more, minimize dependencies, avoid pulling in extra libraries, always talk through with owner first - Less is more, minimize dependencies, avoid pulling in extra libraries, always talk through with owner first
- Keep it simple, apply Casey Muratori's `semantic compression` principles, don't refactor too soon or write code that's too clever for its own good - Keep it simple, apply Casey Muratori's `semantic compression` principles, don't refactor too soon or write code that's too clever for its own good
@ -43,6 +43,10 @@ This document specifies the functional requirements for an SDL2 based media play
## 6. Changelog ## 6. Changelog
### 2026-02-13 — Replace build scripts with Makefile
- **Makefile**: Replaced `build.sh` (macOS) and `build_aarch64.sh` (Linux ARM) with a single `Makefile`. Native builds use `pkg-config` to resolve SDL2 and FFmpeg flags; cross-compilation uses `CROSS_COMPILE` and `PREFIX` environment variables set by the Docker/Buildroot toolchain.
### 2026-02-13 — Raw joystick fallback for non-standard controllers ### 2026-02-13 — Raw joystick fallback for non-standard controllers
- **Joystick fallback**: When no SDL GameController mapping exists for a connected device, the joystick is now opened directly via `SDL_JoystickOpen()` as a fallback. This fixes d-pad and face button input on devices like the Anbernic retro handheld whose GUID is not in SDL's GameController database. - **Joystick fallback**: When no SDL GameController mapping exists for a connected device, the joystick is now opened directly via `SDL_JoystickOpen()` as a fallback. This fixes d-pad and face button input on devices like the Anbernic retro handheld whose GUID is not in SDL's GameController database.

View File

@ -49,7 +49,7 @@ static SDL_bool paused = SDL_TRUE;
static Decoder decoder = {0}; static Decoder decoder = {0};
static char audio_dir[512] = "."; static char audio_dir[512] = ".";
static char current_file[512] = ""; static char current_file[256] = "";
static char audio_files[MAX_FILES][256]; static char audio_files[MAX_FILES][256];
static int num_audio_files = 0; static int num_audio_files = 0;
static int current_file_index = 0; static int current_file_index = 0;
@ -111,8 +111,7 @@ static void save_position(const char* filename, double seconds) {
snprintf(lines[num_lines], sizeof(lines[0]), "%s\t%.2f", filename, seconds); snprintf(lines[num_lines], sizeof(lines[0]), "%s\t%.2f", filename, seconds);
found = SDL_TRUE; found = SDL_TRUE;
} else { } else {
strncpy(lines[num_lines], line, sizeof(lines[0]) - 1); snprintf(lines[num_lines], sizeof(lines[0]), "%s", line);
lines[num_lines][sizeof(lines[0]) - 1] = '\0';
} }
num_lines++; num_lines++;
} }
@ -210,8 +209,7 @@ static void scan_audio_files(const char* dir) {
while ((entry = readdir(d)) != NULL && num_audio_files < MAX_FILES) { while ((entry = readdir(d)) != NULL && num_audio_files < MAX_FILES) {
if (entry->d_name[0] == '.') continue; if (entry->d_name[0] == '.') continue;
if (has_audio_extension(entry->d_name)) { if (has_audio_extension(entry->d_name)) {
strncpy(audio_files[num_audio_files], entry->d_name, 255); snprintf(audio_files[num_audio_files], sizeof(audio_files[0]), "%s", entry->d_name);
audio_files[num_audio_files][255] = '\0';
num_audio_files++; num_audio_files++;
} }
} }