[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Allowing spaces in macro call?

From: Paul Smith
Subject: Re: Allowing spaces in macro call?
Date: Sat, 28 Aug 2010 21:35:26 -0400

On Wed, 2010-08-18 at 15:45 -0500, Peng Yu wrote:
> > According the manual, it advises not to use spaces or newline in macro
> > call like the following. But I feel that it is irritating not to allow
> > spaces and newlines, because allowing them could make my Makefile more
> > readable.
> >
> > I'm wondering if there is any option to
> > globally enable the striping of $1, $2,... for all arguments. If it is
> > not there in GNU Make, could it be added as an command option, or
> > better, added as a derivative (just like derivatives "use warnings;"
> > in perl, to change the behavior of a single Makefile). Or there might
> > be a better solution to this problem?

I don't see any good way to do this without adding too much complexity.

> People may say to use a variable, but since any
> variable is global, it would cause problem when I call test multiple
> times.

Not true in the example below, because in this example all references to
$1 are in "immediate" expansion context.  So you can use the same
variable in all cases and it will work fine.

I'll repeat: you really should not be trying to use eval until you've
completely and totally internalized make's expansion rules (when things
are expanded and when they're not).  Eval is a whole other level of
complexity and if you don't have the basics down, you'll never be able
to untangle it.

> .PHONY: all
> define test
> #$1:=$$(strip $1) # don't work here
> NAME.$$(strip $1):=$$(strip $1)
> all: $$(NAME.$$(strip $1))
> .PHONY: $$(NAME.$$(strip $1))
> $$(NAME.$$(strip $1)):
>         @echo $$@
> endef

> One more thing, I had tried to assign $1 to the stripped version of
> it, which don't work. 

There are many things that are strange or wrong with this.

First, what's the point of escaping the $(strip...) function?  Why not
just write "$(strip $1)"?  This again leads me to believe you're not
fully understanding make's expansion rules.  You could just write:

        define test
        NAME.$(strip $1):=$(strip $1)
        all: $$(NAME.$(strip $1))
        .PHONY: $$(NAME.$(strip $1))
        $$(NAME.$(strip $1)):
                @echo '|$$@|'

Note also: here I've quoted the echo argument in the recipe and put
guard characters around it: "@echo '|$$@|'"; I suggest you ALWAYS do the
same.  Trying to understand and debug whitespace issues using plain
"echo" with no quoting etc. is ridiculous: the shell will strip away
whitespace before echo gets ahold of it, so you can't see what the REAL
values of these variables are.

Second, as written this is overly complicated for no reason at all; if
NAME.$(strip $1) is just assigned to $(strip $1), why not just use
$(strip $1) everywhere?  Creating a variable where the name contains the
value just adds a lot of useless typing and complexity, and definitely
never makes anything any simpler.  You could just rewrite the above as:

        define test
        all: $(strip $1)
        .PHONY: $(strip $1)
        $(strip $1):
                @echo '|$$@|'

Third, as I mentioned above there's absolutely no problem using a simple
variable like "v" or whatever here because all references to $1 are
handled in an immediate context.  So, you can just write:

        define test
        v := $(strip $1)
        all: $$v
        .PHONY: $$v
                @echo '|$$@|'

If you don't find it confusing you can use "1" here instead of "v"; make
won't be confused but don't do it if you think _you_ will be confused.

If any references must handled in a deferred context then indeed you'd
need something other than a simple "v", but you can use a
target-specific variable in that case.

Finally, since I can't seem to get across the need for complete
understanding of expansion contexts before dealing with eval, let me
give you a critical hint for working with eval, which I think has been
mentioned before and may save you time and help you see what's going on:

If you don't understand what eval is doing, replace the eval call with a
call to info (or add a call to info with the same arguments).  That is,
in your example where you have:

        $(eval $(call test, a))

You can change that to:

        $(info $(call test, a))

(or else just add such a call in the same place).  This will print out
the exact text which the eval function will parse, after the call
function is complete and everything has been expanded.  If that output
does not look right to you, and is not what you would have typed by hand
if you'd created the output yourself rather than trying to create a
macro for it, then you've got something wrong in your expansion

Given my last define of "test" above, adding the above info call to the
makefile will display:

        v := a
        all: $v
        .PHONY: $v
                @echo '|$@|'

You can see that this is a good, valid makefile and will do what you

If you want to do this to a lot of different variables you might
consider using $(warning ...) instead of $(info ...) since the former
will print the makefile name/linenumber in addition to the expanded

 Paul D. Smith <address@hidden>          Find some GNU make tips at:            
 "Please remain calm...I may be mad, but I am a professional." --Mad Scientist

reply via email to

[Prev in Thread] Current Thread [Next in Thread]