Использование Stati c Pattern Rule приводит к тому, что изменение одного источника перестраивает все - PullRequest
0 голосов
/ 14 января 2020

Я пытаюсь исправить Makefile, который в настоящее время не обнаруживает изменения исходного файла из-за отсутствия зависимости от исходных файлов. c. Я реализовал шаблонное правило stati c, но оно не может перестроить один объектный файл при изменении одного исходного файла. Он перестроит все изменения.

У меня есть следующее:

ARCHITECTURE_DIR = arm
BUILD_DIR = build
OUTPUT_DIR = $(BUILD_DIR)/$(ARCHITECTURE_DIR)
SDK_DIR     = sdks/v4.0

SOURCE_FILES = \
  $(SDK_DIR)/alarm.c \
  ...

CSOURCES = $(filter %.c, $(SOURCE_FILES))

COBJS = $(addprefix $(OUTPUT_DIR)/,$(CSOURCES:.c=.o))
all: PROLOGUE $(COBJS)
  $(LD) $(COBJS) -o ...

Ранее файл имел следующее:

$(COBJS): %.o:
  @echo 'Building $(notdir $(@:%.o=%.c))...'
  @$(CC) $(CFLAGS) -o $@ $(filter %$(@:$(OUTPUT_DIR)/%.o=%.c),$(CSOURCES)) > /dev/null \

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

COBJS = $(CSOURCES:.c=.o)

$(COBJS): %.o: %.c
    @echo 'Building $(notdir $(@:%.o=%.c))...'
    @$(CC) $(CFLAGS) -o $(addprefix $(OUTPUT_DIR)/,$@) $< > /dev/null \

Но это заставляет его перестраиваться каждый раз, когда объектные файлы помещаются в другой каталог. Есть ли способ сделать так, чтобы он мог найти эти объектные файлы и не восстанавливать их при необходимости?

Спасибо за вашу помощь!

1 Ответ

1 голос
/ 17 января 2020

Не уверен, что я полностью понимаю, где вы хотите хранить различные продукты, но давайте попробуем. Из того, что вы показываете в своем Makefile, я буду считать, что вы хотите, чтобы объектный файл, соответствующий sdks/v4.0/alarm.c, был build/arm/sdks/v4.0/alarm.o. Я также предполагаю, что ваш целевой исполняемый файл build/arm/sdks/v4.0/my_executable.

  1. Вы можете переработать правило шаблона компиляции, чтобы использовать реальные исходные и целевые файлы:

    $(OUTPUT_DIR)/%.o: %.c
        @echo 'Building $(@F)...'
        @mkdir -p $(@D)
        @$(CC) $(CFLAGS) -o $@ $<
    

    Обратите внимание, что рецепт создает каталог назначения перед компиляцией (mkdir -p ...) и использует автоматические переменные c ($(@F), $(@D)) для получения базового имени и каталога цели.

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

    EXEC := $(OUTPUT_DIR)/$(SDK_DIR)/my_executable
    ...
    .PHONY: all
    all: $(EXEC)
    ...    
    $(EXEC): PROLOGUE $(COBJS)
        $(LD) $(COBJS) -o $@
    

В общем, вы можете попробовать что-то вроде:

ARCHITECTURE_DIR := arm
BUILD_DIR        := build
OUTPUT_DIR       := $(BUILD_DIR)/$(ARCHITECTURE_DIR)
SDK_DIR          := sdks/v4.0
SOURCE_FILES     := \
    $(SDK_DIR)/alarm.c \
    ...
CSOURCES         := $(filter %.c,$(SOURCE_FILES))
COBJS            := $(patsubst %.c,$(OUTPUT_DIR)/%.o,$(CSOURCES))
EXEC             := $(OUTPUT_DIR)/$(SDK_DIR)/my_executable

.PHONY: all
all: $(EXEC)

$(EXEC): PROLOGUE $(COBJS)
    $(LD) $(COBJS) -o $@

$(OUTPUT_DIR)/%.o: %.c
    @echo 'Building $(@F)...'
    @mkdir -p $(@D)
    @$(CC) $(CFLAGS) -c -o $@ $<
...