Install SDL2, write the Makefile, and get a window open before any math. Confirm the toolchain works before touching the iteration.
Install SDL2
sudo apt install libsdl2-devVerify the installation:
sdl2-config --versionA version string appears (2.0.x or later). If the command is not
found, the package did not install — check with apt list --installed | grep libsdl2.
Makefile
NAME = infinite
CC = gcc
CFLAGS = -Wall -Wextra -Werror -std=c99 $(shell sdl2-config --cflags)
LDFLAGS = $(shell sdl2-config --libs) -lm
SRCS = main.c mandelbrot.c julia.c view.c colour.c render.c
OBJS = $(SRCS:.c=.o)
all: $(NAME)
$(NAME): $(OBJS)
$(CC) $(OBJS) $(LDFLAGS) -o $(NAME)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f $(OBJS)
fclean: clean
rm -f $(NAME)
re: fclean all
.PHONY: all clean fclean resdl2-config --cflags expands to the include path SDL2 needs
(-I/usr/include/SDL2 -D_REENTRANT). sdl2-config --libs expands
to the linker flags (-lSDL2). Using the config script instead of
hardcoding paths keeps the Makefile portable across SDL2 installations.
game.h
Create game.h with the shared constants and struct forward declarations.
No function prototypes yet — add those as each file is written.
#ifndef GAME_H
#define GAME_H
#include <stdint.h>
#define WIDTH 800
#define HEIGHT 600
#define MAX_ITER 100
typedef struct s_view view_t;
typedef struct s_state state_t;
#endifWIDTH and HEIGHT control the window size and pixel buffer. Adjust
downward if renders feel slow; the math does not change.
Struct and typedef. typedef struct s_view view_t; creates an
alias: view_t means struct s_view. The full definition — the
member fields — comes later, in view.h. Declaring the name here
without defining its contents is a forward declaration: other
headers can reference view_t in a pointer or member without knowing
its internals, which prevents circular include dependencies.
game.h includes nothing from SDL2 and nothing from <math.h>. That
is the platform separation rule in practice: every file that includes
game.h — view.c, mandelbrot.c, julia.c, colour.c — stays
SDL2-free and compiles without a display server. SDL2 belongs only in
render.h (which includes it explicitly) and in main.c. Files
that use floating-point math functions include <math.h> directly;
the -lm in LDFLAGS above tells the linker to bring in the math
library at link time regardless of which source file pulls the header.
Window stub
Create main.c with a minimal SDL2 program that opens a window,
renders it black, and exits cleanly on SDL_QUIT (closing the window
or pressing Escape):
#include <SDL2/SDL.h>
#include "game.h"
int main(void)
{
SDL_Window *win;
SDL_Renderer *ren;
SDL_Event ev;
int running;
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
SDL_Log("SDL_Init: %s", SDL_GetError());
return (1);
}
win = SDL_CreateWindow("infinite", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, WIDTH, HEIGHT, 0);
if (!win) {
SDL_Log("SDL_CreateWindow: %s", SDL_GetError());
SDL_Quit();
return (1);
}
ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);
if (!ren) {
SDL_Log("SDL_CreateRenderer: %s", SDL_GetError());
SDL_DestroyWindow(win);
SDL_Quit();
return (1);
}
running = 1;
while (running) {
while (SDL_PollEvent(&ev)) {
if (ev.type == SDL_QUIT)
running = 0;
if (ev.type == SDL_KEYDOWN
&& ev.key.keysym.sym == SDLK_ESCAPE)
running = 0;
}
SDL_SetRenderDrawColor(ren, 0, 0, 0, 255);
SDL_RenderClear(ren);
SDL_RenderPresent(ren);
}
SDL_DestroyRenderer(ren);
SDL_DestroyWindow(win);
SDL_Quit();
return (0);
}make
./infiniteA black 800 × 600 window opens. Pressing Escape or closing the window
exits cleanly. If the compile fails with SDL2/SDL.h: No such file or directory, SDL2 is not installed or sdl2-config is not finding it.
The pattern — init, create window, create renderer, event loop, clean shutdown — is the foundation. Every SDL2 chapter reuses it.