I'm looking to make a Makefile that can compile a C program on Unix (Ubuntu). That Makefile should include the SDL library (2.0), as well as SDL_image.
So here's my current Makefile :
CC = gcc
OBJECTS = $(patsubst %.c,%.o,$(wildcard *.c))
EXEC = main
LDFLAGS = `sdl2-config --libs` -L/usr/lib -lSDL2_image
CCFLAGS = `sdl2-config --cflags` -I/usr/include/SDL_image.h
$(EXEC): $(OBJECTS)
$(CC) $(LDFLAGS) $< -o $@
%.o: %.c
$(CC) -c $(CCFLAGS) $< -o $@
.PHONY: clean
clean:
rm -f $(OBJECTS) $(EXEC)
And here's my current code (minimal code just to test the Makefile):
#include <stdio.h>
#include <SDL.h>
#include <SDL2/SDL_image.h>
int main(int argc, char **argv) {
SDL_Window* window = NULL;
SDL_Surface* screenSurface = NULL;
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
printf("Initialization error: %s\n",SDL_GetError());
return 1;
}
window = SDL_CreateWindow("Test",SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,640, 480,SDL_WINDOW_SHOWN);
SDL_Quit();
return 0;
}
So when I write the command : make
I get errors on all of the SDL functions. Here's an example : undefined reference to `SDL_Init'
I have tried many things (such as different paths for the Include and Link in the Makefile), but nothing seems to work.
So my question is : How can I solve theses undefined references to SDL2 functions ?
You are specifying linker flags in the wrong order.
This is wrong:
LDFLAGS = `sdl2-config --libs` -L/usr/lib -lSDL2_image
$(EXEC): $(OBJECTS)
$(CC) $(LDFLAGS) $< -o $@
This is correct:
LIBS = `sdl2-config --libs` -L/usr/lib -lSDL2_image
$(EXEC): $(OBJECTS)
$(CC) $(LDFLAGS) $^ $(LIBS) -o $@
With GNU Binutils, the order of libraries is important. Libraries must come after the objects which have undefined references to symbols in those libraries. It sucks, it's stupid, but it's the way GNU Binutils works and you're stuck with it.
You want $^ instead of $<, because $< is only the first dependency.
Probably best to use pkg-config which can find SDL2_image for you:
LIBS = `pkg-config --libs sdl2 SDL2_image`
You probably want := not = when you invoke shell programs, this will expand the variable once, instead of every time it is used:
LIBS := $(shell pkg-config --libs sdl2 SDL2_image)
CFLAGS := $(shell pkg-config --cflags sdl2 SDL2_image)
Here is a cleaned up example, close to how I would write it:
# use := not =
# convention: objects, exec are lower-case because they're private
objects := $(patsubst %.c,%.o,$(wildcard *.c))
CFLAGS := $(shell pkg-config --cflags sdl2 SDL2_image)
LIBS := $(shell pkg-config --libs sdl2 SDL2_image)
# Don't define CC, because the default (cc) is fine
# It's probably linked to gcc on your system anyway
# = or := doesn't matter here
exec = main
# must use = here
depflags = -MF $(patsubst %.o,%.d,$@) -MMD -MP
-include $(wildcard *.d)
$(exec): $(objects)
$(CC) $(LDFLAGS) $^ $(LIBS) -o $@
%.o: %.c
$(CC) $(depflags) -c $(CCFLAGS) $< -o $@
.PHONY: clean
clean:
rm -f *.o *.d $(exec)
You inverted some compiler/linker options:
# linker options
LDFLAGS = `sdl2-config --libs` -I/usr/include/SDL_image.h
# compiler options
CCFLAGS = `sdl2-config --cflags` -L/usr/lib -lSDL2_image
It should be:
# linker options
LDFLAGS = `sdl2-config --libs` -L/usr/lib -lSDL2_image
# compiler options
CCFLAGS = `sdl2-config --cflags` -I/usr/include
Details:
-L Is to indicate to the linker where to find .so files
-l Is to link to a given library
-I Is to indicate to the compiler where to find .h files
As can be seen in the Catalogue of Built-In Rules:
Linking a single object file
nis made automatically fromn.oby running the linker (usually calledld) via the C compiler. The precise recipe used is:$(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)
and Variables Used by Implicit Rules:
LDFLAGS
Extra flags to give to compilers when they are supposed to invoke the linker,
ld, such as-L. Libraries (-lfoo) should be added to the LDLIBS variable instead.
So in this case -lSDL2_image should be set or added to LDLIBS, not LDFLAGS.