Директива make include и генерация зависимостей с -MM - PullRequest
4 голосов
/ 10 мая 2010

Я хочу, чтобы правило сборки запускалось с помощью директивы include, если цель включения устарела или не существует.

В настоящее время make-файл выглядит следующим образом:

program_NAME := wget++
program_H_SRCS := $(wildcard *.h)
program_CXX_SRCS := $(wildcard *.cpp)
program_CXX_OBJS := ${program_CXX_SRCS:.cpp=.o}
program_OBJS := $(program_CXX_OBJS)

DEPS = make.deps

.PHONY: all clean distclean

all: $(program_NAME) $(DEPS)

$(program_NAME): $(program_OBJS)
    $(LINK.cc) $(program_OBJS) -o $(program_NAME)

clean:
    @- $(RM) $(program_NAME)
    @- $(RM) $(program_OBJS)
    @- $(RM) make.deps

distclean: clean

make.deps: $(program_CXX_SRCS) $(program_H_SRCS)
    $(CXX) $(CPPFLAGS) -MM $(program_CXX_SRCS) > make.deps

include $(DEPS)

Проблема в том, что похоже, что директива include выполняется перед правилом сборки make.deps, что фактически означает, что make либо не получает список зависимостей, если make.deps не существует, либо всегда получает make.deps изпредыдущая сборка, а не текущая.

Например:

$ make clean 
$ make
makefile:32: make.deps: No such file or directory
g++  -MM addrCache.cpp connCache.cpp httpClient.cpp wget++.cpp > make.deps
g++    -c -o addrCache.o addrCache.cpp
g++    -c -o connCache.o connCache.cpp
g++    -c -o httpClient.o httpClient.cpp
g++    -c -o wget++.o wget++.cpp
g++      addrCache.o connCache.o httpClient.o wget++.o -o wget++

Редактировать

Я прочитал документы для включениядиректива , и похоже, что если цель включения не существует, она продолжит обработку родительского make-файла, попытается построить цель, но мне не совсем понятно, как это работает:

Если включенный make-файл не может быть найден ни в одном из этих каталогов, генерируется предупреждающее сообщение, но оно не является немедленно фатальной ошибкой;обработка make-файла, содержащего include, продолжается.Как только он закончит чтение make-файлов, make попытается переделать все, что устарело или не существует.Смотрите раздел Как восстанавливаются файлы Makefile.Только после того, как он попытается найти способ переделать make-файл и потерпит неудачу, он сделает диагностику отсутствующего make-файла как фатальную ошибку.

ОТВЕТ

Thisявляется модификацией ответа, который я принял.Единственное, чего не хватало, так это того, что файлы зависимостей также зависят от источников и не будут восстановлены, если они не будут добавлены в включаемые файлы deps:

%.d: $(program_CXX_SRCS)
    @ $(CXX) $(CPPFLAGS) -MM $*.cpp | sed -e 's@^\(.*\)\.o:@\1.d \1.o:@' > $@

sed добавляет имяфайл .d в начале каждой строки зависимости, вот так:

foo.d foo.o: foo.cpp foo.h bar.h baz.h

Из этой удивительной статьи я получил представление об опасностях рекурсивного создания:

Рекурсивное созданиеСчитается вредным

Я также добавляю в make-файл следующее:

clean_list += ${program_SRCS:.c=.d}

# At the end of the makefile
# Include the list of dependancies generated for each object file
# unless make was called with target clean
ifneq "$(MAKECMDGOALS)" "clean"
-include ${program_SRCS:.c=.d}
endif

Ответы [ 3 ]

2 голосов
/ 10 мая 2010

Вы полагаетесь на неявное правило для компиляции ваших файлов .cpp. Вы должны переопределить его, чтобы использовать флаги -MM и -MF, которые создадут файл зависимостей.

%.o: %.cpp
    $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@ -MM -MF $@.d

Затем вы должны включить эти файлы зависимостей в Makefile, используя -include, который не выдаст ошибку, если файлы зависимостей еще не существуют (при первом или после очистки).

program_DEPS := $(program_OBJS:.o=.o.d)
-include $(program_DEPS)

И не забудьте добавить команду rm для файлов зависимостей в чистом правиле.

2 голосов
/ 10 мая 2010

Важным моментом, который я понял, является то, что make.deps из предыдущей сборки достаточно хороши . Подумайте об этом: для данного объектного файла список файлов зависимостей может быть изменен только в том случае, если ... один из старых файлов зависимостей был изменен. И если это так, то старый make.deps вызовет перестройку этого объектного файла, а если перестройка объектного файла также перестроит make.deps, то все будет обновлено. Вам не нужно перестраивать make.deps перед проверкой, чтобы увидеть, какие объекты нужно перестроить.

0 голосов
/ 10 мая 2010

Директивы include работают так же, как в C и C ++ - они обрабатываются до того, как что-то еще произойдет, для создания «реального» make-файла, который создает процессы. В частности, они обрабатываются до запуска каких-либо правил.

...