I'm starting with make, and I made my first makefile to build my project. I don't know if it's the best way to do it or not, so I share with you my makefile to get your opinion on it:
Directory structure:
├── LICENSE ├── Makefile ├── objs │ └── parser.o ├── out │ ├── libsip.a │ └── parser.h ├── README.md ├── src │ ├── parser.c │ ├── parser.d │ └── parser.h └── tests ├── a.out ├── config.ini ├── libsip.a ├── parser.h └── test.c
Makefile:
SHELL = /bin/sh
CC := gcc
CFLAGS := -Wall
SRCSDIR := src
OBJSDIR := objs
OUTDIR := out
SRCS := $(wildcard $(SRCSDIR)/*.c)
OBJS := $(SRCS:$(SRCSDIR)/%.c=$(OBJSDIR)/%.o)
$(OUTDIR)/libsip.a : $(OBJS)
@mkdir -p $(@D)
ar cr -o $@ $^
cp -f src/parser.h $(OUTDIR)
$(OBJSDIR)/%.o : $(SRCSDIR)/%.c
@mkdir -p $(@D)
$(CC) $(CFLAGS) $< -c -o $@
$(CC) -MM $< > $(patsubst %.c, %.d, $<) && \
sed -i \ '1s|^|$(@D)/|' $(patsubst %.c, %.d, $<)
# use sed to add path to object dependencies
.PHONY : clean
clean :
rm -rf $(OBJSDIR) $(OUTDIR)
-include $(SRCS:%.c=%.d)
1 Answer 1
Use of the naked utilities (
cp, mkdir, sed
, and especiallyrm
) is usually frowned upon. It makes your makefile vulnerable to a path attack; aliasing may also result in some strangeness (for example, many distros come withrm
aliased torm -i
); also keep in mind that GNU make works nativly in Windows environment, which lacks those utilities.Typically what you do is to define them like
RM := /bin/rm
(conditionally tailoring for all expected platforms), etc and forget all the complications once and forever. Or use autotools.mkdir
fails if the target directory exists.-mkdir
is a usual practice.I prefer to have separate rules for dependencies and objects. Having them combined,
make
builds the.o
file based on old dependencies. You may end up in an inconsistent state.
-
\$\begingroup\$ thanks, mkdir has the option -p, so it don't return error when it fail. \$\endgroup\$KarimS– KarimS2015年02月02日 14:50:24 +00:00Commented Feb 2, 2015 at 14:50