Search code examples
makefilegnu

Why don’t make check the timestamp when the dependency file is not generated?


I create an ugly Makefile, it worked beyond my expectations. When main.o is not built successfully, the executable is built every time I make. In my opinion, after the main.o target command is executed, make will compare the timestamp of the main.o file with the main file. There is no main.o file at this time, so the main file should be the latest. Why is the command of the main target executed. In my case main is always present after the first build and it is rebuilt each time make is executed, Although the content is the same

When I add a main.o file that is older than main by shell, I change the main.c file and use the make command to update only main1.o, but not main, indicating that make compares main and main.o timestamp.

Is there a problem with my understanding? Is it my misunderstanding of the execution process of make.

main: main.o
    gcc -o main main1.o
    echo generate

main.o: main.c
    gcc -c main.c -o main1.o

Solution

  • It works like this:

    main: main.o
            <create some-other-file>
    
    main.o: main.c
            <create yet-another-file>
    

    Make wants to build main. It sees that before it can build main, it needs to build main.o. It looks at your directory and sees there is no file main.o, so it runs your recipe. Your recipe builds yet-another-file, but make doesn't check for that: make believes that whatever your recipe did, it will satisfy the target you told make that it would satisfy. In other words, it trusts that the makefile author wrote a recipe that did what they intended to do, whatever that was.

    Then make runs the recipe for main, which builds some-other-file. If that recipe needed main.o, then it would fail (presumably). It didn't fail, so make says all good.

    Then you run make again, and it sees that main.o doesn't exist, so it builds it, then it builds main, etc. as many times as you run make.

    If your question is, shouldn't make fail when it sees that the recipe to build the target like main.o didn't actually build the target, the answer is "that's not now make works". There are actually tons of situations where you don't want the recipe to build the target. Just as one example, consider a rule like:

    clean:
            rm -f *.o
    

    ... would fail because it doesn't create a target clean.