Understand the dependency levels of makefiles Assume that the project has the following files, where the first files is dependent on the files under it's category in the unordered list:


main.c


global.h         (contains enumerations and #define macros)
sdlevent.h       (generic header file)


sdlevent.c   (contains implementations of sdlevent.h)

sdlshape.h       (generic header file)


sdlshape.c   (contains implementations of sdlshape.h)




Now, I have the following makefile:

CC = gcc
CFLAGS = -g -w -std=c99
LIBS = -lSDL2 -lSDL2_image -lSDL2_ttf

SRCS = main.c sdlshape.c sdlevent.c
OBJS = $(SRCS:.c=.o)
EXE = play

all: $(EXE)

.c.o:
    $(CC) -c $(CFLAGS) $&lt;

$(EXE): $(OBJS)
    $(CC) -o $(EXE) $(OBJS) $(LIBS)

$(OBJS): global.h sdlevent.h sdlshape.h

run : all
    ./$(EXE)

clean:
    rm -f *.o *~ $(EXE)



  The target $(EXE) is dependent on the target .c.o. Do I absolutely need to define the target $(EXE) after the target .c.o?


I don't think so, because even though the target $(EXE) is dependent on the target $(OBJS), the target ($EXE) is declared before $(OBJS).
I have not divided up the header files into their .h and .c files because they are very small header files. 


I would advice against this. Dividing into header and source files is just something you do. If something deserves an own source file, it also deserves an own header file. If nothing else, future readers of your code will expect .h files to only contain declarations. If you really don't want to split them up, then include the .c files instead. That's not good, but at least you're not hiding what you're doing.

Also, I don't really see the need to manually write dependencies. If your project is big, look into CMake or something. If it is small, use a generic Makefile. Here is a small example that basically contains everything you'll ever need before it's time to move on to CMake:

# Configuration

EXE = play
CFLAGS = -g -Wall -Wextra -std=c11
LDLIBS = -lm
LDFLAGS =

# Don't touch anything below

# Every .c is a source file (dough)
SRC = $(wildcard *.c)
# Every source file should be compiled to an object file
OBJ = $(SRC:.c=.o)
# Every object file should have a dependency file
DEP = $(OBJ:.o=.d)

# Link the exe from the object files
$(EXE): $(OBJ)
    $(CC) $(LDFLAGS) $^ -o $@ $(LDLIBS)

# Generate dependencies for the object files
%.o: %.c
    $(CC) -MMD -MP -c $&lt; -o $@

# https://stackoverflow.com/q/2145590/6699433
.PHONY: clean

clean:
    $(RM) $(OBJ) $(DEP) $(EXE) *~

# Include the generated dependencies
-include $(DEP)


Note that you don't need to pass $(CFLAGS) to the CC commands. It's done automatically.

I used the above Makefile on this:

$ cat *.c *.h
/* bar.c */

#include "bar.h"
#include &lt;math.h&gt;

int bar(int a, int b) { return a*pow(b,3); }
/* foo.c */

#include "foo.h"
#include "bar.h"

int foo(int a, int b) { return a+bar(a,b); }
/* main.c */

#include "foo.h"

int main() { foo(1,2); }
/* bar.h */

#ifndef __BAR_H__
#define __BAR_H__

int bar(int a, int b);

#endif
/* foo.h */

#ifndef __FOO_H__
#define __FOO_H__

int foo(int, int);

#endif


I sacrificed a bit of readability to keep number of lines down. After running make I have a couple of .d files.

$ cat *.d
bar.o: bar.c bar.h

bar.h:
foo.o: foo.c foo.h bar.h

foo.h:

bar.h:
main.o: main.c foo.h

foo.h: