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

gcc makefile dependencies header

79865 просмотра

9 ответа

У меня есть следующий make-файл, который я использую для сборки программы (собственно ядра), над которой я работаю. Это с нуля, и я изучаю процесс, поэтому он не идеален, но я думаю, что он достаточно мощный на данный момент для моего уровня написания 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 $@ $^

$(SOBJS) : $(SFILES)
    $(AS) $(ASFLAGS) $< -o $@

%.o: %.c
    @echo Compiling $<...
    $(CC) $(CFLAGS) -c -o $@ $<

#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, содержащие заголовочный файл, которые я изменяю, были перестроены, и чтобы весь проект снова был связан. Я могу сделать связывание, заставив все заголовочные файлы быть зависимостями от цели, но я не могу понять, как сделать файлы C недействительными, когда их включенные заголовочные файлы являются более новыми.

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

РЕДАКТИРОВАТЬ: Я должен уточнить, я знаком с концепцией размещения отдельных целей и с каждой целью. Требуются файлы заголовков. Это требует от меня редактирования make-файла каждый раз, когда я куда-нибудь включаю заголовочный файл, что немного болезненно. Я ищу решение, которое может получить зависимости файла заголовка самостоятельно, что, я уверен, я видел в других проектах.

Автор: Nicholas Flynt Источник Размещён: 28.08.2019 09:13

Ответы (9)


29 плюса

Решение

Как уже указывалось в других разделах этого сайта, см. Эту страницу: Генерация автозависимостей

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

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

Автор: Udi Meiri Размещён: 09.03.2009 01:47

20 плюса

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

DEPS := $(COBJS:.o=.d)

-include $(DEPS)

%.o: %.c
    $(CC) -c $(CFLAGS) -MM -MF $(patsubst %.o,%.d,$@) -o $@ $<

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

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

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

Автор: Martin Fido Размещён: 23.03.2010 04:20

17 плюса

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


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

depend: .depend

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

include .depend

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

Автор: dmckee Размещён: 07.03.2010 12:42

7 плюса

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

%.o: %.c
        @echo Compiling $<...
        $(CC) $(CFLAGS) -c -o $@ $<

foo.c: bar.h
# And so on...
Автор: mipadi Размещён: 18.11.2008 12:59

4 плюса

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

$(OBJDIR)/%.d: %.c
        $(CC) -MM -MG $(CPPFLAGS) $< | sed -e 's,^\([^:]*\)\.o[ ]*:,$(@D)/\1.o $(@D)/\1.d:,' >$@

ifneq ($(MAKECMDGOALS),clean)
include $(SRCS:%.c=$(OBJDIR)/%.d)
endif

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

Автор: Chris Dodd Размещён: 18.11.2008 01:08

3 плюса

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

Автор: Jonathan Leffler Размещён: 18.11.2008 01:06

0 плюса

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

$ gcc - версия 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,$@) $<
    $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<

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

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

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

$(CC) $(CFLAGS) $(INCLUDES) -c -MM -MF $(patsubst %.o,%.d,$@) $<
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<

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

Автор: Tagar Размещён: 01.07.2016 09:29

0 плюса

Более простое решение: просто используйте Makefile, чтобы правило компиляции .c to .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 $@ $<
Автор: Richard Elkins Размещён: 02.09.2016 03:59

-1 плюса

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

Автор: jdizzle Размещён: 07.03.2010 12:45
Вопросы из категории :
32x32