Search code examples
clinuxmakefile

compliling multi-path with make results in "No rule to make target" errors


when I tried to compile a program with make, something wrong occurs with the following code:

INC_DIR = ./include
BIN_DIR = ./bin
SRC_DIR = ./src1 ./src2 ./src3
OBJ_DIR = ./obj

SRC = $(foreach dir,$(SRC_DIR),$(wildcard $(dir)/*.c))
OBJ = $(patsubst %.c,${OBJ_DIR}/%.o,$(notdir ${SRC}))
TARGET1 = main
BIN_TARGET1 = ${BIN_DIR}/${TARGET1}
 CC = gcc
 CFLAGS = -g -Wall -I${INC_DIR}
 CFLAGS += -DLOG_USE_COLOR
 ${BIN_TARGET1}:${OBJ}
    $(CC) $(OBJ) -o $@
${OBJ_DIR}/%.o:$(foreach dir,$(SRC_DIR),$(dir)/%.c)
    $(CC) $(CFLAGS) -c $< -o $@
.PHONY:clean
clean:
    rm -rf ${BIN_TARGET1}
    rm -rf ${OBJ_DIR}/*.o
    @echo ${SRC}

With make, the result is: make: *** No rule to make target 'obj/main.o', needed by 'bin/main'. Stop. Do not understand what problem is. Thanks a lot!


Solution

  • The rule ${OBJ_DIR}/%.o:$(foreach dir,$(SRC_DIR),$(dir)/%.c), when applied to main.o, says that main.o depends on src1/main.c, src2/main.c and src3/main.c so even make obj/main.o will fail with:

    make: *** No rule to make target 'obj/main.o'.  Stop.
    

    Here are 3 alternatives:

    1. Use separate rules:
    ${OBJ_DIR}/%.o: src1/%.c
        $(CC) $(CFLAGS) -c $< -o $@
    ${OBJ_DIR}/%.o: src2/%.c
        $(CC) $(CFLAGS) -c $< -o $@
    ${OBJ_DIR}/%.o: src3/%.c
        $(CC) $(CFLAGS) -c $< -o $@
    

    You can use a template to generate these (left as exercise for user).

    1. Use VPATH to specify which directories to find your source files:
    SRC_DIR = ./src1 ./src2 ./src3
    VPATH = $(SRC_DIR)
    
    ${OBJ_DIR}/%.o: %.c
        $(CC) $(CFLAGS) -c $< -o $@
    
    1. Consider using a single src/ directory to avoid possible future name clash when you compile files from 3 different directories into obj/.