A quick note:
> INCS=-I./
This is generally a bad idea, unless you're explicitly trying to override #include <stdio.h> with a local file (and there are better ways to do that). <> are for system files, "" are for local files.
So off the bat, your makefile example is better than most makefiles out there. I still see things that look like some dumb IDE wrote them with explicit .d and x.c: x.o rules littered about.
Though I do note you aren't taking advantage of the built-in makefile rules (which are defined in POSIX), and you aren't taking advantage of gcc's -MMD flag, which does the dependencies during compilation instead of a separate step. That eliminates much of the file:
LDLIBS=-lglfw -lGLEW
CFLAGS+=-std=gnu99 -g -ggdb -W -Wall -Wextra -pedantic
CFLAGS+=-MMD
CFLAGS+=$(INCS)
CFLAGS+=-march=native -mno-80387 -mfpmath=sse -O3
SRCS=$(wildcard *.c)
OBJS=$(SRCS:.c=.o)
EXECUTABLE=main
.PHONY: all clean
all: $(EXECUTABLE)
$(EXECUTABLE): $(OBJS)
$(CC) $(CFLAGS) $(LDLIBS) -o $@ $^
-include *.d
clean:
rm -f $(EXECUTABLE)
rm -f $(OBJS) *.d
Furthermore, I like to name my objects explicitly instead of using * .c, which lets you order them on the command line, if you find that makes a difference. In particular, if your executable is named the same as one of your C source files then you don't even need the link line, as long as the C source file is the first dependency:
LDLIBS=-lglfw -lGLEW
CFLAGS+=-std=gnu99 -g -ggdb -W -Wall -Wextra -pedantic
CFLAGS+=-MMD
CFLAGS+=$(INCS)
CFLAGS+=-march=native -mno-80387 -mfpmath=sse -O3
OBJS=main.o obj1.o obj2.o
.PHONY: all clean
all: main
main: $(OBJS)
-include *.d
clean:
rm -f $(EXECUTABLE)
rm -f $(OBJS) *.d
I tend to like to prefix variables with the thing you are making so that different executables in the same Makefile can have (drastically) different compilation parameters:
.PHONY: all clean
all: main
main: LDLIBS=-lglfw -lGLEW
main: CFLAGS+=-std=gnu99 -g -ggdb -W -Wall -Wextra -pedantic
main: CFLAGS+=-MMD
main: CFLAGS+=$(INCS)
main: CFLAGS+=-march=native -mno-80387 -mfpmath=sse -O3
main: OBJS=main.o obj1.o obj2.o
main: $(OBJS)
-include *.d
clean:
rm -f $(EXECUTABLE)
rm -f $(OBJS) *.d
If you have an embedded project that needs both compiling and cross-compiling that trick can work wonders.