yapkm01
yapkm01

Reputation: 3761

Makefile: How does a header file change trigger a target?

I have the below Makefile.

#
# General Makefile
#

BUILD := build
CXXFLAG := -std=c++20
CXX := g++
SRC := 16.15.cc
OBJ := $(SRC:%.cc=$(BUILD)/%.o)
DEP := $(OBJ:.o=.d)
MKDIR_P := mkdir -p

all: directories $(OBJ)

directories:
        $(MKDIR_P) $(BUILD)

$(BUILD)/%.o: %.cc # --> block 1
        echo 1  
        -$(CXX) -c $(CXXFLAG) $< -o $@

$(BUILD)/16.15.o: 16.15.cc include/16.15.h  # --> block 2

.PHONY: directories all

Observation:
When i modify and save include/16.15.h, Block 1 gets executed.

$ make    
  mkdir -p build
  echo 1
  1
  g++ -c -std=c++20 16.15.cc -o build/16.15.o

How? How does this change on a header file trigger block 1?

Upvotes: 1

Views: 68

Answers (2)

John Bollinger
John Bollinger

Reputation: 181179

How does a header file change trigger a target?

Given that this rule ...

$(BUILD)/16.15.o: 16.15.cc include/16.15.h

... provides no recipe for building the target, it is a prerequisite-only rule. make takes into account the prerequisites named in all prerequisite-only rules for each target it needs to build, in addition to the prerequisites given in the rule that provides the recipe for that target. Therefore, yes, if you modify include/16.15.h such that it is newer than $(BUILD)/16.15.o then make will consider the latter out of date and in need of rebuilding. That a different rule will provide the recipe for such a rebuilding is irrelevant.


The question suggests that you may have a flawed mental model of make's operation. Programmers who are less familiar with make sometimes think of make rules as if they were functions in an imperative language, maybe with the prerequisites being arguments. I think the popularity of that arises from its familiarity, but it can be misleading. It leads to wrong ideas, such as assuming that make will consider only the prerequisites given in the rule providing the recipe for the target.

make is not a script interpreter, and makefiles are not scripts. Rather, make is an expert system. The makefile language is by and large a declarative one. In particular, make rules are data, not functions. make operates by taking all the data provided to it

  • in the makefile,
  • on the command line,
  • observable in the filesystem, and
  • configured into it,

and using that to devise and execute a strategy for bringing one or more goal targets up to date with respect to their prerequisites. That often involves using a shell to execute recipes provided to make as data, but that should not be confused with rules being executable, even the ones that provide recipes that are chosen for execution.

Upvotes: 1

HolyBlackCat
HolyBlackCat

Reputation: 96791

You can have more than one target: prereq1 prereq2 prereq3 for any given target. All the prerequisites for a target are combined. The only restriction is that you can have at most one recipe (a set of commands) per target.

And apparently this works in your case too. You have a pattern rule, and can add extra prerequisites to a specific instantiation of it.

Upvotes: 1

Related Questions