Why does `make` think these are invalid options? - makefile

I get the following error when building zedboard:
redacted#redacted C:\dev\fpga-zynq\zedboard
$ make vivado
C:/ProgramData/chocolatey/lib/make/tools/bin/make -C C:/dev/fpga-zynq/rocket-chip/firrtl SBT="java -Xmx2G -Xss8M -XX:MaxPermSize=256M -jar C:/dev/fpga-zynq/rocket-chip/sbt-launch.jar" root_dir=C:/dev/fpga-zynq/rocket-chip/firrtl build-scala
C:\ProgramData\chocolatey\lib\make\tools\bin\make: invalid option -- X
C:\ProgramData\chocolatey\lib\make\tools\bin\make: invalid option -- x
C:\ProgramData\chocolatey\lib\make\tools\bin\make: invalid option -- 2
C:\ProgramData\chocolatey\lib\make\tools\bin\make: invalid option -- G
C:\ProgramData\chocolatey\lib\make\tools\bin\make: invalid option -- X
C:\ProgramData\chocolatey\lib\make\tools\bin\make: invalid option -- 8
C:\ProgramData\chocolatey\lib\make\tools\bin\make: invalid option -- M
C:\ProgramData\chocolatey\lib\make\tools\bin\make: invalid option -- X
C:\ProgramData\chocolatey\lib\make\tools\bin\make: invalid option -- X
C:\ProgramData\chocolatey\lib\make\tools\bin\make: invalid option -- :
C:\ProgramData\chocolatey\lib\make\tools\bin\make: invalid option -- M
C:\ProgramData\chocolatey\lib\make\tools\bin\make: invalid option -- a
C:\ProgramData\chocolatey\lib\make\tools\bin\make: invalid option -- x
C:\ProgramData\chocolatey\lib\make\tools\bin\make: invalid option -- P
C:\ProgramData\chocolatey\lib\make\tools\bin\make: invalid option -- z
C:\ProgramData\chocolatey\lib\make\tools\bin\make: invalid option -- =
C:\ProgramData\chocolatey\lib\make\tools\bin\make: invalid option -- 2
C:\ProgramData\chocolatey\lib\make\tools\bin\make: invalid option -- 5
C:\ProgramData\chocolatey\lib\make\tools\bin\make: invalid option -- 6
C:\ProgramData\chocolatey\lib\make\tools\bin\make: invalid option -- M
make: the `-j' option requires a positive integral argument
Usage: make [options] [target] ...
Options:
-b, -m Ignored for compatibility.
-B, --always-make Unconditionally make all targets.
-C DIRECTORY, --directory=DIRECTORY
Change to DIRECTORY before doing anything.
-d Print lots of debugging information.
--debug[=FLAGS] Print various types of debugging information.
-e, --environment-overrides
Environment variables override makefiles.
-f FILE, --file=FILE, --makefile=FILE
Read FILE as a makefile.
-h, --help Print this message and exit.
-i, --ignore-errors Ignore errors from commands.
-I DIRECTORY, --include-dir=DIRECTORY
Search DIRECTORY for included makefiles.
-j [N], --jobs[=N] Allow N jobs at once; infinite jobs with no arg.
-k, --keep-going Keep going when some targets can't be made.
-l [N], --load-average[=N], --max-load[=N]
Don't start multiple jobs unless load is below N.
-L, --check-symlink-times Use the latest mtime between symlinks and target.
-n, --just-print, --dry-run, --recon
Don't actually run any commands; just print them.
-o FILE, --old-file=FILE, --assume-old=FILE
Consider FILE to be very old and don't remake it.
-p, --print-data-base Print make's internal database.
-q, --question Run no commands; exit status says if up to date.
-r, --no-builtin-rules Disable the built-in implicit rules.
-R, --no-builtin-variables Disable the built-in variable settings.
-s, --silent, --quiet Don't echo commands.
-S, --no-keep-going, --stop
Turns off -k.
-t, --touch Touch targets instead of remaking them.
-v, --version Print the version number of make and exit.
-w, --print-directory Print the current directory.
--no-print-directory Turn off -w, even if it was turned on implicitly.
-W FILE, --what-if=FILE, --new-file=FILE, --assume-new=FILE
Consider FILE to be infinitely new.
--warn-undefined-variables Warn when an undefined variable is referenced.
This program built for i386-pc-mingw32
Report bugs to <bug-make#gnu.org>
make: *** [C:/dev/fpga-zynq/rocket-chip/firrtl/utils/bin/firrtl.jar] Error 2
I am using make from Chocolatey.
redacted#redacted C:\dev\fpga-zynq\zedboard
$ where make
C:\ProgramData\chocolatey\bin\make.exe
C:\cygwin64\bin\make.exe
C:\WinAVR-20100110\utils\bin\make.exe
I've tried reordering variables in my PATH, installing things my msys2 and mingw, but to no avail. I'm using Windows 10 with Cygwin, but the tools I'm using here are Windows-native. I'm not sure why it would be throwing the invalid option errors, it's a bit mystifying to me.

Related

Why do I get "Makefile:1: *** missing separator. Stop." with "set -e"?

I have a single line Makefile that throws the following error: Makefile:1: *** missing separator. Stop. I know there are dozens of duplicate questions with the same error message but most of them suggest something to do with using not using tabs or mysterious special characters.
$ cat -e -v -t Makefile
set -e$
$ make
Makefile:1: *** missing separator. Stop.
As far as I can see, there are no mysterious special characters. Perhaps there are characters that cat -e -v -t doesn't show?
The following works, so I'm guessing it isn't an issue with my make installation:
$ cat -v -e -t Makefile
foo:$
^Iecho "Foo"$
$ make
echo "Foo"
Foo
Some relevant version and shell information.
$ make --version
GNU Make 3.81
$ echo $0
-bash
Edit: See comment by #AProgrammer
Note it throws the same error message regardless of what I have below the set -e.
$ cat -e -v -t Makefile
set -e$
$
foo:$
^Iecho "foo"$
$ make
Makefile:1: *** missing separator. Stop.
Edit 2:
Note adding #!/bin/bash throws the same error message.
$ cat -e -v -t Makefile
#!/bin/bash$
set -e$
$
foo:$
^Iecho "foo"$
$ make
Makefile:2: *** missing separator. Stop.
Edit 3:
Running set -e on my shell directly seems to work (it exits the failed make call as expected).
$ set -e
$ make
Makefile:2: *** missing separator. Stop.
Saving session...completed.
Deleting expired sessions...11 completed.
[Process completed]
There is absolutely no reason for which make would be able to interpret arbitrary shell commands outside of rules.
If you want to exit rules immediately when there is an error, there are several ways to do it, more or less portably.
First, each line in a rule is executed by a separate instance of the shell. This means that if you don't merge them manually (with \ and ;), you'll get the behavior you want if you have one command per line.
Then you can use set -e as part of the probably few rules which need it. For instance;
foo:
set -e; for i in a b c d; mkdir $$i; done
With GNU Make, you can change the flags used to call the shell, additionally passing -e:
.SHELLFLAGS=-ec
With POSIX Make, you can change the shell. I don't know if passing a flag is supported, but it seems so with GNU Make:
SHELL=/bin/sh -e
but you can always pass a wrapper which set the flags as you want:
SHELL=/path/to/mywrapper
with mywrapper being
#!/bin/sh
exec /bin/sh -e "$#"

Why make '--dry-run' with $(MAKE) in a recipe result in an error?

When I run make --dry-run on
all:
false # $(MAKE)
using GNU Make 4.2.1, I get back the following error. Why?
false # make all
make: *** [Makefile:2: all] Error 1
https://www.gnu.org/software/make/manual/make.html#Instead-of-Execution:
The -n, -t, and -q options do not affect recipe lines that begin with + characters or contain the strings $(MAKE) or ${MAKE}.
(--dry-run is an alias for -n.)
https://www.gnu.org/software/make/manual/make.html#MAKE-Variable:
subsystem:
cd subdir && $(MAKE)
[...]
As a special feature, using the variable MAKE in the recipe of a rule alters the effects of the -t (--touch), -n (--just-print), or -q (--question) option. Using the MAKE variable has the same effect as using a + character at the beginning of the recipe line.
[...]
Consider the command make -t in the above example. (The -t option marks targets as up to date without actually running any recipes; see Instead of Execution.) Following the usual definition of -t, a make -t command in the example would create a file named subsystem and do nothing else. What you really want it to do is run cd subdir && make -t; but that would require executing the recipe, and -t says not to execute recipes.
The special feature makes this do what you want: whenever a recipe line of a rule contains the variable MAKE, the flags -t, -n and -q do not apply to that line. Recipe lines containing MAKE are executed normally despite the presence of a flag that causes most recipes not to be run.
Your recipe contains $(MAKE), so it gets executed despite --dry-run. false returns an exit status of 1, which is considered an error by make.

VERBOSE environment in shell script

I'm trying to write a Bash script, which compiles and runs all C files in the current directory. My Bash script is the following:
#!/bin/bash
LIST="$(ls *.c)"
echo "Compile all C source files"
for f in $( ls *.c); do
#echo "C file: $f"
gcc $f -o "${f%.*}"
./"${f%.*}"
done
Now, I'm trying to define a VERBOSE environment variable. If VERBOSE environment variable is set then my Bash script should display the command that is being used to compile the source file.
How can I define such a VERBOSE environment variable in this Bash script?
When verbose is defined my output should be like,
Compiling all C source files:
gcc copyfile.c -o copyfile
---- successful ----
gcc haserror.c -o haserror
haserror.c: In function ‘main’:
haserror.c:9:10: warning: missing terminating " character
printf("Hello !\n);
^
haserror.c:9:10: error: missing terminating " character
printf("Hello!\n);
^~~~~~~~~~~~~~~~~~~
haserror.c:11:1: error: expected expression before ‘}’ token
}
^
haserror.c:11:1: error: expected ‘;’ before ‘}’ token
gcc hello.c -o hello
---- successful ----
gcc p005.c -o p002
---- successful ----
gcc p103.c -o p101
---- successful ----
gcc p102.c -o p105
---- successful ----
============
5 C source files are compiled successfully.
1 C source files have compilation error(s).
**Otherwise, when my VERBOSE not defined, my output should be like**
Compiling all C source files:
haserror.c: In function ‘main’:
haserror.c:9:10: warning: missing terminating " character
printf("Hello!\n);
^
haserror.c:9:10: error: missing terminating " character
printf("Hello!\n);
^~~~~~~~~~~~~~~~~~~
haserror.c:11:1: error: expected expression before ‘}’ token
}
^
haserror.c:11:1: error: expected ‘;’ before ‘}’ token
============
5 C source files are compiled successfully.
1 C source files have compilation error(s).
The trivially obvious shoud work.
#!/bin/bash
[ "$VERBOSE" ] && echo "$0: Compile all C source files" >&2
for f in *.c; do
[ "$VERBOSE" ] && echo "$0: C file: $f" >&2
# [ "$VERBOSE" ] && set -x
gcc $f -o "${f%.*}"
# set +x
./"${f%.*}"
done
Notice also how we avoid the useless (and slightly dangerous) use of ls and print the diagnostic output to standard error, with the script's name included in the message.
The condition is simple; [ "$VERBOSE" ] evaluates to true (returns a zero exit code) when VERBOSE is set and non-empty. You can perform arbitrarily complex actions conditionally using the shell's normal flow control statements, such as perhaps
if [ "$VERBOSE" ]; then
echo "$0: compiling $f" >&2
(set -x; gcc "$f" -o "${f.c}") &&
echo "$0: ----- $f: successful -----" >&2
else
gcc "$f" -o "${f.c}"
fi
(though I would perhaps then also refactor the compilation command into a separate function.)
A better design is to have the script accept a command-line option. Also, you should probably avoid using upper case for your private variables.

Makefile - argument list too long, but only in some configurations

I'm trying to reproduce a situation which happens only in some machines. To reproduce it, I create a directory with 2000 files:
mkdir /tmp/test
cd /tmp/test
for f in $(seq 1 2000); do touch $f.txt; done
Then I use the following Makefile (simplified from the real use case):
FILES:=$(shell find . -name '*.txt')
%.done: %.txt
#echo "done $#"
toolong:
#$(foreach file,$(sort $(FILES)), \
if $(MAKE) $(file); \
then echo "did $(file)" >> $#; \
else echo "failed $(file)" >> $#; fi; )
Running make produces, unsurprisingly, an error:
make: execvp: /bin/sh: Argument list too long
This question presents a solution which does work. However, I need to understand exactly why this error does not happen on my colleagues' computers. I tried the following things:
Increasing stack limit (ulimit -s gives the same result on both machines, 8192, and increasing it does not change anything);
Checking getconf ARG_MAX (2097152 in both machines);
Checking MAX_ARG_STRLEN (131072 in both machines);
Using a different shell (zsh is being used in both machines; I also tried bash, dash and sh, via export SHELL=<shell> make, and also by replacing the symlink /bin/sh -> /bin/bash with a link to dash).
Finally, I tried recompiling Make from source, and realized that, even when I compile the same version of Make (4.1) in my Ubuntu test machine, I get the same behavior as I had in my Fedora, that is, the error "argument list too long".
make --version only shows a single difference between them:
Version from the apt package:
GNU Make 4.1
Built for x86_64-pc-linux-gnu
Version compiled from source (./configure && make):
GNU Make 4.1
Built for x86_64-unknown-linux-gnu
I even tried compiling make-dfsg, which results in an identical make --version, but the result is the same as with my other manually-compiled make.
By increasing the number of files on Ubuntu, I managed to identify that the actual limits in the size of the generated command line are:
Fedora or Arch Linux (both with Make 4.2.1), or Ubuntu with manually-compiled Make 4.1: 128 KB (~1200 files);
Debian Sid or Ubuntu, both with Make 4.1 installed from apt package: 2 MB (~19300 files).
I'd really like to understand (1) why this difference exists, and (2) how could I compile Make to obtain the higher limit, so that I can have the exact same behavior on both machines.
Your recipe expands as a one-line shell compound command (because of the line ending backslashes). And this line is probably way too long. Did you check what it looks like (the shell compound command) on all machines? I suggest that you wrap it in $(info...):
toolong:
#$(info $(foreach file,$(sort $(FILES)), \
if $(MAKE) $(file); \
then echo "did $(file)" >> $#; \
else echo "failed $(file)" >> $#; fi; ))
and see if the output is the same on your machine and on the others. If, for any reason, yours is longer, it could be the explanation. Else it must be a OS difference...
Note: you could have one rule per target, instead of one single rule with a huge recipe for all.
Note: your recipe (independently from its fantastic length) does nothing useful. As the files already exist and do not have pre-requisites, all your sub-make calls will just tell you that the files are up-to-date.

Chisel installation error

While following the tutorial on the Chisel official website for installation, I came to the point where I should test if the installation was done correctly. Doing so yields this error:
set -e -o pipefail; "sbt" -Dsbt.log.noformat=true -DchiselVersion="2.+" "run Parity --genHarness --compile --test --backend c --vcd --targetDir /home/me/chisel-tutorial/generated/examples " | tee /home/me/chisel-tutorial/generated/examples/Parity.out
/bin/bash: sbt: command not found
make: *** [/home/me/chisel-tutorial/generated/examples/Parity.out] Error 127
There is another question regarding the same problem here, where the suggestion to add SHELL=/bin/bash to the Makefile is made. That did not work for me. Another suggestion is to remove set -e -o pipefail: this suggestion actually works but is it OK to remove that option? what does it do?
Edit_1:
I have installed sbt and added its path to the PATH variable.
$ which sbt
/usr/bin/sbt
But still I am getting this error when running make Parity.out
set -e -o pipefail; "sbt" -Dsbt.log.noformat=true -DchiselVersion="2.+" "run Parity --genHarness --compile --test --backend c --vcd --targetDir /home/me/chisel-tutorial/generated/examples " | tee /home/me/chisel-tutorial/generated/examples/Parity.out
/bin/sh: 1: set: Illegal option -o pipefail
make: *** [/home/me/chisel-tutorial/generated/examples/Parity.out] Error 2
If I edit this part of the file suffix.mk:
$(objdir)/%.dot: %.scala
set -e -o pipefail; "$(SBT)" $(SBT_FLAGS) "run $(notdir $(basename $<)) --backend dot --targetDir $(objdir) $(CHISEL_FLAGS)"
$(objdir)/%.out: %.scala
set -e -o pipefail; "$(SBT)" $(SBT_FLAGS) "run $(notdir $(basename $<)) --genHarness --compile --test --backend c --vcd --targetDir $(objdir) $(CHISEL_FLAGS)" | tee $#
By deleting the -o option in the set -e -o pipefail it works, I get the PASSED and [success] message after running $ make Parity.out. So what is going on?
Edit_2:
It is working fine now after I added the SHELL=/bin/bash to the Makefile, so it was first a problem of not having sbt as Nathaniel pointed out then editing the Makefile to include SHELL=/bin/bash.
set -e -o pipefail is a way of making sure that the execution of the bash script both works as expected and that if there is a failure, it halts immediately (rather than at some later stage). Removing it might work - but if there is a failure it might get swallowed and hide the fact it's broken.
But I think your problem lies here, making the other question a bit of a red herring:
/bin/bash: sbt: command not found
Do you have sbt installed on your system? Run which sbt as the user that executes the script. For instance, on my system:
$ which sbt
/opt/local/bin/sbt
If you don't have it on your system, nothing will be returned by running which.
The script clearly needs access to sbt and is failing when it doesn't find it. If you do have it on your system, then there is a mismatch between the user running the script and access to that file. You'll need to post more information about how you're executing the script: in that case it is likely you'll have to update your PATH variables to be able to find the sbt executable.
Given that, after fixing this, you still have a problem, you have to ensure that you're running in bash, and not another terminal type. The reason for this is that bash supports set -o pipefail but a lot of other terminals don't. We suspect this might be the case because of the error messages:
/bin/sh: 1: set: Illegal option -o pipefail
Here we see that /bin/sh (the shell) is being invoked by the program. Use ls -l /bin/sh to determine if your /bin/sh is pointing to a particular shell. If it is not pointed to a bash shell, then you either need to repoint it (be careful! this is probably another question in it's own right), or need to specify to your Scala program to use a specific shell.

Resources