Makefile. Шаблон задачи для проекта с вложенными каталогами

Пусть у меня будет примерно такая структура:

  • src
    • main.cpp
    • dir
      • two.cpp
  • build
    • Makefile

Мой Makefile сейчас:

CC = g++
FLAGS = -MD

ROOT_DIR = ../src/
SUB_DIR = dir/

DIRS = $(ROOT_DIR) $(addprefix $(ROOT_DIR), $(SUB_DIR)) 
SRC = $(wildcard $(addsuffix *.cpp, $(DIRS)))
OBJ = $(patsubst $(ROOT_DIR)%.cpp, %.o, $(SRC))

build: $(OBJ)
    $(CC) $(FLAGS) -o main $(OBJ)

%.o : $(ROOT_DIR)%.cpp
    $(CC) $(FLAGS) -c $< -o $@

dir/%.o : $(ROOT_DIR)dir/%.cpp
    $(CC) $(FLAGS) -c $< -o $@

clean:
    rm -rf main *.o *.d $(SUB_DIR)
    @-mkdir $(SUB_DIR)

Здесь переменная OBJ содержит:

main.o dir/two.o

Он работает, но проблема в том, что у меня для исходников из директорий /src и /src/dir/ разные задачи:

%.o : $(ROOT_DIR)%.cpp
    $(CC) $(FLAGS) -c $< -o $@

dir/%.o : $(ROOT_DIR)dir/%.cpp
    $(CC) $(FLAGS) -c $< -o $@

Я пытаюсь объединить их просто убрав второй вариант, но тогда он не хочет находить two.cpp. Вот это работает:

%.o : $(ROOT_DIR)dir/two.cpp
    @echo $<
    @echo $@
    $(CC) $(FLAGS) -c $< -o $@

А это нет:

%.o : $(ROOT_DIR)%.cpp
    $(CC) $(FLAGS) -c $< -o $@

Падает с ошибкой:

make: *** No rule to make target 'dir/two.o', needed by 'build'.  Stop.

Не создавать же для каждого подкаталога отдельный шаблон задач?


Ответы (1 шт):

Автор решения: Neutrino Zh

Ещё немного почитав, понял как правильно использовать VPATH, что и сделал:

CC = g++
FLAGS = -MD -I src 

ROOT_DIR = ../src/
SUB_DIR = dir/

DIRS = $(ROOT_DIR) $(addprefix $(ROOT_DIR), $(SUB_DIR)) 
SRC = $(wildcard $(addsuffix *.cpp, $(DIRS)))
OBJ = $(patsubst $(ROOT_DIR)%.cpp, %.o, $(SRC))

build: directory $(OBJ)
    $(CC) $(FLAGS) -o main $(OBJ)

directory: 
    @mkdir -p $(SUB_DIR)

VPATH := ../src/
%.o : %.cpp
    $(CC) $(FLAGS) -c $< -o $@

clean:
    rm -rf main *.o *.d $(SUB_DIR)

Теперь всё работает как и должно!

→ Ссылка