Как я могу заставить Makefile автоматически пересобирать исходные файлы, содержащие модифицированный заголовочный файл? (В C / C ++)

У меня есть следующий make-файл, который я использую для создания программы (на самом деле kernel), над которой я работаю. Это с нуля, и я изучаю процесс, поэтому он не идеален, но я думаю, что он достаточно мощный на данный момент для моего уровня опыта написания make-файлов.

AS = nasm CC = gcc LD = ld TARGET = core BUILD = build SOURCES = source INCLUDE = include ASM = assembly VPATH = $(SOURCES) CFLAGS = -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions \ -nostdinc -fno-builtin -I $(INCLUDE) ASFLAGS = -f elf #CFILES = core.c consoleio.c system.c CFILES = $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) SFILES = assembly/start.asm SOBJS = $(SFILES:.asm=.o) COBJS = $(CFILES:.c=.o) OBJS = $(SOBJS) $(COBJS) build : $(TARGET).img $(TARGET).img : $(TARGET).elf c:/python26/python.exe concat.py stage1 stage2 pad.bin core.elf floppy.img $(TARGET).elf : $(OBJS) $(LD) -T link.ld -o [email protected] $^ $(SOBJS) : $(SFILES) $(AS) $(ASFLAGS) $< -o [email protected] %.o: %.c @echo Compiling $<... $(CC) $(CFLAGS) -c -o [email protected] $< #Clean Script - Should clear out all .o files everywhere and all that. clean: -del *.img -del *.o -del assembly\*.o -del core.elf 

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

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

Я слышал, что у GCC есть некоторые команды, чтобы сделать это возможным (так что makefile может каким-то образом определить, какие файлы нужно перестраивать), но я не могу на всю жизнь найти реальный пример реализации. Может ли кто-нибудь опубликовать решение, которое позволит это поведение в make-файле?

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

Как уже указывалось в другом месте на этом сайте, см. Эту страницу: http://make.paulandlesley.org/autodep.html

Короче говоря, gcc может автоматически создавать файлы зависимостей .d для вас, которые представляют собой fragmentы мини-файла makefile, содержащие зависимости .c файла, который вы скомпилировали. Каждый раз, когда вы меняете файл .c и компилируете его, файл .d будет обновлен.

Помимо добавления флага -M в gcc, вам нужно включить файлы .d в make-файл (как писал Крис выше). На странице есть несколько более сложных проблем, которые решаются с помощью sed, но вы можете их игнорировать и выполнять «очистить», чтобы очистить файлы .d, когда вы жалуетесь на невозможность создания файла заголовка, который больше не существует ,

Вы могли бы добавить команду «make depend», как заявили другие, но почему бы не получить gcc для создания зависимостей и компиляции в одно и то же время:

 DEPS := $(COBJS:.o=.d) -include $(DEPS) %.o: %.c $(CC) -c $(CFLAGS) -MM -MF $(patsubst %.o,%.d,[email protected]) -o [email protected] $< 

Параметр '-MF' указывает файл для хранения зависимостей.

Черточка в начале «-include» говорит Make продолжить, когда файл .d не существует (например, при первой компиляции).

Заметьте, что в gcc есть ошибка в отношении опции -o. Если вы obj/_file__c.o имя файла объекта obj/_file__c.o то сгенерированный _file_.d прежнему будет содержать _file_.o , а не obj/_file_c.o .

Это эквивалентно ответу Криса Додда , но использует другое соглашение об именах (и по совпадению не требует волшебства sed . Скопировано из более позднего дубликата .


Если вы используете компилятор GNU, компилятор может собрать список зависимостей для вас. Фрагмент файла:

 depend: .depend .depend: $(SOURCES) rm -f ./.depend $(CC) $(CFLAGS) -MM $^>>./.depend; include .depend 

Существует также инструмент makedepend , но я никогда не любил его столько, сколько gcc -MM

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

 %.o: %.c @echo Compiling $<... $(CC) $(CFLAGS) -c -o [email protected] $< foo.c: bar.h # And so on... 

Помимо того, что сказал @mipadi, вы также можете изучить использование опции « -M » для создания записи зависимостей. Вы даже можете сгенерировать их в отдельный файл (возможно, «depend.mk»), который затем включаете в make-файл. Или вы можете найти правило « make depend », которое редактирует make-файл с правильными зависимостями (условия Google: «не удалять эту строку» и зависеть).

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

 $(OBJDIR)/%.d: %.c $(CC) -MM -MG $(CPPFLAGS) $< | sed -e 's,^\([^:]*\)\.o[ ]*:,$(@D)/\1.o $(@D)/\1.d:,' >[email protected] ifneq ($(MAKECMDGOALS),clean) include $(SRCS:%.c=$(OBJDIR)/%.d) endif 

в вашем файле.

Ни один из ответов не работал для меня. Например, ответ Мартина Фидо предполагает, что gcc может создавать файл зависимостей, но когда я попытался создать для него пустые (нулевые байты) объектные файлы без каких-либо предупреждений или ошибок. Это может быть ошибка gcc. Я нахожусь

$ gcc –version gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-16)

