Циклическая зависимость Makefile с файлами ресурсов Windows

Было несколько вопросов об удалении круговых зависимостей при запуске Makefile (здесь и здесь), однако я все еще немного не понимаю, почему они происходят.

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

CC = gcc
CFLAGS = -mwindows
DEPS = resource.h
OBJ = menu_one.o $(patsubst %.rc,%.rc.o,$(wildcard *.rc))

all: menu_one

%.rc.o: %.rc
    windres $^ -o $@

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

menu_one: $(OBJ)
    $(CC) $^ -o $@ $(CFLAGS)

Команда $(patsubst %.rc,%.rc.o,$(wildcard *.rc)) берет все файлы ресурсов, оканчивающиеся на .rc, и добавляет к ним расширение .o (например, resource.rc.o).

Когда я запускаю это, кажется, что все работает, и я получаю работающий исполняемый файл, однако Make выводит следующее:

gcc -c menu_one.c -o menu_one.o -mwindows
make: Circular menu_one.rc <- menu_one.rc.o dependency dropped.
windres menu_one.rc -o menu_one.rc.o
gcc menu_one.o menu_one.rc.o -o menu_one -mwindows

Возникает ли эта циклическая зависимость из-за того, что технически у меня есть два правила .o? Другими словами, как исправить эту циклическую зависимость?


Редактировать 1:

Однако я попытался следовать тому, что сказал @MadScientist: это по-прежнему создавало циклическую зависимость с Make. Еще немного погуглив, я наткнулся на следующую страницу . В самом низу находится раздел "Зависимости циклических файлов". Это заставило меня задуматься о выводе Make:

make: Circular menu_one.rc <- menu_one.rc.o dependency dropped.

Похоже, что суффикс rc создает эту зависимость, даже если он не является частью расширения файла выходного объектного файла (т.е. file.rc.o). Если я изменю суффикс выходного файла на .res.o, циклическая зависимость полностью исчезнет:

...
RESOBJ = $(patsubst %.rc,%.res.o,$(wildcard *.rc))
OBJ = menu_one.o $(RESOBJ)
...
%.res.o: %.rc
    windres $^ -o $@
...

Возникает очень похожий вопрос: если бы я хотел использовать предыдущий суффикс .rc.o, как бы вы это сделали? Возможно ли это?

Редактировать 2:

@MadScientist предлагает использовать правило соответствия чему угодно отлично помогло решить проблему. Теперь это позволяет мне использовать окончание суффикса .rc.o. См. @MadScientist обновленный ответ ниже.


person Code Doggo    schedule 24.03.2019    source источник
comment
Ниже в моем обновленном ответе я рассказал, почему вы получаете эту циклическую ссылку (что делает make) и как ее решить. Ваше здоровье!   -  person MadScientist    schedule 25.03.2019


Ответы (1)


Один из способов — не называть выходные файлы windres расширением .o. Если вы выберете другое расширение, у вас не будет этой проблемы.

Другой способ — использовать правила статического шаблона для windres цели:

RCOBJ := $(patsubst %.rc,%.rc.o,$(wildcard *.rc))
OBJ = menu_one.o $(RCOBJ)

  ...
$(RCOBJ) : %.rc.o : %.rc
        windres $^ -o $@

Поскольку правила статического шаблона являются сокращением для создания явных правил, а не неявными правилами, они не участвуют в поиске, поэтому make не будет создавать циклическую зависимость.

Расчетное время прибытия

ОК, я создал ваш пример локально. Используя make -d, мы можем увидеть, что происходит: make нужно собрать menu_one.rc.o, и он находит наше правило с пререквизитом menu_one.rc. Затем ему нужно посмотреть, сможет ли он пересобрать manu_one.rc, и найти общее правило шаблона для сборки исполняемых файлов:

%: %.o ; ...

Сопоставление этого шаблона с целью menu_one.rc дает предпосылку menu_one.rc.o, и вы получаете петлю.

Что вам нужно сделать, так это уведомить make о том, что файлы *.rc являются исходными файлами, и make не должен пытаться их собрать. Вы можете сделать это, объявив правило терминала. Здесь подробно обсуждаются тонкости работы с match-anything. rules (правила только с целью %, которая соответствует любой цели) в руководстве GNU make.

Добавьте это, чтобы сообщить make, что ваши файлы .rc являются терминальными (то есть их нельзя собрать из чего-то другого):

%.rc:
person MadScientist    schedule 24.03.2019
comment
Я добавил новую переменную RCOBJ и добавил правило статического шаблона для списка файлов $(RCOBJ), однако я все еще получаю ошибку циклической зависимости. Я удалил правило %.rc.o: %.rc, но оставил правила %.o: %.c $(DEPS) и menu_one: $(OBJ) как есть. Я что-то пропустил? - person Code Doggo; 25.03.2019