Germán Diago
Germán Diago

Reputation: 7673

Make goal depend on same prerequisite with different flags

I am trying to make a self-contained Makefile. My Makefile has a rule like the following one:

benchmark:
      (something that depends on variable CXX)

That rule represents a single benchmark for a single compiler. I want to benchmark several compilers.

So what I would like to accomplish is the following without invoking $(MAKE) recursively from inside the plot rule (pseudo-syntax):

plot: benchmark CXX=clang++ benchmark CXX=g++
    (generate a plot)

Namely, I want this goal to depend on the prerequisite benchmark + one flag and treat both as two different prerequisites, even if they are the same rule.

Upvotes: 0

Views: 619

Answers (2)

Renaud Pacalet
Renaud Pacalet

Reputation: 29375

As suggested by reinierpost you can define a pseudo target for each of your compilers. A pseudo-target is a target that has no real file production associated with it.

But as make is really happy with real file targets (targets are considered up-to-date or not based on their last modification date) you could also use your plot result as a target. And, as also suggested, you could wrap all this in a foreach-eval-call construct to factorize your code. Something like:

COMPILERS = clang++ g++

define PLOT_compiler
plotfile-$(1): CXX = $(1)
plotfiles += plotfile-$(1)
endef

$(foreach compiler,$(COMPILERS),$(eval $(call PLOT_compiler,$(compiler))))

all: $(plotfiles)

plotfile-%:
    <generate plot file using the CXX variable>

The foreach-eval-call construct instantiates one set of make statements per compiler, as defined by the PLOT_compiler variable.

If you prefer collecting all results in a single file named, let's say, plots.txt you can instead use:

COMPILERS = clang++ g++

define PLOT_compiler
plotfile-$(1): CXX = $(1)
plotfiles += plotfile-$(1)
endef

$(foreach compiler,$(COMPILERS),$(eval $(call PLOT_compiler,$(compiler))))

plots.txt: $(plotfiles)
    cat $(plotfiles) > $@

plotfile-%:
    <generate plot file using the CXX variable>

clean:
    rm -f $(plotfiles)

ultraclean:
    rm -f $(plotfiles) plots.txt

The clean and ultraclean targets will help you keeping your workspace clean. You can easily test all this by replacing the <generate plot file using the CXX variable> recipe by echo $(CXX) > $@, and:

make
make clean
cat plots.txt

Upvotes: 1

reinierpost
reinierpost

Reputation: 8611

Assuming GNU Make, I think the logic you're looking for can be expressed in this way:

CXXES := clang++ g++

benchmark: $(CXXES:%=benchmark-%)

Then have a single rule to generate the benchmarks:

benchmark-%:
    # generate a plot using $(CXX), which will be equal to $@

or multiple ones if your plot generation rules are compiler specific:

benchmark-clang++: CXX = clang++
    # generate a plot using $(CXX)
    (...)

benchmark-g++: CXX = g++
    # generate a plot using $(CXX)
    (...)

It would be better to identify output files (plots?) whose file names depend on the value of $(CXX) and use those as intermediate targets.

Upvotes: 1

Related Questions