How to automatically create a dependency between files?

%.d: %.c
        @set -e; rm -f $@; \
        $(CC) -MM  $< > $@.$$$$; \
        sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
        rm -f $@.$$$$

sinclude $(SOURCES:.c=.d)

      

above, I saw someone's blog post, but it doesn't explain how the code for creating a dependency between .c and .h files in a makefile works.

Is there anyone who can explain this to me or provide some material?

I would really appreciate your help! Thank you!

+3


source to share


4 answers


Suppose your only new source file foo.c

that contains the lines

#include "foo.h"
#include "bar.h"

      

Make detects that it is foo.d

deprecated (because it doesn't exist or foo.c is newer), so it executes the rule.

%.d: %.c
        @set -e; rm -f $@; \
        $(CC) -MM  $< > $@.$$$$; \
        sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
        rm -f $@.$$$$

sinclude $(SOURCES:.c=.d)

      

Make an estimate $$$$

as $$

well as transfer it to the shell; the shell interprets this as the value of a parameter $

, which is the process ID of the shell that the rule wants to use to construct a unique filename. This will only remain constant within one command, so the rule is written with line continuation ("\"). This is not a good way to do it; if there are different processes trying to spawn foo.d

at the same time, you will probably be closed anyway. Therefore, we can rewrite the rule:

%.d: %.c
        @set -e; rm -f $@
        $(CC) -MM  $< > $@.temp
        sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.temp > $@
        rm -f $@.temp

sinclude $(SOURCES:.c=.d)

      

We can abandon the first rule, it doesn't really matter.

The second command $(CC) -MM $< > $@.temp

expands to gcc -MM foo.c > foo.d.temp

(or another compiler). The flag -MM

tells the compiler to create a list of dependencies:



foo.o: foo.c foo.h bar.h

      

The next line is chewing this list with sed

sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g'

      

Which translates roughly as "change foo.o:

to foo.o foo.d :

":

foo.o foo.d : foo.c foo.h bar.h

      

(And the last command deletes the temporary file.)

This is not the best way to handle dependencies, as it will rebuild all files %.d

every time you run Make, even those that have no purpose for you. A more polished approach is Advanced Auto-Dependency Creation .

0


source


From the gcc manual :

-M
Instead of outputting the result of preprocessing, output a rule suitable for make describing the dependencies of the main source file. ...

-MM
Like -M but do not mention header files that are found in system header directories, ...

      

So the command is here:



$(CC) -MM  $< > $@.$$$$; \
        sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \

      

Creates a temporary ($ @. $$$$, i.e. target filename appended with a unique number) output file gcc -MM

and using sed files to be included in the makefile, the dependency file will look like target file: [gcc generated dependencies]

. Then it removes the original output gcc -MM

.

+3


source


The actual tracking #include

is done by the preprocessor (see and options ). -M

-MM

-M

Instead of outputting the result of preprocessing, output a rule suitable for make

describing the dependencies of the main source file. The preprocessor outputs a single rule make

containing the name of the object file for that source file, a colon, and the names of all included files, including those included in the command line parameters -include

or -imacros

.

-MM

Likewise -M

, but do not mention header files that are found in system header directories, or header files that are directly or indirectly included from such a header.

Also a good overview of possible ways to track these types of dependencies is available here .

0


source


For all gobbledegooks with four dollar signs per line, etc. the idea is pretty simple:

  • To create a file xyz.d

    from a file xyz.c

    , run the commands displayed ...
  • The line $(CC)

    should probably include $ (CFLAGS), but assumes the compiler is GCC (the option is -MM

    not standard elsewhere). The flag -MM

    asks the compiler to generate output that lists the headers (or other files) included in the source so that you get the correct dependency information for the current platform.
  • The compiler compiles the source and writes the dependencies to standard output, which is redirected to a temporary file. The extension $@.$$$$

    in the makefile (for example), xyz.$$

    in the shell, which $$

    becomes the PID of the shell that the script is running on.
  • The command sed

    outputs the output from the compiler such that the line starting with xyz.o

    starts with (so the object file and the program created from the object file depend on the files after the colon) , so both the object file and the dependency file need to be updated if any from source or header files will change. xyz.o xyz

    xyz.o xyz.d

  • The output is written to xyz.d

    .
  • Cleaning up and down.
  • The line sinclude

    reads as many files as possible .d

    .

[Edited to correct the inconsistency indicated by Beta .]

0


source







All Articles