Makefile circular dependency with Windows resource files

527 views Asked by At

There have been several questions regarding circular dependencies being dropping when running a Makefile (here and here), however, I am still a bit confused as to why they are occurring.

For example, I am trying to compile a Win32 GUI program that contains resource files (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)

The command $(patsubst %.rc,%.rc.o,$(wildcard *.rc)) takes all the resource files ending in .rc and slaps a .o extension onto them (e.g. resource.rc.o).

When I run this, everything seems to work and I get a working executable, however, Make outputs the following:

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

Is this circular dependency occurring because I technically have two .o rules? In other words, how can I correct this circular dependency?


Edit 1:

I tried following what @MadScientist said, however, this still created a circular dependency with Make. After some more Googling, I came across the following page. Towards the very bottom there is a section titled "Circular File Dependencies." This got me thinking about the output from Make:

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

It looks to be that the rc suffix is creating this dependency - even though it is not part of the file extension of the outputted object file (i.e. file.rc.o). If I change the output file suffix to be .res.o, the circular dependency goes away entirely:

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

This sparks a very similar question, if I wanted to use the previous suffix .rc.o, how would you accomplish this? Is it possible?

Edit 2:

@MadScientist'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 @MadScientist's updated answer below.

1

There are 1 answers

1
MadScientist On BEST ANSWER

One way is to not name your windres output files with a .o extension. If you choose a different extension, you won't have this problem.

Another way is to use static pattern rules for the windres targets:

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

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

Since static pattern rules are shorthand for creating explicit rules, and are not implicit rules, they don't participate in searches so make won't come up with a circular dependency.

ETA

OK I created your example locally. Using make -d we can see what happens: make needs to build menu_one.rc.o and it finds our rule with a prerequisite of menu_one.rc. Then it needs to see if it can rebuild manu_one.rc, and it find the generic pattern rule for building executables:

%: %.o ; ...

Matching this pattern with a target of menu_one.rc gives a prerequisite of menu_one.rc.o, and you have a loop.

What you need to do is notify make that the *.rc files are source files and make shouldn't try to build them. You can do this by declaring a terminal rule. There is a comprehensive discussion of the intricacies of dealing with match-anything rules (rules with a target of % alone, which matches any target) in the GNU make manual.

Add this to inform make that your .rc files are terminal (that is, they can't be built from something else):

%.rc: