I\'ve trying to learn the \"best practice\" makefile\'s for a project.
Please review my Makefile file below and suggest changes to enhance it.
The dir layout:>
Here is a suggestion for a revised makefile, tested slightly on a 7-year-old version of Linux (RHEL 5):
# Generic makefile
TARGETS=tengine test2
all: ${TARGETS}
help:
@echo ""
@echo "make - builds ${TARGETS}"
@echo "make tengine - builds tengine"
@echo "make test2 - builds test2"
@echo "make clean - deletes prior build"
@echo "make help - prints this help"
# Switches:
INC=-I/usr/include/hiredis
LIB=-lhiredis
SUBDIRS=obj deps bin
LNK=gcc -g -Wl,--warn-common
DEBUG=1
ifdef DEBUG
CFLAGS=-Wall -Winline -pipe -g -DDEBUG #-pedantic -pg
else
CFLAGS=-Wall -Winline -pipe -O3 -march=native -funroll-all-loops \
-finline-functions #-pedantic
endif
#CXXFLAGS=$(CFLAGS)
# Generic rules:
obj/%.o: src/%.c
@echo Compiling $@
@mkdir -p $(SUBDIRS)
$(CC) $(CFLAGS) $(INC) -MMD -MF '$(patsubst src/%.c,deps/%.d,$<)' -o $@ -c $<
obj/%.o: src/%.cc
@echo Compiling $@
@mkdir -p $(SUBDIRS)
$(CXX) $(CXXFLAGS) $(INC) -MMD -MF '$(patsubst src/%.c,deps/%.d,$<)' -o $@ -c $<
${TARGETS}: %:bin/%
# Specific target rules:
bin/tengine: obj/main.o obj/tengine.o
$(LNK) $^ $(LIB) -o $@
bin/test2: obj/main.o obj/test2.o
$(LNK) $^ $(LIB) -o $@
clean:
rm -f *~ src/*~ gmon.out
rm -fr $(SUBDIRS)
-include deps/*.d
Some notes:
A key problem with the original was that the dependency were generated, but not used. This has been fixed using -include deps/*.d (at the end).
Now that deps/*.d is used, the makefile doesn't need to have the src/%.h cases.
The original was also putting garbage into these files: in $(patsubst src/%,obj/%,%(patsubst %.cc,%.o,$<)) the third % should have been a $.
In the revised version, the dependencies are generated at the same time as the object, using -MMD. This is quicker, shortens the makefile, and adds some DRY.
Shortened INC: why bother including the standard system include directories? And in fact gcc will apparently ignore your -I /usr/include -I /usr/local/include anyway.
Removed your two different definitions of OBJS. Not needed, and potentially confusing. Used $^ instead.
It is always a good idea for make clean to completely undo everything make does, so you are left with what you started. But the sub-directories obj/ and deps/ were being created, and never deleted. Also, bin/ was pre-supposed to exist.
For the linking, added $(LNK), with LNK=gcc -g -Wl,--warn-common (but you may not want the warnings). AFAIK, all the other usual $(CFLAGS) are ignored for links.
Removed comments, which were (mostly) distracting.
Repeated twice make;make now gives make: Nothing to be done for ....
See also gcc dependency generation for a different output directory.