I am looking for improvements for this basic makefile and directory structure. I know this is overkill and could be compiled with one line in a flat directory structure, but I want to use this as a learning exercise.
CC=g++
CFLAGS=-Wl,--no-as-needed -std=c++11
LIBS=-lpthread
SRC=$(PWD)/src
BUILDDIR=$(PWD)/build
OUTDIR=$(BUILDDIR)/bin
TEMPDIR=$(BUILDDIR)/tmp
MKDIR_P = mkdir -p
.PHONY: directories clean run
all: directories $(OUTDIR)/terminal
$(OUTDIR)/terminal: $(TEMPDIR)/main.o $(TEMPDIR)/terminal.o
$(CC) $(CFLAGS) $(TEMPDIR)/terminal.o $(TEMPDIR)/main.o $(LIBS) -o $(OUTDIR)/terminal
$(TEMPDIR)/main.o: $(SRC)/main.cpp $(SRC)/terminal.hpp
$(CC) -c $(CFLAGS) $(SRC)/main.cpp -o $(TEMPDIR)/main.o
$(TEMPDIR)/terminal.o: $(SRC)/terminal.cpp $(SRC)/terminal.hpp
$(CC) -c $(CFLAGS) $(SRC)/terminal.cpp -o $(TEMPDIR)/terminal.o
directories: ${OUTDIR} $(TEMPDIR)
$(OUTDIR):
${MKDIR_P} $(OUTDIR)
$(TEMPDIR):
${MKDIR_P} $(TEMPDIR)
clean:
rm -rf $(BUILDDIR)
run:
$(OUTDIR)/terminal
-
\$\begingroup\$ GNU make, I assume? \$\endgroup\$200_success– 200_success2015年01月10日 07:12:29 +00:00Commented Jan 10, 2015 at 7:12
-
\$\begingroup\$ Yes. <10 more characters for yes/no question.> \$\endgroup\$rileymat– rileymat2015年01月10日 17:43:14 +00:00Commented Jan 10, 2015 at 17:43
2 Answers 2
Stem rules:
Spelling out compilation rule for each object file is tedious and error prone.
$(TEMPDIR)/%.o: $(SRC)/%.c $(CXX) $(CFLAGS) -c $< -o $@
takes care about all of them.
Autodependencies:
Spelling out dependencies for each object file is tedious and error prone.
gcc
can do it for you:$(TEMPDIR)/main.d: $(SRC)/main.c $(CXX) $(CFLAGS) -MM -MT $< -o $@ -include $(TEMPDIR)/main.d
Of course you we don't want to spell it out for each source file, which naturally leads us to the next step.
Use macros. Shall you add more source files, only
FILES
needs to be modified.FILES = main.c terminal.c SOURCES = $(patsubst %,$(SRC)/%,$(FILES)) OBJECTS = $(patsubst %.c,$(TEMPDIR)/%.o,$(FILES)) DEPS = $(patsubst %.c.$(TEMPDIR)/%.d,$(FILES)) $(TEMPDIR)/%.o: $(SRC)/%.c $(CXX) $(CFLAGS) -c $< -o $@ $(TEMPDIR)/%.d: $(SRC)/%.c $(CXX) $(CFLAGS) -MM -MT $< -o $@ -include $(DEPS) $(TARGET): $(OBJECTS) $(CXX) $(LDFLAGS) $(OBJECTS) -o $(TARGET)
-
1\$\begingroup\$ Good review. The only point I think you may wish to add is that
rm -rf
is rather dangerous forclean
. Better would be to remove only the generated files. \$\endgroup\$Edward– Edward2015年01月11日 14:55:15 +00:00Commented Jan 11, 2015 at 14:55 -
\$\begingroup\$ @Edward Agreed. It is even better to define
RM = /bin/rm
. \$\endgroup\$vnp– vnp2015年01月12日 05:34:13 +00:00Commented Jan 12, 2015 at 5:34
You should pick a single make variable usage style and use it consistently. Personally I use $(...)
to avoid confusing it with shell variable ${...}
(as I use that much more frequently than command substitution).
You probably want to make all
as phony also.
Your run
target will fail if run first thing. Using run: $(OUTDIR)/terminal
will cause it to bootstrap the binary before using it.
GNU Make has built-in rules for building .c
files into .o
files which, if you want, you can use. Which means you just need to add the .h
files as prerequisites to the .o
files (if you don't autogenerate them) like this $(TEMPDIR)/main.o: $(SRC)/terminal.hpp
with no recipe.
As to autogenerating dependencies (which @vnp also mentions) you should read Auto-Dependency Generation.
These two rules
$(OUTDIR):
${MKDIR_P} $(OUTDIR)
$(TEMPDIR):
${MKDIR_P} $(TEMPDIR)
can be combined into
$(OUTDIR) $(TEMPDIR):
$(MKDIR_P) $@
You can avoid needing to manually run the directories
target by using order-only prerequisites on the needed directories.
$(OUTDIR)/terminal: $(TEMPDIR)/main.o $(TEMPDIR)/terminal.o | $(OUTDIR)
....
$(TEMPDIR)/main.o: $(SRC)/main.cpp $(SRC)/terminal.hpp | $(TEMPDIR)
....
$(TEMPDIR)/terminal.o: $(SRC)/terminal.cpp $(SRC)/terminal.hpp | $(TEMPDIR)
....
-
\$\begingroup\$ Well done review, especially the note about the order-only-prerequisites. I had not recalled that feature of gnu make. \$\endgroup\$Edward– Edward2015年01月11日 15:26:56 +00:00Commented Jan 11, 2015 at 15:26