makefilegnu-make

How to comment a line within a Makefile define directive?


I want to comment one or more line(s) within a define directive in a Makefile so as the line is ignored when the directive is expanded. The goal is to place the commented line as a hint for the users of my Makefile to show an example of what could be into the define directive. The directive is expanded into a target.

In other words, I want that Makefile

define ECHO_FOO = 
#   @echo foo
endef

all: 
    @echo Before call
    $(ECHO_FOO)
    @echo After call

.PHONY: all

to have the same behavior than this one :

define ECHO_FOO = 
endef

all: 
    @echo Before call
    $(ECHO_FOO)
    @echo After call

.PHONY: all

The issue is that the first Makefile gives me the following error :

process_begin: CreateProcess(NULL, #@echo foo, ...) failed. make (e=2): The system cannot find the file specified. Makefile:6: recipe for target 'all' failed make: *** [all] Error 2

The GNU make:Makefile contents page states that :

Within a define directive, comments are not ignored during the definition of the variable, but rather kept intact in the value of the variable. When the variable is expanded they will either be treated as make comments or as recipe text, depending on the context in which the variable is evaluated.

But this doesn't explain in which specific case the # symbol is treated as a make comment or as a recipe text (which seems to be the problem I meet).

Can someone tell me how to have the # symbol treated as a comment mark in a define function ?

I have already tried all of the following lines with the idea of escaping the # symbol or changing the indentation but none of them gave me a correct output :

#@echo foo
    #@echo foo
##@echo foo
    ##@echo foo
\#@echo foo
    \#@echo foo 
/#@echo foo
    /#@echo foo 

I'm running MinGW make 3.82 on Windows but I have already tried other implementations of make v3.82.90 and 4.1.


Solution

  • There's no way to do what you're asking for directly. The contents of the variable are expanded in a recipe context, so no matter what the variable expands to it will be considered part of the recipe and whatever characters are there will be passed to the shell.

    Note you can use : in UNIX shells as well as Windows command.com, because : is the shell no-op operator. You have to add a space after it though otherwise it will try to run the command :echo which is not a valid command. However, further note that the shell will still expand the line! This means that if you use backquotes etc. then those still are expanded. Also note that since it's a statement, semicolon will stop it. So for example:

    define ECHO_FOO
    : echo hi `echo there 1>&2` ; echo bye
    endef
    
    all: ; @$(ECHO_FOO)
    

    Here, the hi won't be printed because the echo command is not run, but the backticks are still expanded so there will be printed (to stderr) and the semicolon ends the "no-op" command so bye will also be printed.

    If your commands are simple enough then : will work, but if they're that simple one wonders why you're using define...

    Another option is just to override the variable, rather than comment it out:

    define ECHO_FOO = 
       @echo foo
    endef
    
    ECHO_FOO =
    

    ETA: In the comments you affirm that the command is simple. I don't quite know what you mean by could be expanded by the final user or why that makes a difference.

    But what I was alluding to is that if you have a simple command you can just write:

    ECHO_FOO = echo hi
    

    and not use define. define is only needed for complicated commands: really it's only required for commands that contain un-escaped newlines.

    And, if you write:

    ECHO_FOO =# echo hi
    

    then you ARE commenting out the content of the variable using make comments, not shell comments, so it will work everywhere.