Использование g++ с -MMD в make файле для автоматического создания зависимостей

Я знаю, что следующий make файл будет иметь предварительный процессор, автоматически генерирующий зависимости (в .d файлах) и включающий их в make файл (потому что мои комментарии курса говорят так), так что их не нужно автоматически поддерживать. Флаг -MMD отвечает за это. Я не получаю: В какой момент генерируются файлы .d? Нет никакой команды, в которой используется ${CXXFLAGS}. Предположительно, команды типа ${CXX} ${CXXFLAGS} -c x.C -o x.o будут автоматически выведены make для каждого из объектных файлов, но если это команды, которые генерируют файлы .d, мы бы уже не прошли точку, где зная зависимости xo, yo и zo может быть актуальным, если мы знаем только их, выполняя команды, которые генерируют эти .o файлы? (Скажем, есть файлы .h, которые makefile игнорирует, если оставить их самостоятельно или что-то.)

CXX = g++                     # compiler
CXXFLAGS = -g -Wall -MMD      # compiler flags
OBJECTS = x.o y.o z.o         # object files forming executable
DEPENDS = ${OBJECTS:.o=.d}    # substitutes ".o" with ".d"
EXEC = a.out                  # executable name

${EXEC} : ${OBJECTS}          # link step
    ${CXX} ${OBJECTS} -o ${EXEC}

-include ${DEPENDS}           # copies files x.d, y.d, z.d (if they exist)

Ответ 1

Предположительно, команды типа ${CXX} ${CXXFLAGS} -c x.C -o x.o будут автоматически выведены make для каждого из объектных файлов, но если это команды, которые генерируют .d файлы, разве мы уже не прошли бы точку, в которой знание зависимостей xo, yo и zo могли бы быть релевантными, если мы знаем только их, выполняя команды, которые генерируют эти .o файлы?

Вы здесь верны. Зависимости не присутствуют при первом запуске Makefile.

Но это не имеет значения - информация о зависимости нужна только тогда, когда файлы .o уже присутствуют, и вы изменили файл .h. При первом запуске Make все файлы .o должны быть построены в любом случае, и файлы .d будут сгенерированы одновременно.

После этого файлы .d выдадут информацию о зависимостях. Если заголовок изменен, информация о зависимости будет указывать Make, какие файлы .o необходимо восстановить. Если исходный файл изменен, то всегда нужно будет перестроить .o, и обновленная информация о зависимости будет сгенерирована в одно и то же время.

Ответ 2

Если вы когда-нибудь задавались вопросом, что делается makefile за спиной, используйте флаг -p и перенаправляйте вывод в файл, потому что это тонна вещей.

make -p foo > bar выгрузит все значения и правила переменной для make foo, а затем в bar покажет вам, какие команды выполняются для неявных правил. В вашем случае это показало бы вам, что правило .cpp.o или %.o: %.cpp (как ни странно, они оба там) вызывают $(COMPILE.cpp), который разрешает $(COMPILE.cc), который разрешает $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c. У кого есть интересное свойство, которое вы можете добавить в CXXFLAGS или CPPFLAGS, чтобы получить их в своих компиляторах .cpp.o, но не в CFLAGS, которые используются только в правилах .c.o, что мало что значит, потому что вы, вероятно, захотите ваши файлы C и файлы С++ обрабатываются по-разному (CC и CXX обычно устанавливаются и для разных компиляторов).

Ответ 3

Да, вы правы, что если вы удаляете файлы зависимостей, но оставляете файлы объектов на месте, тогда make будет работать с неполной информацией о зависимостях и может не воссоздать объектный файл, чьи заголовки изменены.

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

Единственный ответ на этот вопрос - дисциплина: при удалении файлов зависимостей всегда удаляйте файлы объектов. Вы можете использовать цель clean, чтобы помочь с этим.

clean::
        $(RM) *.o *.d

Альтернативно Кроме того, расскажите, как создать файлы зависимостей:

%.dep: %.cc
        $(CXX) -MM $(CPPFLAGS) $< | sed -e 's,\($*\)\.o[ :]*,\1.o [email protected]: ,g' > [email protected]

(команда sed гарантирует, что сама зависимость зависит от тех же источников, что и файл объекта).