Прежде всего вам нужно сослаться на файл зависимостей в вашем Makefile
.
Это можно сделать с помощью функции
SOURCES := $(wildcard *.cpp)
DEPENDS := $(patsubst %.cpp,%.d,$(SOURCES))
, который возьмет имя всех *.cpp
файлов, заменит и добавит расширение *.d
для обозначения вашей зависимости.
Тогда в вашем коде
-include $(DEPENDS)
-
говорит Makefile
не жаловаться, если файлы не существуют. Если они существуют, они будут включены и перекомпилированы ваши источники в соответствии с зависимостями.
Наконец, зависимости могут быть созданы автоматически с параметрами: -MMD -MP
для правил для создания файла объектов. Здесь вы можете найти полное объяснение. Что генерирует зависимости это MMD
; MP
, чтобы избежать некоторых ошибок. Если вы хотите перекомпилировать при обновлении системных библиотек, используйте MD
вместо MMD
.
В вашем случае вы можете попробовать:
main.o: main.cpp
clang++ $(CFLAGS) -MMD -MP -c main.cpp -o main.o
Если у вас есть больше файлов, лучше создать единое правило для создания объектных файлов. Что-то вроде:
%.o: %.cpp Makefile
clang++ $(CFLAGS) -MMD -MP -c $< -o $@
Вы также можете посмотреть на эти 2 великолепных ответа:
В вашем случае более подходящий Makefile
должен выглядеть следующим образом (могут быть некоторые ошибки, но дайте мне знать):
CXX = clang++
CXXFLAGS = -stdlib=libc++ -std=c++17
WARNING := -Wall -Wextra
PROJDIR := .
SOURCEDIR := $(PROJDIR)/
SOURCES := $(wildcard $(SOURCEDIR)/*.cpp)
OBJDIR := $(PROJDIR)/
OBJECTS := $(patsubst $(SOURCEDIR)/%.cpp,$(OBJDIR)/%.o,$(SOURCES))
DEPENDS := $(patsubst $(SOURCEDIR)/%.cpp,$(OBJDIR)/%.d,$(SOURCES))
# .PHONY means these rules get executed even if
# files of those names exist.
.PHONY: all clean
all: main
clean:
$(RM) $(OBJECTS) $(DEPENDS) main
# Linking the executable from the object files
main: $(OBJECTS)
$(CXX) $(WARNING) $(CXXFLAGS) $^ -o $@
#include your dependencies
-include $(DEPENDS)
#create OBJDIR if not existin (you should not need this)
$(OBJDIR):
mkdir -p $(OBJDIR)
$(OBJDIR)/%.o: $(SOURCEDIR)/%.cpp Makefile | $(OBJDIR)
$(CXX) $(WARNING) $(CXXFLAGS) -MMD -MP -c $< -o $@
РЕДАКТИРОВАТЬ, чтобы ответить на комментарии
В качестве другого вопроса, есть ли проблема с переписыванием определения DEPENDS как просто DEPENDS := $(wildcard $(OBJDIR)/*.d)
?
Хороший вопрос, мне потребовалось некоторое время, чтобы понять вашу точку зрения
С здесь
$(wildcard pattern…)
Эта строка, используемая в любом месте make-файла,
заменены разделенным пробелами списком имен существующих файлов, которые
соответствует одному из заданных шаблонов имен файлов. Если имя файла не существует
соответствует шаблону, то этот шаблон пропускается из выходных данных
функция подстановки.
Итак, wildcard
возвращает список имен файлов, соответствующих шаблону. patsubst
действует на строки, его не волнует, что это за строки: он используется как способ создания имен файлов зависимостей, а не самих файлов. В примере Makefile
, который я разместил, DEPENDS
фактически используется в двух случаях: при очистке с помощью make clean
и с include
, поэтому в этом случае они оба работают, потому что вы не используете DEPENDS
ни в одном правиле. Есть некоторые различия (я пытался бежать, и вы должны подтвердить). При DEPENDS := $(patsubst $(SOURCEDIR)/%.cpp,$(OBJDIR)/%.d,$(SOURCES))
, если вы запустите make clean
зависимостей *.d
, у которых нет соответствующего *.cpp
файла, он не будет удален, как при вашем изменении. Напротив, вы можете включить зависимости, не относящиеся к вашему *.cpp
файлу.
Я задавал эти вопросы : посмотрим ответы.
Если файлы .d
удаляются из-за неосторожности, но файлы .o
остаются, значит, у нас проблемы. В исходном примере, если main.d
удален, а затем cow.cpp
впоследствии изменен, make
не поймет, что ему нужно перекомпилировать main.o
, и, таким образом, он никогда не создаст заново файл зависимостей. Есть ли способ дешево создать файлы .d
без перекомпиляции объектных файлов? Если так, то мы могли бы воссоздать все /.d
файлы в каждой команде make?
Хороший вопрос снова.
Да, вы правы. На самом деле это была моя ошибка. Это происходит из-за правила
main: main.o
$(CXX) $(WARNING) $(CFLAGS) main.o -o main
на самом деле должно было быть:
main: $(OBJECTS)
$(CXX) $(WARNING) $(CXXFLAGS) $^ -o $@
, чтобы он был перекомпонован (исполняемый файл обновлен) всякий раз, когда один из объектов изменяется, и они будут меняться всякий раз, когда изменяется один их cpp
файл.
Остается одна проблема: если вы удалите свои зависимости, но не объекты, и измените только один или несколько заголовочных файлов (но не исходные файлы), тогда ваша программа не будет обновлена.
Я исправил и предыдущую часть ответа.
РЕДАКТИРОВАТЬ 2
Для создания зависимостей вы также можете добавить новое правило в Makefile
:
здесь является примером.