Search code examples
c++makefilegnu-make

How the forcing rebuild in my Makefile actually work?


How to force make to always rebuild a file from this answer more specifically, I was able to achieve my goal as a beginner, so I better commented on everything.

I have these 4 files in one directory; ls -F:

iterator  Makefile  test*  test.cpp

where all the files should be self-explanatory, but I have some little feeling, the iterator may sound a bit odd, so just to be crystal clear, I want to store/show the information on how many times I recompiled the test.cpp source code.

Here I would politely like to ask HOW the forcing of rebuild/recompile actually works? I am no expert on Makefiles so that about sums it up.


Here is my actual Makefile with no changes at all:

CXX := g++-10
CXXFLAGS := -O2 -std=c++20 -Wall -Wextra -Werror -Wpedantic -pedantic-errors
APP_NAME := test
SRC_FILE := $(APP_NAME).cpp

# The following works!
# However, I have no idea how? :(
$(APP_NAME): .force_rebuild
.PHONY: .force_rebuild

$(APP_NAME): $(SRC_FILE)
# quickly delete terminal buffer
    @clear
# increase test number
    @expr $$(cat iterator) + 1 > iterator
# print test number description
    @printf '%s' "Test Nr.: "
# set bright cyan color for the number
    @tput bold; tput setaf 6
# print test number
    @cat iterator
# reset to normal terminal color
    @tput sgr0
# compile (always force rebuild)
    @$(CXX) $(CXXFLAGS) $(SRC_FILE) -o $(APP_NAME)
# run my test app
    @./$(APP_NAME)

For completeness, I work on Linux Mint 20.2 Cinnamon with Bash as shell and VS Code as a text editor using GNU Make 4.2.1.

Side note: It looks weird and less readable when without syntax highlight, which is the only why I am attaching a screenshot also:

VS Code editing my Makefile


Solution

  • From the manual:

    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. If the target is older than any prerequisite from any rule, the recipe is executed.

    In your case you have two rules for the app target. The prerequisite .force_rebuild from the first rule is marked as .PHONY, which makes your app target always older than .force_rebuild. This triggers execution of the recipe for the app target. That recipe is in the second rule.

    Just in case, also pointing out the paragraph following the above quote:

    There can only be one recipe to be executed for a file. If more than one rule gives a recipe for the same file, make uses the last one given and prints an error message.