У меня есть следующий файл makefile, который я использую для сборки программы (фактически ядра), над которой я работаю. Это с нуля, и я изучаю этот процесс, поэтому он не идеален, но я думаю, что на данный момент он достаточно мощный для моего уровня опыта написания 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-файл каждый раз, когда я куда-то включаю файл заголовка, что немного неудобно. Я ищу решение, которое может самостоятельно определять зависимости файла заголовка, и я уверен, что видел это в других проектах.
источник
Вы можете добавить команду 'make зависимой', как заявляли другие, но почему бы не заставить gcc создавать зависимости и компилировать одновременно:
Параметр -MF указывает файл, в котором будут храниться зависимости.
Тире в начале '-include' говорит Make продолжить, когда файл .d не существует (например, при первой компиляции).
Обратите внимание, что в gcc есть ошибка, связанная с параметром -o. Если вы установите имя файла объекта, чтобы сказать,
obj/_file__c.o
то сгенерированный файл_file_.d
все равно будет содержать_file_.o
, а неobj/_file_c.o
.источник
g++ -c -Wall -Werror -MM -MF main.d -o main.o main.cpp
Я получил файл main.d, но main.o был равен 0 байтам. Однако флаг -MMD, похоже, делает именно то, что требовалось. Итак, моим рабочим правилом makefile стало:$(CC) -c $(CFLAGS) -MMD -o $@ $<
Это эквивалентно ответу Криса Додда , но использует другое соглашение об именах (и по совпадению не требует
sed
магии. Скопировано из более позднего дубликата .Если вы используете компилятор GNU, он может составить для вас список зависимостей. Фрагмент Makefile:
Есть еще инструмент
makedepend
, но он мне никогда не нравился так сильно, какgcc -MM
источник
SRCS
иOBJS
. Я бы согласен в большинстве случаев, но каждый должен знать, что это такое.Вам нужно будет создать индивидуальные цели для каждого файла C, а затем указать файл заголовка как зависимость. Вы по-прежнему можете использовать свои общие цели, а
.h
потом просто разместить зависимости, например:источник
По сути, вам нужно динамически создавать правила 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-файле.
источник
Помимо того, что сказал @mipadi, вы также можете изучить использование
-M
опции ' ' для создания записи о зависимостях. Вы даже можете сгенерировать их в отдельный файл (возможно, «depends.mk»), который затем включите в make-файл. Или вы можете найтиmake depend
правило, которое редактирует make-файл с правильными зависимостями (термины Google: «не удалять эту строку» и зависеть).источник
Ни один из ответов не помог мне. Например, ответ Мартина Фидо предполагает, что gcc может создавать файл зависимостей, но когда я попытался, он генерировал для меня пустые (нулевые байты) объектные файлы без каких-либо предупреждений или ошибок. Это может быть ошибка gcc. Я на
Итак, вот мой полный 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.
Также обратите внимание на важность этих двух строк:
поэтому 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 $@ $<
источник
Я считаю, что
mkdep
команда - это то, что вы хотите. Фактически он сканирует файлы .c на наличие#include
строк и создает для них дерево зависимостей. Я считаю, что проекты Automake / Autoconf используют это по умолчанию.источник