22

In a makefile, escaping a new-line with \ allows to split a single-line long string content across multiple source lines. However, the new-line is replaced with a space. Is there a transparent line break in the source that does not affect the string content?

VAR=w\
o\
r\
d

all:
    echo $(VAR)

The desired output is 'word', but the actual output is 'w o r d'.

alexei
  • 2,031
  • 1
  • 26
  • 28
  • 1
    Possible duplicate of [How can I break a variable definition across multiple lines in a Makefile without spaces?](https://stackoverflow.com/questions/21223880/how-can-i-break-a-variable-definition-across-multiple-lines-in-a-makefile-withou) – Louis Jul 16 '19 at 19:36

2 Answers2

18

The simplest solution is to use $\<newline> to split the line (at least if you are using GNU Make):

VAR = w$\
      o$\
      r$\
      d

all:
    echo $(VAR)

The output will be "word" with no spaces. This is because GNU Make will replace backslash-newline-whitespace with a single space, making the assignment to VAR be equivalent to:

VAR = w$ o$ r$ d

From https://www.gnu.org/software/make/manual/html_node/Reference.html#Reference: "A dollar sign followed by a character other than a dollar sign, open-parenthesis or open-brace treats that single character as the variable name." So the $<space> pairs are expansions of the variable whose name is a single space character. Since this variable is not defined by default, it will expand to the empty string.

Note that the variable VAR will still contain the $<space> pairs until it is expanded. Most of the time, this doesn't matter, but if your makefile depends on using $(value VAR) to process the underlying (unexpanded) value, the above technique may provide surprising results.

Also, the recently released GNU Make 4.3 now explicitly documents this technique for splitting lines (https://www.gnu.org/software/make/manual/make.html#Splitting-Lines):

Splitting Without Adding Whitespace

If you need to split a line but do not want any whitespace added, you can utilize a subtle trick: replace your backslash/newline pairs with the three characters dollar sign/backslash/newline:

var := one$\
       word

After make removes the backslash/newline and condenses the following line into a single space, this is equivalent to:

var := one$ word

Then make will perform variable expansion. The variable reference ‘$ ’ refers to a variable with the one-character name “ ” (space) which does not exist, and so expands to the empty string, giving a final assignment which is the equivalent of:

var := oneword

For other ideas, see my answer to a similar question here: How can I break a variable definition across multiple lines in a Makefile without spaces?

A longer treatment of line continuation options can be found in my article "GNU Make line continuations": http://drmikehenry.com/gnu-make-line-continuations/

Michael Henry
  • 496
  • 3
  • 8
  • 1
    There are tricks to this that rely on currently-not-well-defined behavior. For example it's not legal to create a variable name containing space directly right now (you can do so with tricks), so it could become illegal to try to expand a variable name containing a space. Also it relies on backslash being interpreted before `$` in the `$\` pair. I know Michael has filed a bug on Savannah asking that this behavior become defined and supported. – MadScientist Jun 15 '18 at 23:36
  • It's always nice to hear from an active maintainer! (http://mad-scientist.net/about/) The impetus for the ticket (https://savannah.gnu.org/bugs/index.php?54116) is that the documentation (but not the implementation) currently disallows whitespace in variable names. It's rare to get a useful new feature for free, retroactively applied to (all?) previous versions, just by documenting it. I'm hopeful that the GNU Make maintainers will see fit to document this as an official feature, eliminating one of the larger barriers to readable Makefiles. – Michael Henry Jun 17 '18 at 20:43
  • It seems strange to split this answer (_e.g._, the useful bit about `value`, which can sometimes be avoided with `:=`) across two questions. Should we mark this one as a duplicate? – Davis Herring Jun 17 '18 at 23:17
  • Whitespace in variable names is disallowed in the implementation, if done directly: `foo bar = biz` will give an error. However you can still do it indirectly: if `$s` expands to a space then `foo$sbar = biz` will set the variable named `foo bar`. The reason whitespace is disallowed is because we want the freedom to write things like `$(foo bar)` and have that mean something different than referencing the variable named `foo bar`. Single space could be treated specially. It is certainly nice that it works in all versions of GNU make. But you must admit, it feels like a bit of a hack :). – MadScientist Jun 18 '18 at 00:38
  • The reason it works is indeed a hack; but the syntax itself is quite good IMO: ``\`` inserts a space, ``$\`` doesn't. I've seen the idea of interpreting ``$(foo bar)`` as ``$(call foo,bar)``. Eliminating ``call`` is a minor benefit, much smaller IMO than having a way to perform readable function indentation. Also, backward compatibility is a must-have feature for me; we can barely require Make 3.81 (12 years old now). It would be a decade before I could use a hypothetical new feature like ``$(foo bar)`` :-) – Michael Henry Jun 18 '18 at 12:21
10

This was just asked yesterday: How can I break a variable definition across multiple lines in a Makefile without spaces?

The short answer is no, there's no way to do that. This behavior is required by the POSIX standard for make.

All you can do is try postprocessing the string to remove the whitespaces using $(subst ...) or similar.

Community
  • 1
  • 1
MadScientist
  • 92,819
  • 9
  • 109
  • 136