0

在运行 Makefile 时,有几个关于循环依赖关系下降的问题(这里这里),但是,我仍然对它们发生的原因感到有些困惑。

例如,我正在尝试编译一个包含资源文件的 Win32 GUI 程序(来自本教程)。这些资源文件通过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建议使用match-anything 规则完美地解决了这个问题。这现在允许我使用.rc.o后缀结尾。请参阅下面@MadScientist的更新答案。

4

1 回答 1

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 不应该尝试构建它们。您可以通过声明终端规则来做到这一点。GNU make 手册中全面讨论了处理match-anything 规则(目标为单独的规则,它匹配任何目标)的复杂性。%

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

%.rc:
于 2019-03-24T20:27:50.137 回答