C ++ 11 — Понимание зависимостей Makefile (C ++)

Работая над проектом C ++, я заметил, что вносил изменения в один из заголовочных файлов, связанных в моем основном коде, но утилита make не регистрировала его. Мне пришлось заставить его компилироваться по-разному, учитывая изменения, используя «make — B».

Я хочу знать, почему это так; это из-за того, как написан мой make-файл, как мои файлы зависят друг от друга, от обоих, или нет?

Вот мой make-файл:

CXXFLAGS = -Wall -Werror -std=c++11 -pedantic -Wvla -g
//CXXFLAGS = -std=c++11

all:    main.o game.o zombie.o
g++ $(FLAGS)  game.o main.o zombie.o -o main $(CXXFLAGS)

game:   game.cpp
g++ $(FLAGS) -c game.cpp $(CXXFLAGS)

zombie: zombie.cpp
g++ $(FLAGS) -c zombie.cpp $(CXXFLAGS)

main:   main.cpp
g++ $(FLAGS) -c main.cpp pairing_heap.h $(CXXFLAGS)

Я внес изменения в pairing_heap.h
который включен в мой основной файл.

Почему make не заметил, что он должен снова скомпилироваться? Поскольку я чувствую, что это концептуальное недоразумение, я чувствовал, что нет необходимости включать изменения, которые я делал, или разницу в результатах, когда я делал «make — B». Это были простые вещи, такие как cout’s и cerr, включенные в новый pairing_heap.h, которые не собирались до принудительного использования.

Дайте мне знать, если мне нужно предоставить больше информации.

Спасибо.

1

Решение

Make действительно ничего не знает о каком-либо конкретном языке программирования или инструменте, поэтому он не понимает, что файлы C / C ++ зависят от заголовков, а также от исходных файлов. У него просто есть правила вида

target: dependencies
actions

Все, что он знает, это то, что файл target зависит от файлов, перечисленных в dependenciesи если какой-либо из этих файлов является более новым, команды в actions должен быть запущен для обновления target, Это действительно так — все, что делает make, исходит из этого простого представления о целевых файлах, зависимостях и действиях.

Сейчас является Более того — в make есть множество встроенных правил для часто используемых вещей, а также способы указания правил ‘pattern’ — правил, в которых цель содержит подстановочный знак, поэтому может использоваться для множества различных цели, которые зависят от других файлов со связанными именами.

Теперь в вашем случае у вас есть правило:

all:    main.o game.o zombie.o
g++ $(FLAGS)  game.o main.o zombie.o -o main $(CXXFLAGS)

который говорит переделать файл all, если он старше, чем файлы main.o, game.o или же zombie.o это должно выполнить команду. Это первое правило в файле, поэтому оно создается по умолчанию при вводе make,

Теперь у вас, вероятно, нет файла с именем all (если ты сделал make вероятно, ничего бы не сделал), но в целом это нормально, так как если он не существует, он явно не обновлен, поэтому команду нужно запустить.
Когда нужно выполнить команду, она также проверяет любую из зависимостей, чтобы увидеть, есть ли у них, в свою очередь, зависимости, которые являются более старыми (поэтому их необходимо перестраивать). Поскольку все эти файлы заканчиваются .oони соответствуют встроенному правилу, которое знает, как создать их из файла с тем же именем, за исключением окончания с .cpp, поэтому он выполняет эти действия, если (и только если) .cpp файл новее.

Теперь вы говорите: «А как насчет других моих правил — что они делают?» Ну, оказывается, они ничего не делают. Это правила для создания файлов с именем game, zombie, а также mainи, поскольку вы никогда не просите создавать эти файлы и от них ничего не зависит, они ничего не делают. Вы могли бы также удалить их.

Вы также спрашиваете: «Как сделать так, чтобы файл перестраивался при изменении файла заголовка?» Что ж, если вы добавите правило без действий (только цель и зависимости), оно просто добавит эти зависимости в другое правило (встроенное в данном случае), которое делает есть действие. Так что, если вы добавите строку вроде:

main.o: pairing_heap.h

(без действий), make добавит эту зависимость к встроенному правилу, которое знает, как построить main.o от main.cpp и запустим это правило (перекомпиляция main.cpp) если или main.cpp или же pairing_hep.h новее чем main.o — что именно то, что вы хотите.

0

Другие решения

Вы перечисляете pairing_heap.h в рецепте main, что не делает его зависимостью main (кроме того, вы никогда не должны передавать заголовки такому компилятору), для этого вам нужно написать правило следующим образом:

main:   main.cpp pairing_heap.h
g++ $(FLAGS) -c main.cpp $(CXXFLAGS)

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

CPPFLAGS := -MMD -MP
CXXFLAGS := -Wall -Werror -std=c++11 -pedantic -Wvla -g
SOURCES  := $(wildcard *.cpp)

main: $(SOURCES:.cpp=.o)

-include $(SOURCES:.cpp=.d)

который использует марку неявные правила и автоматическое создание зависимостей gcc / clang для создания исполняемого файла с именем main,

1