Итак, вот мой полный Makefile, который работает для меня; это комбинация решений + то, о чем никто не упоминал (например, «правило замены суффикса», указанное как .cc.o :):

 CC = g++ CFLAGS = -Wall -g -std=c++0x INCLUDES = -I./includes/ # LFLAGS = -L../lib # LIBS = -lmylib -lm # List of all source files SRCS = main.cc cache.cc # Object files defined from source files OBJS = $(SRCS:.cc=.o) # # define the executable file MAIN = cache_test #List of non-file based targets: .PHONY: depend clean all ## .DEFAULT_GOAL := all # List of dependencies defined from list of object files DEPS := $(OBJS:.o=.d) all: $(MAIN) -include $(DEPS) $(MAIN): $(OBJS) $(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LFLAGS) $(LIBS) #suffix replacement rule for building .o's from .cc's #build dependency files first, second line actually compiles into .o .cc.o: $(CC) $(CFLAGS) $(INCLUDES) -c -MM -MF $(patsubst %.o,%.d,[email protected]) $< $(CC) $(CFLAGS) $(INCLUDES) -c -o [email protected] $< clean: $(RM) *.o *~ $(MAIN) *.d 

Заметьте, что я использовал .cc .. Вышеупомянутый Makefile легко настраивается для файлов .c.

Также важно отметить важность этих двух линий:

 $(CC) $(CFLAGS) $(INCLUDES) -c -MM -MF $(patsubst %.o,%.d,[email protected]) $< $(CC) $(CFLAGS) $(INCLUDES) -c -o [email protected] $< 

поэтому gcc вызывается один раз, чтобы сначала создать файл зависимостей, а затем фактически компилирует файл .cc. И так далее для каждого исходного файла.

Упрощенное решение: просто используйте Makefile, чтобы правило компиляции .c в .o зависело от файлов заголовков и любого другого значения в вашем проекте как зависимости.

Например, в Makefile где-то:

 DEPENDENCIES=mydefs.h yourdefs.h Makefile GameOfThrones.S07E01.mkv ::: (your other Makefile statements like rules ::: for constructing executables or libraries) # Compile any .c to the corresponding .o file: %.o: %.c $(DEPENDENCIES) $(CC) $(CFLAGS) -c -o [email protected] $< 

Я считаю, что команда mkdep – это то, что вы хотите. Он фактически сканирует файлы .c для строк #include и создает для них дерево зависимостей. Я считаю, что проекты Automake / Autoconf используют это по умолчанию.

  • Создание собственного файла заголовка в C
  • Каковы преимущества относительного пути, например «../include/header.h» для заголовка?
  • c ++ шаблон и файлы заголовков
  • В чем разница между .cpp-файлом и файлом .h?
  • GridView - отображать заголовки на пустом источнике данных
  • Заголовок в исходном файле
  • Заголовок ответа jQuery и AJAX
  • Заглавийте первую букву обоих слов в строке из двух слов
  • C ++ Заголовок заголовка
  • Обнаружение, если файл PDF верен (заголовок PDF)
  • Interesting Posts

    Каков конечный почтовый индекс и регулярное выражение zip?

    SIMD, подписанный с неподписанным умножением для 64-разрядных * 64-бит до 128 бит

    Как получить sms-отправленное подтверждение для каждого контакта / человека в android?

    Стоит ли чистить реестр?

    Почему IEnumerable сделал ковариант в C # 4?

    Как изменить выбранное значение выпадающего списка select2 с помощью JqGrid?

    Будет ли разница в плотности пикселей видна между мониторами 4K и 2K с размером 27 дюймов?

    Запрос LINQ для возврата словаря

    log2 не найден в моей math.h?

    Angular2 – Взаимодействие между компонентами с использованием сервиса

    Перевести индекс столбца в имя столбца Excel

    Как я могу получить доступ к теневой глобальной переменной в C?

    Как установить Google Chrome полностью в автономном режиме и не проверять новую версию?

    Форматирование даты на основе пользовательской локали на Android

    chrome.identity Аутентификация пользователя в расширении Chrome

    Давайте будем гением компьютера.