Recursive Dependencies Between make Targets in Same Makefile

前端 未结 1 1107
清歌不尽
清歌不尽 2021-01-20 15:20

I am attempting to write a makefile that is able to determine when headers were changed and then recompile the corresponding .cpp files. To test this, I created three files:

1条回答
  •  礼貌的吻别
    2021-01-20 15:50

    What am I doing incorrectly

    Your rule:

    a.h: b.h
    

    merely tells make that a.h depends on b.h, i.e. that a.h will need to be (re)made, in whatever manner make can determine from the makefile, if a.h is older than b.h or doesn't exist.

    It doesn't tell make what to do to remake a.h from b.h. Your makefile contains no recipe for remaking a.h from b.h. It only contains a recipe for remaking prog from main.cpp and a.h, namely:

    prog: main.cpp a.h
            g++ main.cpp -o prog
    

    Furthermore make, of course, has no builtin rule with a recipe for making a.h from b.h. So in the absence of any recipe for making a.h from b.h it assumes that this dependency requires nothing to be done. There is no other reasonable default. So even if a.h is older than b.h, nothing is done to a.h; and although prog depends on a.h, nothing need be done to prog on that account.

    This is fortunate, because in fact you don't want a.h to be remade in any manner whatever when b.h changes, and you don't want main.cpp to be remade in any manner whatever when a.h or b.h changes. You want prog to be remade when any of them changes. What you want is expressed by any of the following makefiles:

    1

    prog: main.cpp a.h b.h
        g++ main.cpp -o prog
    

    2

    prog: main.cpp a.h
        g++ main.cpp -o prog
    
    prog: b.h
    

    3

    prog: main.cpp b.h
        g++ main.cpp -o prog
    
    prog: a.h
    

    4

    prog: main.cpp
        g++ main.cpp -o prog
    
    prog: a.h b.h
    

    5

    prog: main.cpp
        g++ main.cpp -o prog
    
    prog: a.h
    prog: b.h
    

    (and some more). They're all equivalent. They all say that prog depends on main.cpp, a.h and b.h and they all say what is to be done whenever prog needs to remade, namely:

        g++ main.cpp -o prog
    

    how can I accomplish what I want without adding the full and complete set of headers to each individual .cpp file like this (since for larger projects this could become extremely cumbersome)

    Indeed it would, and for that reason GCC compilers have for a very long time had a feature for generating mini-makefiles that express the dependency of the object file that is going to be generated upon each of the header files that are read in order to make the object file. GNU make can exploit this feature to generate those dependency files and include them in a makefile for building GCC target(s). This co-operation between GCC and make is called auto-dependency generation (or similar). The question of how to do it in a makefile is a duplicate of this one and if you google, e.g. "gcc auto generate dependencies" you can also find guru treatments.

    In a comment you suggest that you aren't yet sufficiently expert with GNU make to be confident with the auto-dependency generation techniques illustrated in those answers. Well, you can begin to get the hang of it with a rudimentary implementation as simple as this (which also makes the makefile more normal in other respects):

    Makefile

    .PHONY: all clean
    
    all: prog
    
    prog: prog.o
    
    prog.o: main.cpp
        g++ -MMD -c -o prog.o main.cpp
    
    prog: prog.o
        g++ -o prog prog.o 
    
    clean:
        rm -f prog *.o *.d
    
    -include prog.d
    

    -MMD is the GCC preprocessor option that generates the dependency file prog.d. Here is the documentation of -MMD

    prog.d is a mini-makefile:

    $ cat prog.d 
    prog.o: main.cpp a.h b.h
    

    expressing all of the dependencies of prog.o. The first time this runs, the include-ed makefile prog.d will not exist, which would be a fatal make error but for the fact that the - prefix tells make to ignore that error. So make proceeds and everything, including prog.d gets made, and thereafter prog.d will be regenerated whenever any rule - including the rule in prog.d itself - requires prog.o to be recompiled.

    0 讨论(0)
提交回复
热议问题