-1

In a GNU Makefile, I am defining the contents of a temporary file using multi-line variable syntax as follows:

define __FOO__
file
with
many
lines
endef

This file happens to be a GDB script, which supports function definitions with the following syntax:

define my-func
    foo
end

I suppose you see the problem already:

define __FOO__
define my-func
    foo
end
endef

make pukes with the following error:

Makefile:218: *** missing 'endef', unterminated 'define'.  Stop.

In the link I posted above, GNU confidently explains the feature:

You may nest define directives: make will keep track of nested directives and report an error if they are not all properly closed with endef. Note that lines beginning with the recipe prefix character are considered part of a recipe, so any define or endef strings appearing on such a line will not be considered make directives.

So if I heed that advice and insert the recipe prefix character (\t) at the beginning of each line:

define __FOO__
        define my-func
            foo
        end
endef

It happily parses this, but now __FOO__ has a leading \t at the front of every line when I write it to file in a recipe:

foo:
        @echo $$__FOO__ > my-file
$ cat my-file
        define my-func
            foo
        end

This may be OK in many cases, but I can imagine it leads to some potentially ambiguous content, which I would rather not enjoy debugging next year.

How should I be handling this — including a string with a leading define, and not have leading tabs in the output?

ardnew
  • 2,028
  • 20
  • 29
  • It would be best to not rely on external tools, e.g. `@echo $$__FOO__ | sed -e 's/^\t//' > my-file`, since this Makefile conceivably would run on multiple systems, not to mention this would destroy any intentional leading tabs – ardnew Aug 31 '21 at 05:17
  • How does `echo $$__FOO__` work for you, this outputs an empty string for me. – ssbssa Aug 31 '21 at 10:46
  • @ssbssa the OP has probably [exported](https://www.gnu.org/software/make/manual/make.html#Variables_002fRecursion) either that particular variable or all of them. But using `echo` with *anything but fixed strings with no backslashes* (especially with unquoted variables) is bound to bite them back sooner or later ;-) –  Aug 31 '21 at 12:06
  • @ktzap If I export the variable, I get the error `*** missing separator. Stop.` – ssbssa Aug 31 '21 at 12:19
  • 1
    @ssbssa that's because of this [censored] site which is replacing tabs with spaces -- if you indent the `define my func` ... `end` with TABS *and* also `export __FOO__`, the OP's example will print `define my-func foo end` (which is probably not what he's expecting, that's why they should use `echo "$$__FOO__"` or, better `printf '%s\n' "$$__FOO__"`) –  Aug 31 '21 at 12:28
  • @ktzap Judging by your answer, you clearly understood quoting wasn't the problem (i.e., invalid `Makefile` syntax). The example recipe was for conceptual purposes, which I mistakenly assumed any reader would know wasn't the problem. – ardnew Sep 01 '21 at 22:51
  • @ssbssa Yes, it must be exported in order to use it in a recipe: `export __FOO__`. Along with the other pedantic criticism, perhaps I should also explain these lines are expectantly placed in a file, and that file is given to `make` as argument on a command line such as: `make -f "Makefile"` :) – ardnew Sep 01 '21 at 23:02

1 Answers1

1
Makefile:218: *** missing 'endef', unterminated 'define'.  Stop.

You can work around that by using macros which expand to the whole or part of the troublesome directives.

Simplest and dumbest:

d = d
e = e
define __FOO__
$define my-func
    foo
$end
endef


export __FOO__
all:; @printf '%s\n' "$$__FOO__"