#gcc #makefile #gnu-make
#gcc #makefile #gnu-make
Вопрос:
Я прочесывал веб-страницы и не могу найти правильный способ заставить это работать. Просто пытаюсь создать простой Makefile, который использует мой исходный код и создает только измененные файлы. Мне нужно, чтобы все файлы .o были помещены в одну выходную папку. В настоящее время у меня все работает, за исключением того, что если я изменяю один файл, все это перестраивается заново. Например, если я изменю main.c, он также скомпилирует EOL.c. Однако, если ничего не меняется, это говорит о том, что ничего не нужно делать.
NAME=Program
CC=arm-none-eabi-gcc
CFLAGS=-c -Wall -O0 -std=c99
-nostartfiles --specs=nano.specs
-mthumb -fmessage-length=0
-fsigned-char -ffunction-sections
-fdata-sections -mcpu=cortex-m0
BID?=_DEV
DEFINES= -DPROD -DBLD_ID="$(BID)"
LDFLAGS= -nostartfiles
INCLUDES= -ISrc/App/Include -ISrc/Device/CMSIS/Include
SOURCES= Src/main.c Src/App/Source/Application.c Src/App/Source/EOL.c Src/Svc/Source/TimerManager.c
OBJECTS=$(OBJECTS1:.c=.o)
OBJECTS1=$(SOURCES:.S=.o)
OFILES1=$(notdir ${OBJECTS})
OFILES=$(addprefix $(OBJDIR)/,$(OFILES1))
OBJDIR=Output
.PHONY: all rebuild clean
all: $(OBJDIR) $(SOURCES) $(OBJDIR)/$(NAME).hex
%.hex: %.elf
arm-none-eabi-objcopy -O ihex $< $@
%elf: $(OBJECTS)
$(CC) $(LDFLAGS) $(OFILES) -o $@
rebuild: clean all
.SECONDARY:
.c.o:
$(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) $< -o $(OBJDIR)/$(notdir $@)
.S.o:
$(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) $< -o $(OBJDIR)/$(notdir $@)
$(OBJDIR):
mkdir $(OBJDIR)
clean:
rm -f $(OBJDIR)/*.o $(OBJDIR)/*.elf $(OBJDIR)/*.hex $(OBJDIR)/*.bin
Комментарии:
1. Я не вижу связи тега «cmake» с проблемой. CMake — это не Make.
Ответ №1:
С этим makefile существует несколько проблем. По сути, у вас есть правила, целями которых не являются файлы, которые они фактически создают, и правило, предварительными условиями которого не являются файлы, которые ему действительно нужны.
Предположим, вы внесли изменения Src/main.c
и пытаетесь перестроить Output/Program.elf
, используя это правило:
%elf: $(OBJECTS)
$(CC) $(LDFLAGS) $(OFILES) -o $@
Предварительные условия ( $(OBJECTS)
) на самом деле Src/main.o Src/App/Source/EOL.o
и так далее. Эти файлы не существуют — они никогда не существовали — но для них есть правило:
.c.o:
$(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) $< -o $(OBJDIR)/$(notdir $@)
Make видит, что это Src/main.o
зависит от Src/main.c
, и поэтому должен быть перестроен, как и должно Output/Program.elf
. Таким образом, он вызывает это правило, которое фактически выполняет сборку Output/main.o
. Но правило elf требует всех (воображаемых) объектных файлов, поэтому все исходные файлы должны быть перекомпилированы — в объектные файлы, которые уже существуют и не устарели, но на которые Make не обратил внимания.
Первое, что нужно сделать, это исправить правила для объектов, но есть проблема: хотя правила имеют недостатки, они имеют то преимущество, что помогают Make находить соответствующие исходные файлы (прежде чем использовать их неправильно), вот так:
Src/App/Source/EOL.o: Src/App/Source/EOL.c
...
Как мы можем сообщить Make, где найти исходный файл, соответствующий Output/EOL.o
? Существует несколько способов, но хороший способ — использовать vpath:
vpath %.c Src/App/Source
Output/EOL.o: EOL.c
...
Все, что нам нужно сделать, это создать список исходных каталогов, передать его в vpath и изменить правило шаблона:
SRCDIRS := $(dir $(SOURCES))
vpath %.c $(SRCDIRS)
$(OBJDIR)/%.o: %.c
$(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) $< -o $@
( .S.o
Правило может быть исправлено таким же образом.)
Затем измените elf
правило, чтобы назвать — и использовать — его реальные предварительные условия:
%elf: $(OFILES)
$(CC) $(LDFLAGS) $^ -o $@