Makefile 循环依赖 Windows 个资源文件

Makefile circular dependency with Windows resource files

关于 循环依赖性 在 运行 生成 Makefile (here and here) 时被删除的几个问题,但是,我仍然有点困惑至于它们为什么会发生。

例如,我正在尝试编译包含资源文件的 Win32 GUI 程序 (from this tutorial). These resource files are compiled to object files through the windres command, so they can be linked to the final executable (as described here):

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)。

当我运行这个时,一切似乎都正常,我得到了一个工作的可执行文件,但是,输出如下:

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:

我尝试遵循 said, however, this still created a circular dependency with Make. After some more Googling, I came across the following page。在最底部有一个标题为“Circular File Dependencies”的部分。这让我想到了 Make:

的输出
make: Circular menu_one.rc <- menu_one.rc.o dependency dropped.

看起来 rc 后缀正在创建这种依赖性 - 尽管它不是输出的 object 文件(即 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:

's suggestion of using a match-anything rule worked perfectly with correcting the problem. This now allows me to use the .rc.o suffix ending. See 在下面更新了答案。

一种方法是不使用 .o 扩展名命名您的 windres 输出文件。如果您选择不同的扩展程序,您将不会遇到此问题。

另一种方法是对 windres 目标使用 static pattern rules

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

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

由于静态模式规则 shorthand 用于创建显式规则,而不是隐式规则,因此它们不参与搜索,因此 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 不应尝试构建它们。您可以通过声明 终端规则 来完成此操作。在 GNU make 手册中全面讨论了处理 match-anything rules(目标为 % 的规则,它匹配任何目标)的复杂性。

添加这个来通知 make 你的 .rc 文件是终端文件(也就是说,它们不能从其他东西构建):

%.rc: