Reputation: 33
I'm trying simple thing in makefile but unable to make it work. Following is the example file which is related to my requirement:
OBJDIR=obj
dummy_build_folder := $(shell mkdir -p $(OBJDIR))
CC = gcc
SRCS = 1/print.c \
2/add.c
INCLUDE = -I "./1/" \
-I "./2/" \
OBJS = $(addprefix $(OBJDIR)/,$(patsubst %.c,%.o,$(notdir $(SRCS))))
$(OBJDIR)/%.o: %.c
@-if not exist $(OBJDIR) mkdir $(OBJDIR) 1>NUL 2>NUL
$(CC) -c $(INCLUDE) $< -o $@
all: $(OBJS)
@-if not exist $(OBJDIR) mkdir $(OBJDIR) 1>NUL 2>NUL
@echo $(OBJS)
.PHONY : clean
clean:
rm $(OBJS)
When I'm trying to run the same I'm getting following error: "make: *** No rule to make target 'obj/print.o', needed by 'all'. Stop."
I tried of using "$(OBJDIR)/%.o: $(SRCS)" also, but here $< is pointing only to print.c, whereas $@ is incrementing to next file (i.e. print.o & add.o). Above is trying to compiling the print.c file twice and placing the output in both print.o and add.o
gcc -c -I "./1/" -I "./2/" 1/print.c -o obj/print.o
gcc -c -I "./1/" -I "./2/" 1/print.c -o obj/add.o
My Directory structure is:
RootFolder:
1/print.c
2/add.c
3/xyz.c (Don't want to compile this file)
Makefile
Also, I want to keep all the .o files in a different folder (./obj/*o) in above location.
Upvotes: 1
Views: 1238
Reputation: 136495
There are no dependencies between .o
files and the corresponding .c
files and no matching rules, this is what make
tells you by make: *** No rule to make target 'obj/print.o', needed by 'all'. Stop.
.
The pattern rule $(OBJDIR)/%.o : %.c
cannot match a .c
to .o
because the object files do not have the directory level present in the paths to .c
. That directory level is removed by that $(notdir ...)
call.
The %
(the stem) parts in the pattern rule must match. E.g. in $(OBJDIR)/1/print.o : 1/print.c
the stem is 1/print
. Whereas in $(OBJDIR)/print.o : 1/print.c
print
does not match 1/print
.
A good way to avoid this problem is to build the same directory structure for the output files as that of the source files.
Fixed Makefile
:
OBJDIR := obj
CC := gcc
SRCS := 1/print.c 2/add.c
INCLUDE := -I "./1/" -I "./2/"
OBJS := $(patsubst %.c,${OBJDIR}/%.o,${SRCS})
DEPS := $(patsubst %.c,${OBJDIR}/%.d,${SRCS})
all: $(OBJS)
@echo "Object files are $(OBJS)"
.SECONDEXPANSION:
# This rule creates the object file and its directory.
$(OBJS) : ${OBJDIR}/%.o : %.c | $$(dir $$@)
$(CC) -c $(INCLUDE) $< -MD -MP -o $@
${OBJDIR}/%.d : ;
${OBJDIR}/% :
mkdir -p $@
clean :
rm -rf ${OBJDIR}
.PHONY: all clean
-include ${DEPS}
Example usage:
$ mkdir 1 2
$ touch 1/print.c 2/add.c
$ make
mkdir -p obj/1/
gcc -c -I "./1/" -I "./2/" 1/print.c -MD -MP -o obj/1/print.o
mkdir -p obj/2/
gcc -c -I "./1/" -I "./2/" 2/add.c -MD -MP -o obj/2/add.o
Object files are obj/1/print.o obj/2/add.o
Notes:
| $$(dir $$@)
.-MD -MP
and -include ${DEPS}
bits.Upvotes: 2