How to run command and checking exit status from windows make files - windows

I am new to windows make files.I am trying to understand a few things. How to run commands (DOS commands) from windows mk files. I ran the following command from cmd command prompt--
find testsuite
and it gives proper output. Now I try to run the same from windows mk file as follows -- $(shell find testsuite). However, it gives error "FIND: Parameter format not correct". Is $(shell commandname ...) the correct way or if not what does $(shell...) indicate? Also how to capture the exit status of the command.Adding logline like below after the command doesn't print anything $(warning $(errorlevel)

However, it gives error "FIND: Parameter format not correct".
This is Windows own find utility. It searches for strings in files, kind of grep without regexp :-(. So it requires at least two arguments.
Also how to capture the exit status of the command.
For $(shell ...) function it's in .SHELLSTATUS variable.

Related

Run a command in a makefile and print STDERR / STDOUT to both the terminal and a text file

First off, I'm using GNU Make 4.3 on Windows 10. I previously tried GNU Make 4.2.1, which gave me the exact same results as 4.3.
Anyway, I have a very simple makefile that does (or at least is intended to do) nothing more than run a simple command and print the output of that command (both stderr and stdout) to the terminal and to a text file.
$(info $$(MAKECMDGOALS) is "$(MAKECMDGOALS)". $$(SHELL) is \
"$(SHELL)". $$(MAKESHELL) is "$(MAKESHELL)". $$(COMSPEC) is "$(COMSPEC)". $$(OS) is "$(OS)".)
TEE := C:\tools\UnixTools\usr\local\wbin\tee.exe
LOG_FILE := C:\Temp\loggy__.txt
.PHONY : meep
all : meep
meep :
$(info Making meep.)
$(info Running command {dir 2>&1 | $(TEE) $(LOG_FILE)}.)
$(shell dir 2>&1 | $(TEE) $(LOG_FILE))
The last line is the one that is giving me trouble. Two things are happening that run counter to my expectations:
While the $(shell ...) call does print the output of the dir command both to my text file and the terminal, the output on the terminal is weirdly formatted. Where normally, dir prints one element per line, here I'm getting the entire output in one line, so it seems like GNU Make (or something else) somehow removes the newline characters from the output before it is shown in the terminal window.
In addition, I'm getting a The system cannot find the file specified. error message (and as usual, Windows is not nice enough to tell me which file it is that it cannot find). Running an echo %errorlevel% in the same CMD shell in which I ran GNU Make confirms that the Make call errored out (exit status is 2).
Weirdly enough, if I run the command dir 2>&1 | C:\tools\UnixTools\usr\local\wbin\tee.exe C:\Temp\loggy__.txt directly in the CMD window, everything works exactly as one would expect, without any errors whatsoever, so I'm thinking there's either something wrong with GNU Make's $(shell ...) function, or I'm using it wrong. Does anyone spot something silly in how I'm trying to use the $(shell ...) function?
I just added --debug=a to my make call to get extra debug output, and I found the following in the output:
Creating temporary batch file C:\Users\mkemp\AppData\Local\Temp\make23400-1.bat
Batch file contents:
#echo off
dir 2>&1 | C:\tools\UnixTools\usr\local\wbin\tee.exe C:\Temp\loggy__.txt
CreateProcess(C:\Users\mkemp\AppData\Local\Temp\make23400-1.bat,C:\Users\mkemp\AppData\Local\Temp\make23400-1.bat,...)
Main thread handle = 00000000000000B4
Cleaning up temporary batch file C:\Users\mkemp\AppData\Local\Temp\make23400-1.bat
Creating temporary batch file C:\Users\mkemp\AppData\Local\Temp\make23400-2.bat
Batch file contents:
#echo off
Volume in drive C is Windows Volume Serial Number is 045A-E422 Directory of C:\tools\UnixTools\usr\local\wbin (... the rest of the output)
CreateProcess(C:\Users\mkemp\AppData\Local\Temp\make23400-2.bat,C:\Users\mkemp\AppData\Local\Temp\make23400-2.bat,...)
So it appears that GNU Make's $(shell ...) function somehow interprets the output produced by the dir call as an additional command it needs to run, which is nonsense, of course.
Using $(shell) is nonsense here. make is acting exactly like you instructed it.
The proper solution is to not add the $(shell ...) function call where it makes no sense.
meep :
$(info Making meep.)
$(info Running command {dir 2>&1 | $(TEE) $(LOG_FILE)}.)
dir 2>&1 | $(TEE) $(LOG_FILE)
Of course, using $(info ...) in a recipe is probably bogus. Inside each recipe, you are running the shell; use the shell's syntax to print diagnostic messages.
meep:
#echo Making meep. >&2
#echo Running command '{dir 2>&1 | $(TEE) $(LOG_FILE)}.' >&2
dir 2>&1 | $(TEE) $(LOG_FILE)
Better yet, don't run make -s and let make itself print what commands it is running, as it does by default (if you don't sprinkle your Makefile with # before all commands to make it harder to debug).

Syntax for executing a script using Git Bash on Windows 10 pro/docker/ddev

I am executing the following command:
wget -O -https://raw.githubusercontent.com/drud/ddev/master/scripts/windows_ddev_nfs_setup.sh | bash
And I get the following:
wget: missing URL
Usage: wget [OPTION]... [URL]...
Looks as if I have the syntax wrong, but I have been searching to find out how to fix this and haven't found an answer.
I checked the command on shellcheck.net and learned the following:
SC2148: Tips depend on target shell and yours is unknown. Add a shebang.
That sounds great, but I don't (yet) know what it means.
You are using -O, which means that the next argument is the output file. Hence,
-https://raw.githubusercontent.com/drud/ddev/master/scripts/windows_ddev_nfs_setup.sh
is the name of your output file, and there is no URL in your command.
Since you are piping the result of wget into bash, you don't need an output file, I think.

fastest command, which accepts pipe, but generates no text on StdOut & StdErr

Which command in Windows command script (.cmd) accepts pipe (so, no error "The Process tried to write to a nonexistent pipe." generated), but generates no output itself, including output to StdErr? I need to not touch normal StdErr output (keep in mind, pipe transports only StdOut). I can't use null device, due to it's not installed in the system.
For example, command|rem generates mentioned error. But I want no error output, except generated by command, so rem is not suitable command for needed purpose.
Main aim is the script speed. So, don't offer extensive constructions, please.
should be break(or set/p= ?) as it is internal command prompt command (i.e. no external process started ) and generally do nothing.Though I suppose if you are searching for executable packed with the windows answer will be different.
The cd . command is what you are looking for. I used it to create empty files. This way, command | cd . works and echo Hello >&2 | cd . show "Hello" in the screen! This works as a filter that just blocks Stdout (interesting).

Get predefined macros from GCC without temporary files

Is there a way to retrieve predefined macros from the GCC preprocessor without having to use temporary files (e.g. using pipes)?
There is a similar question here on StackOverflow, but all its answers make use of the command line, while I need to read mentioned data from within a process.
GCC dump preprocessor defines
Google basically returns a lot of answers to the command line version of the question.
When I try to perform the command line trick of directing output to /dev/null on Linux or NUL on Windows using pipes:
RunAndGetOutput("cpp -dM -E < NUL");
... an error occurs:
cpp.exe: error: <: Invalid argument
cpp.exe: warning: '-x c' last input file has no effect
cpp.exe: fatal error: no input files
compilation terminated.
When I execute the same command from the command line all is fine, and a list of defines it printed.
Is there any way I can fix this problem?
I'm not sure exactly sure how NUL behaves under windows, but I assume it is similar to /dev/null in Unix/Linux: /dev/null in Windows?
On my Ubuntu VM I can do:
cpp -dM -E -xc /dev/null
So I assume under windows you could do something like:
cpp -dM -E -xc NUL
This assumes NUL behaves essentially like an empty file. If the output from type NUL is any indicator here, then this is hopefully the case.
Alternatively, if this doesn't work, you could do the cpp command with redirection within a cmd.exe subshell:
cmd.exe /C "cpp -dM -E < NUL"
From the point of view of RunAndGetOutput(), this is just a single cmd.exe command with a few params passed, and no pipes/redirections. But the cmd.exe shell will interpret the passed string as a command, and importantly will understand how to handle the < redirection correctly.
Since you're calling the cpp preprocessor directly, the -E and -xc options are unnecessary (at least this is the case in Linux), but leaving them there won't do any harm.

How to make a failing $(shell) command interrupt Make

I have a Makefile that starts by running a tool before applying the build rules (which this tool writes for me). If this tool, which is a python script, exits with a non-null status code, I want GNU Make to stop right there and not go on with building the program.
Currently, I do something like this (top level, i.e. column 1):
$(info Generating build rules...)
$(shell python collect_sources.py)
include BuildRules.mk
But this does not stop make if collect_sources.py exits with a status code of 1. This also captures the standard output of collect_sources.py but does not print it out, so I have the feeling I'm looking in the wrong direction.
If at all possible, the solution should even work when a simple MS-DOS shell is the standard system shell.
Any suggestion?
There might be a better way, but I tried the following and it works:
$(if $(shell if your_command; then echo ok; fi), , $(error your_command failed))
Here I did assume that your_command does not give any output, but it shouldn't be hard to work around such a situation.
Edit: To make it work with the default Windows shell (and probably any decent shell) you could write your_command && echo ok instead of the if within the shell function. I do not think this is possible for (older) DOS shells. For these you probably want to adapt your_command or write a wrapper script to print something on error (or success).
Ok, here's my own solution, which is unfortunately not based on the status code of the collect_sources.py script, but which Works For Me (TM) and lets me see any output that the script produces:
SHELL_OUTPUT := $(shell python collect_sources.py 2>&1)
ifeq ($(filter error: [Errno %],$(SHELL_OUTPUT)),)
$(info $(SHELL_OUTPUT))
else
$(error $(SHELL_OUTPUT))
endif
The script is written so that any error produces an output beginning with "collect_sources: error:". Additionally, if python cannot find or execute the given script, it outputs an error message containing the message "[Errno 2]" or similar. So this little piece of code just captures the output (redirecting stderr to stdout) and searches for error messages. If none is found, it simply uses $(info) to print the output, otherwise it uses $(error), which effectively makes Make stop.
Note that the indentation in the ifeq ... endif is done with spaces. If tabs are used, Make thinks you're trying to invoke a command and complains about it.
You should use a regular target to create BuildRules.mk:
BuildRules.mk: collect_sources.py
python $< >$#
include BuildRules.mk
This is the standard trick to use when automatically generating dependencies.
Fixing https://stackoverflow.com/a/226974/192373
.PHONY: BuildRules.mk
BuildRules.mk: collect_sources.py
echo Generating build rules...)
python $< >$#
$(MAKE) -f BuildRules.mk
Make sure you're not invoking make/gmake with the -k option.

Resources