[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Rule-specific variables
From: |
Brian Dessent |
Subject: |
Re: Rule-specific variables |
Date: |
Mon, 28 Apr 2008 10:26:47 -0700 |
Jeffrey Ratcliffe wrote:
> I'm trying to optionally add arguments to a command, depending on the
> target, as shown by my (obviously non-working) example:
>
> %.xdb : %.bdfi
> var=1
> [ $(basename $(@F)) = part_of_filename ] && var=2
> command --var=$(var) $(basename $(@F)).bdfi
Everything that is part of the recipe (i.e. starts with a TAB) is passed
directly to the shell after undergoing variable expansion, so any
variable assignments that occur are in the domain of the shell and not
make. Try the following two commands to understand why this won't work:
sh -c 'var=1'
sh -c 'echo var is: $var'
This is essentially what you are telling make to invoke with your
makefile, and as you can see any assignment to var in the first command
is invisible to the second one, because any changes to 'var' in the
child process effectively disappear when that child terminates.
Therefore if you want to use shell variables you need to write the
recipe so that it uses a single shell invocation, e.g.
sh -c 'var=1; echo var is: $var'
You can still write the recipe on multiple lines but you must use '\' at
the end of each line and separate each command with ';' so that
logically it's still one single command.
Moreover, using this technique 'var' is a shell variable not a 'make'
variable so you cannot refer to it as $(var). You need for the shell to
see it as $var (or ${var}) so you must write it as $$var (or $${var}) in
the makefile, so that make passes the $ through to the shell rather than
trying to expand it as an (empty) make variable. See section 5.1.2
("Using Variables in Recipes") of the manaul. You might end up with
something like:
%.xdb : %.bdfi
var=1; \
[ $(basename $(@F)) = part_of_filename ] && var=2; \
command --var=$$var $<
There is another way to handle this, however. You can do all the logic
using 'make' functions:
%.xdb : %.bdfi
command --var=$(if $(findstring part_of_filename,$(basename
$(@F))),2,1) $<
This is potentially more efficient since 'make' expands the $(if ...)
expression before passing it to the shell, avoiding the need for the
shell to have to fork/exec the 'test' binary to evaluate the expression
(although most common Bourne shell implementations do have a 'test'
builtin to avoid this cost.) But even still it will likely be faster to
use $(if ...) since make has an optimization where it can skip the shell
and invoke the command directly if the command is simple, e.g. if after
expansion it contains no shell metacharacters or shell constructs like
redirection or quoting or &&.
The flip side of the coin is that using functions like $(if ...) is GNU
make specific and so your makefile will not be usable with other 'make'
implementations, whereas doing it in the shell does not depend on any
'make' features. However, since you are already using $(basename ...)
you most likely don't care about portability since that's specific to
GNU make too, AFAIK.
Brian