39
votes

I have already seen How to manually call another target from a make target?, but my question is a bit different; consider this example (note, stackoverflow.com changes the tabs to spaces in display; but tabs are preserved in source, if you try to edit):

TEXENGINE=pdflatex

pdflatex:
    echo the engine is $(TEXENGINE)

lualatex:
    TEXENGINE=lualatex
    echo Here I want to call the pdflatex rule, to check $(TEXENGINE) there!

Here, if I run the default target (pdflatex), I get the expected output:

$ make pdflatex 
echo the engine is pdflatex
the engine is pdflatex

But, with the target lualatex, I want to:

  • change the make variable TEXENGINE to lualatex, and then
  • call the same code as in pdflatex (which uses it).

How could I do that?

Clearly, in my lualatex rule I don't even manage to change the TEXENGINE variable, because I get this when I try it:

$ make lualatex 
TEXENGINE=lualatex
echo Here I want to call the pdflatex rule, to check pdflatex there!
Here I want to call the pdflatex rule, to check pdflatex there!

... so I would really like to know if something like this is possible in Makefiles.

2
For a start, I wouldn't call that target pdflatex, if you're using it to check arbitrary stuff. I'd suggest something like checkEngine, and make it .PHONY.Oliver Charlesworth
Thanks, @OliverCharlesworth - I think that is fine, though, because pdflatex in this use case is the default, and so I get the same result for just make or make pdflatex (and the use case is then to change engines by specifying them as targets to make, as in make lualatex). Cheers!sdaau
Well, it's up to you ;) (I'd find that rather confusing and bad practice...) Can you just do make TEXENGINE=whatever, and structure a generic set of targets/rules that use the user-specified TEXENGINE variable?Oliver Charlesworth
Thanks again @OliverCharlesworth - I agree it would have been bad practice, especially for code building; but in this case, it will be very limited how this kind of a makefile would grow, so I'd dare ignore bad practices in exchange for command line convenience :) Otherwise, I'd forgotten all about variables on the make command line - just remembered while writing my answer below. Cheers!sdaau

2 Answers

64
votes

Use a target-specific variable

There is one more special feature of target-specific variables: when you define a target-specific variable that variable value is also in effect for all prerequisites of this target, and all their prerequisites, etc. (unless those prerequisites override that variable with their own target-specific variable value).

TEXENGINE=pdflatex

pdflatex:
    echo the engine is $(TEXENGINE)

lualatex: TEXENGINE=lualatex
lualatex: pdflatex
    echo Here I want to call the pdflatex rule, to check $(TEXENGINE) there!

The output is:

$ make pdflatex
echo the engine is pdflatex
the engine is pdflatex
$ make lualatex
echo the engine is lualatex
the engine is lualatex
echo Here I want to call the pdflatex rule, to check lualatex there!
Here I want to call the pdflatex rule, to check lualatex there!
6
votes

Well, I managed to get to a sort of a workaround, but I don't exactly understand it much - so a more learned answer will be appreciated. For me here, these links helped:

So here is the example modified - apparently, to call a rule from a rule afterwards (not as a prerequisite, rather, as a postrequisite), I can only recursively call make, while having the new variable value specified on its command line:

TEXENGINE=pdflatex

pdflatex:
    echo the engine is $(TEXENGINE)

lualatex:
    echo Here I want to call the pdflatex rule, to check $(TEXENGINE) there!
    $(MAKE) TEXENGINE=lualatex pdflatex

The output is somewhat more verbose than I'd like it, but it works:

$ make lualatex 
echo Here I want to call the pdflatex rule, to check pdflatex there!
Here I want to call the pdflatex rule, to check pdflatex there!
make TEXENGINE=lualatex pdflatex
make[1]: Entering directory `/tmp'
echo the engine is lualatex
the engine is lualatex
make[1]: Leaving directory `/tmp'

... which is what I wanted purely command-line interaction-wise, but I know is not the best solution (see @JonathanWakely's comment below)