I have a simple makefile to compile some C code that uses OpenGL libraries, however, it appears to be interpreting one of it's own rules as a file to compile. The simplified version is as follows:
CC = gcc
COMPILEFLAGS = -Wall -lglut -lGL -lGLU -lm -c
LINKFLAGS = -lglut -lGL -lGLU -lm
castle: castle_link
run_castle:
./castle $(ARGS)
castle_link: castle_compile
${CC} -o castle castle.o ${LINKFLAGS}
castle_compile:
${CC} ${COMPILEFLAGS} castle.c
clean:
rm *.o castle
Executing make -n castle
yields the following:
gcc -Wall -lglut -lGL -lGLU -lm -c castle.c
gcc -o castle castle.o -lglut -lGL -lGLU -lm
gcc castle.o castle_link -o castle
And I cant understand why this happens. On this very same file there is another set of rules that follow precisely the same pattern, only changing file names, that work flawlessly.
(This only happens when executing the rule make castle
, manually executing castle_compile
and then castle_link
does not cause that).
Any help is very much appreciated.
CodePudding user response:
To explain what happened, you have a rule without a recipe:
castle: castle_link
which means that make
will try to find an implicit rule for it. From the manual:
If none of the explicit rules for a target has a recipe, then make searches for an applicable implicit rule to find one
And earlier in that page it says that prerequisites for targets are combined:
One file can be the target of several rules. All the prerequisites mentioned in all the rules are merged into one list of prerequisites for the target.
The implicit rule that matches will be either:
%: %.o
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
if the .o
file exists or:
%: %.c
$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@
if it doesn't. (make -p
will print definitions of the implicit rules).
So the prerequisites for target castle
will be:
- either castle.o castle_link
- or castle.c castle_link
And the $^
variable in the recipe from the implicit rule will put them in the cc
command to execute. Let's see with this simplified makefile:
castle: castle_link
castle_link: castle_compile
$(CC) -o castle castle.o -lm
castle_compile:
$(CC) -Wall -c castle.c
If we execute it on a clean directory (i.e. with no castle.o
):
]$ make --debug=m castle
...
Must remake target 'castle_compile'.
cc -Wall -c castle.c # This is our recipe, notice -Wall
Successfully remade target file 'castle_compile'.
Must remake target 'castle_link'.
cc -o castle castle.o -lm # This is our reicpe, notice -lm
Successfully remade target file 'castle_link'.
Must remake target 'castle'.
cc castle.c castle_link -o castle # This is implicit rule with castle.c
cc: error: castle_link: No such file or directory
Now that castle.o
was created, we execute it again:
]$ make --debug=m castle
...
Must remake target 'castle_compile'.
cc -Wall -c castle.c # This is our recipe, notice -Wall
Successfully remade target file 'castle_compile'.
Must remake target 'castle_link'.
cc -o castle castle.o -lm # This is our recipe, notice -lm
Successfully remade target file 'castle_link'.
Prerequisite 'castle_link' of target 'castle' does not exist.
Must remake target 'castle'.
cc castle.o castle_link -o castle # This is implicit rule with castle.o
cc: error: castle_link: No such file or directory
As you can see, in the first invocation it was "cc castle.c castle_link -o castle" and in the second it was "cc castle.o castle_link -o castle".
Don't ask me why only the second invocation printed "Prerequisite 'castle_link' of target 'castle' does not exist." :-)