Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Escaping makefile variables (for internal makefile use)

Is it possible to "safely" expand a variable in a makefile, escaping all characters that makefile considers special?

As an example, assume that a variable is used as a target:

${external_chaos}:
    dd if=/dev/zero of=${external_chaos}

(drama in example intentional)

If external_chaos contains spaces, ;, #, :, ,, or other makefile-significant characters, then the whole rule gets messed up.

What I imagine as a solution is some Make built-in function that should do this, such as ${escape external_chaos} (imaginary luxury).

${value external_chaos} doesn't do it.

like image 681
Prikso NAI Avatar asked Sep 29 '22 15:09

Prikso NAI


1 Answers

In general you won't succeed (without massive pain, if at all) in using targets with spaces in them. Just give it up. If you must support targets with spaces in them then choose a different build tool, not make.

The short answer is no, there's no built-in function. You can write one yourself using subst; for example in targets you need to escape at least % and ::

TESCAPE = $(subst :,\:,$(subst %,\%,$1))

On the other hand, note that ; and , are not special in targets so you don't need to escape them at all; in fact if you do you'll get incorrect results because the \ will be left in the target name: backslash is only removed if it's quoting a special character.

# is special when you define the variable, but not when the variable is expanded: the parser has already finished looking for comments by then. So you'll have to write:

external_chaos = foo\#bar,biz;baz:boz%bin

to get the # into the variable in the first place, but once it's there you don't need to escape it when the variable is used.

The next interesting thing is that you need to escape differently for targets and prerequisites. So for example, in a target you must not escape ;, but in a prerequisite you must escape ;. So you need different macros:

PESCAPE = $(subst :,\:,$(subst ;,\;,$1))

TESCAPE = $(subst :,\:,$(subst %,\%,$1))

all: $(call PESCAPE,${external_chaos})

$(call TESCAPE,${external_chaos}): ; echo '$@'

gives:

foo#bar,biz;baz:boz%bin
like image 126
MadScientist Avatar answered Oct 08 '22 13:10

MadScientist