Andreas
Andreas

Reputation: 5301

GNU Make rule hello.c and %.c does strange things

I have a program hello.c and a makefile to build it using implicit rules:

hello:

The build works as expected:

cc -c -o hello.o hello.c
cc hello.o -o hello

Then I put a recipe on hello.c and things go wild. The new makefile:

hello:
hello.c:
    : secret recipe

The build output:

: secret recipe
cc hello.c -o hello

Which brings me to question 1: why do the implicit rules no longer create the object file?

And then it gets weirder when I use pattern %.c for hello.c. Makefile:

hello:
%.c:
    : secret recipe

Output:

cc hello.c -o hello

No object file, but also the recipe for hello.c is not run. How?

And now for the really super strange stuff. Running make -B on the makefile with %.c rule gives this output:

: secret recipe
cc -c -o makefile.o makefile.c
cc: error: makefile.c: No such file or directory

Where does makefile.c come from? And how can this be any different from manual touch-remove to force recipes?

(Collated these questions as they are all related to rules on *.c-files, and presumably related somehow)

Upvotes: 1

Views: 198

Answers (1)

Jens
Jens

Reputation: 72697

Where does makefile.c come from?

From a combination of a) the default suffix list, b) the %.c pattern rule, and c) the fact that GNU make also considers its makefile for updating (that's an esoteric feature needed for reexecution of a makefile reading e.g. generated included targets.)

You can enable the debug option (make -B -d) to see this:

GNU Make 3.82
Built for x86_64-redhat-linux-gnu
Copyright (C) 2010  Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Reading makefiles...
Reading makefile `makefile'...
Updating makefiles....
 Considering target file `makefile'.
  Looking for an implicit rule for `makefile'.
  Trying pattern rule with stem `makefile'.
  Trying implicit prerequisite `makefile.o'.
  Trying pattern rule with stem `makefile'.
  Trying implicit prerequisite `makefile.c'.
  Trying pattern rule with stem `makefile'.
  Trying implicit prerequisite `makefile.cc'.
  Trying pattern rule with stem `makefile'.
  [...]
  Trying implicit prerequisite `makefile.sh'.
  Trying pattern rule with stem `makefile'.
  Trying implicit prerequisite `makefile,v'.
  Trying pattern rule with stem `makefile'.
  Trying implicit prerequisite `RCS/makefile,v'.
  Trying pattern rule with stem `makefile'.
  Trying implicit prerequisite `RCS/makefile'.
  Trying pattern rule with stem `makefile'.
  Trying implicit prerequisite `s.makefile'.
  Trying pattern rule with stem `makefile'.
  Trying implicit prerequisite `SCCS/s.makefile'.
  Trying pattern rule with stem `makefile'.
  Trying implicit prerequisite `makefile.o'.
  Looking for a rule with intermediate file `makefile.o'.
   Avoiding implicit rule recursion.
   Trying pattern rule with stem `makefile'.
   Trying implicit prerequisite `makefile.c'.
   Trying pattern rule with stem `makefile'.
   Trying implicit prerequisite `makefile.cc'.
   Trying pattern rule with stem `makefile'.
   Trying implicit prerequisite `makefile.C'.
   Trying pattern rule with stem `makefile'.
   Trying implicit prerequisite `makefile.cpp'.
   Trying pattern rule with stem `makefile'.
   [...]
   Trying implicit prerequisite `RCS/makefile.o'.
   Trying pattern rule with stem `makefile.o'.
   Trying implicit prerequisite `s.makefile.o'.
   Trying pattern rule with stem `makefile.o'.
   Trying implicit prerequisite `SCCS/s.makefile.o'.
   Trying pattern rule with stem `makefile'.
   Trying implicit prerequisite `makefile.c'.
   Looking for a rule with intermediate file `makefile.c'.
    Avoiding implicit rule recursion.
    Avoiding implicit rule recursion.
    Trying pattern rule with stem `makefile'.
  Found an implicit rule for `makefile'.
  Considering target file `makefile.o'.
   File `makefile.o' does not exist.
   Considering target file `makefile.c'.
    File `makefile.c' does not exist.
    Finished prerequisites of target file `makefile.c'.
   Must remake target `makefile.c'.
Invoking recipe from makefile:3 to update target `makefile.c'.
: secret recipe
Putting child 0xbe74b0 (makefile.c) PID 13836 on the chain.
Live child 0xbe74b0 (makefile.c) PID 13836
Reaping winning child 0xbe74b0 PID 13836
Removing child 0xbe74b0 PID 13836 from chain.
   Successfully remade target file `makefile.c'.
   Finished prerequisites of target file `makefile.o'.
  Must remake target `makefile.o'.
Invoking builtin recipe to update target `makefile.o'.
cc    -c -o makefile.o makefile.c
Putting child 0xbdb910 (makefile.o) PID 13837 on the chain.
Live child 0xbdb910 (makefile.o) PID 13837
cc: error: makefile.c: No such file or directory
cc: fatal error: no input files
compilation terminated.
Reaping losing child 0xbdb910 PID 13837
gmake: *** [makefile.o] Error 4
Removing child 0xbdb910 PID 13837 from chain.

You can delete the suffix list by placing .SUFFIXES: as the first line in your makefile, then you get:

GNU Make 3.82
Built for x86_64-redhat-linux-gnu
Copyright (C) 2010  Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Reading makefiles...
Reading makefile `makefile'...
Updating makefiles....
 Considering target file `makefile'.
  Looking for an implicit rule for `makefile'.
  Trying pattern rule with stem `makefile'.
  Trying implicit prerequisite `makefile,v'.
  Trying pattern rule with stem `makefile'.
  Trying implicit prerequisite `RCS/makefile,v'.
  Trying pattern rule with stem `makefile'.
  Trying implicit prerequisite `RCS/makefile'.
  Trying pattern rule with stem `makefile'.
  Trying implicit prerequisite `s.makefile'.
  Trying pattern rule with stem `makefile'.
  Trying implicit prerequisite `SCCS/s.makefile'.
  No implicit rule found for `makefile'.
  Finished prerequisites of target file `makefile'.
 No need to remake target `makefile'.
Updating goal targets....
Considering target file `hello'.
 Looking for an implicit rule for `hello'.
 Trying pattern rule with stem `hello'.
 Trying implicit prerequisite `hello,v'.
 Trying pattern rule with stem `hello'.
 Trying implicit prerequisite `RCS/hello,v'.
 Trying pattern rule with stem `hello'.
 Trying implicit prerequisite `RCS/hello'.
 Trying pattern rule with stem `hello'.
 Trying implicit prerequisite `s.hello'.
 Trying pattern rule with stem `hello'.
 Trying implicit prerequisite `SCCS/s.hello'.
 No implicit rule found for `hello'.
 Finished prerequisites of target file `hello'.
No need to remake target `hello'.
gmake: Nothing to be done for `hello'.

You can even avoid these "match anything rules" with make -B -d --no-builtin-rules:

Reading makefiles...
Reading makefile `makefile'...
Updating makefiles....
 Considering target file `makefile'.
  Looking for an implicit rule for `makefile'.
  No implicit rule found for `makefile'.
  Finished prerequisites of target file `makefile'.
 No need to remake target `makefile'.
Updating goal targets....
Considering target file `hello'.
 Looking for an implicit rule for `hello'.
 No implicit rule found for `hello'.
 Finished prerequisites of target file `hello'.
No need to remake target `hello'.
gmake: Nothing to be done for `hello'.

Upvotes: 1

Related Questions