46

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.

Community
  • 1
  • 1
sdaau
  • 36,975
  • 46
  • 198
  • 278
  • 1
    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 Oct 15 '14 at 12:45
  • 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 Oct 15 '14 at 12:50
  • 1
    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 Oct 15 '14 at 12:51
  • 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 Oct 15 '14 at 13:04

2 Answers2

74

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!
Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • Thanks for that @JonathanWakely - I was confused at first, because a prerequisite would call `pdflatex` before `lualatex`; but then I tested and realized splitting the `lualatex:` target in two avoids this pitfall - and the solution also works without recursive `make` call, which is great. Thanks also for the note on "target-specific variables". Cheers! – sdaau Oct 15 '14 at 13:08
  • 4
    More specifically, if there isn't anything you need to do in `lualatex` that isn't just what `pdflatex` does then you don't need a recipe body on the `lualatex` target at all. Just the two `lualatex:` lines are enough. – Etan Reisner Oct 15 '14 at 13:25
  • can you have multiple variables defined? – CpILL Sep 03 '20 at 01:08
  • 2
    @CpILL Yes, you can add multiple "lualatex: foo=bar" lines, each one for an additional variable. (I'm not sure if you can do multiple variables on a single line). – chrismo Jun 21 '22 at 14:05
  • What if I want to call `pdflatex` from `lualatex` twice, with different variables? – SOFe Aug 22 '23 at 05:58
  • 1
    @SOFe that seems like it belongs in a new question, not a comment. You could have the lualatex target depend on lualatex1 and lualatex2 targets, which each use a different override for the variable. – Jonathan Wakely Aug 22 '23 at 14:00
7

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)

Community
  • 1
  • 1
sdaau
  • 36,975
  • 46
  • 198
  • 278
  • 4
    What your rule does here is run another instance of `make` and explicitly override the `TEXENGINE` variable. Variables defined on the command-line take precedence over variables defined in the environment or in the makefile, so when the second `make` runs it uses the overridden value. The downside of this approach is you run `make` twice, so if it has to do a lot of work to check the status of prerequisites then you do all that work twice. – Jonathan Wakely Oct 15 '14 at 13:09