#echo in Makefile always causes error " *** missing separator. Stop." - makefile

I put
#echo "============= $(TOOLPREFIX) ================="
in line 34 of Makefile of xv6 used by many OS courses, in hope of printing out the value of variable TOOLPREFIX. But I always got error
Makefile:37: *** missing separator. Stop.
This line is before any target. I tried everything I could, like adding Tab at the beginning of the command, moving the command to everywhere in Makefile, or deleting the symbol # before echo, but I always got an error no matter what. But if I comment out this command, there is no error. So, how should I correctly print out a variable in this Makefile?
As a side note, if I add Tab at the beginning of the command, the error I got is "Makefile:37: *** recipe commences before first target. Stop." But if I move the #echo command to the bottom of Makefile, "Makefile:287: *** missing separator. Stop." comes out again.
The environment is Window Subsystem for Linux with ubuntu 20.04 installed.

Should not use echo command there. Should use this to print out message:
$(info ============= $(TOOLPREFIX) =================)

Your directive can't be outside any rule.
You have to create one:
mydebug:
#echo "============= $(TOOLPREFIX) ================="

In my case $(info bla bla '$(FOO)') gives an error(missing operator) but
$(warning bla bla '$(FOO)') works fine.

Related

How to execute a bash script into a makefile

I have a simple bash script, that install and zip a NodeJS application. It's worked great local. Now I want to execute this script from a Makefile. So I wrote this code
.FOO: install_and_zip
install_and_zip: ./install_and_zip_foo.sh
So if I run this Makefile with make foo I'm getting this error message:
make: *** No rule to make target `foo'. Stop.
Makefile and bash script are in the same directory.
What I'm doing wrong? Can you help me to fix this Makefile?
Different errors. This will work:
foo: install_and_zip
install_and_zip:
# next line must start with a real TAB (ASCII 9)
./install_and_zip_foo.sh
If you want to make foo, then call the rule foo, but not FOO or .FOO.
Code goes always below the rule. All command lines must start with a real TAB (ASCII 9, but not a series of spaces).
Rule foo calls rule install_and_zip. Is this your whish? Otherwise this will do it too:
foo:
# next line must start with a real TAB (ASCII 9)
./install_and_zip_foo.sh
You should write "make .FOO" as you have defined it to be that way. However, you have to properly write your Makefile (tab identations and so on). If you do, you can just write 'make' and the tool will identify "install_and_zip" as the main target, thus executing your script.
PD: targets with a leading '.' (and without slashes) will be ignored by make when trying to identify the main goal (i.e. they won't run just executing 'make'). So, unless you know what you are doing, just rename your target to 'foo'.

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.
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.
On Windows, you can use : as a comment character. The traditional comment keyword in MS-DOS is REM (as in "remark").

GNUMake: How to separate the make file statements after any rule?

Case 1
all:
<TAB> #echo hei
#done
ifneq ($(DD),1)
<TAB> TESTVAR:=1
endif
Case 2
all:
<TAB> #echo hei
#done
ifneq ($(DD),1)
<SPACE> TESTVAR:=1
endif
Case 3
ifneq ($(DD),1)
<TAB> TESTVAR:=1
endif
all:
<TAB> #echo hei
As you all know case #2 and #3 will work, but not case #1.
Below is error for case #1,
hei
TESTVAR:=1
/bin/sh: TESTVAR:=1: command not found
make: *** [all] Error 127
Reason is TESTVAR:=1 is interpreted as command instead of makefile variable, because the statment comes after a rule.
My question here is, how to avoid this problem without using any fixes like case #2 & case #3 ?
You cannot use a tab in front of a Makefile assignment. Take it out (or replace it with spaces) and you should be fine.
There is no way to "fix" this. Many people don't realize this, but a "recipe context" does not stop at a blank line, or a comment, and certainly not at a conditional statement like ifdef.
When make is parsing a recipe for a rule, it will consider all subsequent lines that begin with TAB to be part of the recipe, until it finds a line which does not begin with a TAB. Blank lines (including lines containing nothing but comments) and conditional lines do not end the recipe.
The only thing that will terminate a recipe is another rule or a variable assignment, that does not start with a TAB. Or the end of the file, of course.

make error: "make[1]: *** [directories] Error 1"

When I try to run "make all" on a makefile with some complexity I get this errors:
C:\BITCLOUD\BitCloud_PS_SAM3S_EK_1_10_0\BitCloud_PS_SAM3S_EK_1_10_0\Applications\ZAppSi\Dem o\SEDevice>make all
make -C makefiles/PC -f Makefile_PC_Gcc all APP_NAME=DemoSE
make[1]: Entering directory
'C:/BITCLOUD/BitCloud_PS_SAM3S_EK_1_10_0/BitCloud_PS_SAM3S_EK_1_10_0/Applications/ZAppSi/Demo/SEDevice/makefiles/PC'
A sintaxe do comando está incorrecta.
make[1]: *** [directories] Error 1
make[1]: Leaving directory
'C:/BITCLOUD/BitCloud_PS_SAM3S_EK_1_10_0/BitCloud_PS_SAM3S_EK_1_10_0/Applications/ZAppSi/Demo/SEDevice/makefiles/PC'
make: *** [all] Error 2
where the line
A sintaxe do comando está incorrecta.
translated to english means: "The syntax of the command is incorrect"
I already tried to change the project to different directories, check spaces in file names, using GNU make and also use MinGW make (mingw32-make) and the result is the same with both "make". I also checked for all files that are included in the makefile and they correspond.
Im not an expert in makefiles, so Im asking for help.
What is the main problem that occurs when make throws this type of error?
It is likely not make that throws this error, but a command executed by make returns with a nonzero exit status, in this case with status 1 (due to Error 1); then the top level make stops with Error 2. Note that make by default stops as soon as a command fails.
Since the output doesn't show what command was executed, there is no way to tell what went wrong exactly.
EDIT: from the GNU make manual:
-d Print debugging information in addition to normal processing.
The debugging information says which files are being considered
for remaking, which file-times are being compared and with what
results, which files actually need to be remade, which implicit
rules are considered and which are applied---everything inter‐
esting about how make decides what to do.
--debug[=FLAGS]
Print debugging information in addition to normal processing.
If the FLAGS are omitted, then the behavior is the same as if -d
was specified. FLAGS may be a for all debugging output (same as
using -d), b for basic debugging, v for more verbose basic
debugging, i for showing implicit rules, j for details on invo‐
cation of commands, and m for debugging while remaking make‐
files.
I suggest running make --debug=j to see the commands.

GNU make yields "commands commence before first target" error

In my makefile, I would like to check for the existence of a library and give an informative error message. I created a conditional that should exit the make process when the file is not found:
9: ifeq ($(${JSONLIBPATH}),)
10: JSONLIBPATH = ${ALTJSONLIBDIR}/${LIBJSON}
11: endif
12: ifeq ($(${JSONLIBPATH}),)
13: $(error JSON library is not found. Please install libjson before building)
14: endif
My makefile gets stuck on line 13:
Makefile:13: *** commands commence before first target. Stop.
After line 13, my makefile has its targets.
I tried putting this conditional block into a target (e.g. a target called isJSONLibraryInstalled) but this does not execute correctly.
How would I check for a file's existence and handle the error case, before processing targets? Apologies if this is a dumb question.
First of all, you are looking at the contents of a variable that is named after the current path, which is probably not what you want. A simple environment variable reference is $(name) or ${name}, not $(${name}). Due to this, line 13 is always evaluated.
Second, I think it is choking on the indentation of the $(error ...) expression. While the expression resolves to an empty string, there is still a tab character at the start of the line, which indicates a command, which in turn cannot exist outside a rule.
I think using spaces rather than tabs to indent would work.
When you get Make error messages, always check the Error message documentation
On GNU Make 3.81 (error appears to have been removed from newer versions), it says:
This means the first thing in the makefile seems to be part of a command script: it begins with a TAB character and doesn't appear to be a legal make command (such as a variable assignment). Command scripts must always be associated with a target.
What makes matters more confusing is that "doesn't appear to be a legal make command" part. That explains why in:
a := b
$(error a)
the error happens at line 2 and not 1: make simply accepts statements that it can parse, like the assignment, so the following works:
a := b
a:
echo $a
Note: SO currently converts tabs to spaces in code, so you can't just copy the above code into your editor.
For me it was an unnecessary white space before the connector that was causing this.
On slickEdit I selected the option to view all special character and noticed the black sheep.
You can check whitespaces, spaces and tabs by using VSCode [View > Render Whitespace]
As you can see;
command-1 has a tab (->) and whitespace at the end
command-2 has space at first
command-3/4 has tab+spaces
So, you should remove the whitespaces at the end and apply the same spaces with the same action. e.g: tab like the following;

Resources