Control the output of subcalls to `make` - makefile

I have a Makefile where one of the goals looks as follows:
task: $(foreach t,$(SUBDIRS),subtask_$t)
subtask_%:
make -C $* subtask
In words, task runs the subtask goals defined in each Makefile found in the directories in the list $(SUBDIRS). By default, the output to the console is the combination of all outputs from the subtasks. Is there a way to simply output, e.g. $* SUCCESS or $* FAILED depending on the exit code?
I have tried using #make..., but this doesn't mask the output of the commands run from the other Makefiles.
Ideally, I would like to keep the sub-Makefiles unchanges, as I still occasionally want to use them directly and get the full output.

One possible way would be to get each subtask make write it's output to it's own log file. As in:
subtask_%:
make -C $* subtask 2>&1 > subtask/make.log

Related

Problem executing Makefile for FPGA poject-Vivado

Hi I am new to creating makefile.
I have written the following commands in a makefile but they do not seem to execute when i type make in my terminal.
However, if i type the command separately in the terminal, it works.
I am trying to open a vivado project in this tcl file and do some spyglass analysis on it and save the result in a txt file.The tcl file also runs properly if executed separately.
I cd to my project folder where all the files- sources folder, project folder, makefile is present. I named it "makefile" so that i can execute it by typing make in the terminal.The makefile contents are as follows.
.PHONY : vivado_open
vivado_open:
$(info Hello Make)
bsub -Is -q i_soc_rh7 -R "rusage[mem=32000, temp=1GB] affinity[core(8):membind=localonly]" vivado -nolog -nojou -mode batch -source vivado.tcl
Here is the result from the terminal
$make
Hello Make
make: Nothing to be done for `vivado_open'.
Sorry, but there has to be something else going on here, that you haven't told us about. It's simply not possible for you to get that output if you typed make with that makefile.
You are using a variable, not a target named vivado_open, so make would never print nothing to be done for 'vivado_open'. It would say instead something like: nothing to be done for ../projectfiles/test.prj
Further, you didn't answer my question about TABs vs. spaces. If both the info and bsub lines are indented with TABs, there's no possible way that make would print Hello Make, without also printing the bsub command and trying to run it.
You must have another makefile in your directory, maybe named Makefile or GNUmakefile, that is being used instead of makefile. Or maybe you have an environment variable like MAKEFILES set which is causing other makefiles to be read.
If none of those appear to be true, you'll have to run make -d and see if you can figure out what's happening. That output is far too large to post to StackOverflow, so you'll have to try to read it yourself.
EDITED
OK, the problem is you're using spaces to indent your rules. In make, all recipe lines must be indented with a hard TAB character. Normal spaces don't mean anything special to make. Basically your makefile is interpreted as if you'd written this:
.PHONY : vivado_open
vivado_open:
$(info Hello Make)
bsub -Is -q i_soc_rh7 -R "rusage[mem=32000, temp=1GB] affinity[core(8):membind=localonly]" vivado -nolog -nojou -mode batch -source vivado.tcl
This is why you get this message "nothing to be done": you haven't actually defined a recipe for vivaldo_open, so there is literally nothing that make knows to do to update that target.
As an aside, normally you would get a syntax error for the bsub line because make doesn't know what that is. However, if you look carefully at your line you'll see that it contains a :. So, make is interpreting this as a set of targets and set of prerequisites, like this:
bsub ... affinity[core(8) : membind=localonly]" vivado ... vivado.tcl
(make doesn't care about quotes or other special characters like [] etc.)
So. Be sure you indent your recipe lines with TAB characters and you'll be fine. This is probably the single most common issue people have with makefiles.

How make can restore state after failure

Considering the following:
all:
mv info.h info.h.back
generate_info.sh
compile
mv info.h.back info.h
How do I force make to run the last line even if compilation failed?
I am aware of .DELETE_ON_ERROR but this deals only with removing targets on failure.
I am also aware of the option to add - before the compile command. Unfortunately this will make the whole make to return with a good error code, which is unacceptable.
You can't force make to do this. You'll have to arrange for it to be done in your shell script, yourself. Make will send every "logical line" of the shell script to the same shell command. Turn multiple physical lines into one logical line by appending backslashes to the end of the physical lines.
So, for example:
all:
mv info.h info.h.back
generate_info.sh && compile; \
r=$$?; mv info.h.back info.h; \
exit $$r
This saves the return code of the two commands in the shell variable r, then runs the mv command, then exits the shell with the result code that was saved.
The generate_info.sh && compile means that the second command (compile) will only run if the first command (generate_info.sh) succeeds.

Why does make utility fail to delete a file associated with an incomplete task when issuing qdel command on SGE?

I have a bash script which runs a make command on a Sun Grid Engine HPC:
#submitscript.sh
module load program1 program2
set -a
make
This bash script runs a makefile which looks like:
# makefile
SHELL := /bin/bash
all: Variants.vcf Variants1.vcf
Variants.vcf:
program1 inputfile > Variants.vcf
Variants1.vcf:
program2 inputfile2 > Variants1.vcf
I submit the script on the HPC by issuing:
qsub submitscript.sh
When I issue qdel to delete the task the file that is currently being written to is not deleted by make. I would have thought that the qdel command would result in the makefile exiting and deleting any target files not completely written. Can anybody explain what is happening here?
Update
Thank you. I realise my mistake now. Qdel is killing the entire job so as you both say make is not being allowed to clean up. When I added the line to the makefile:
.DELETE_ON_ERROR: *.vcf
and then put a wrong file path into the program2 line eg.
Variants1.vcf:
program2 inputfile2 > /wrong/file/path/Variants1.vcf
the desired behaviour was shown with the partially written file being deleted on exit.
From the Comments:
If you kill make how can it then do the cleanup? If you killed program1 or program2 it could have a chance. – user2672165
Response:
I realise my mistake now. Qdel is killing the entire job so as you both say make is not being allowed to clean up. – user1977981
I'm answering this so other users with the same problem can easily determine the answer that was provided.

Help with aliases in shell scripts

I have the following code, which is intended to run a java program on some input, and test that input against a results file for verification.
#!/bin/bash
java Program ../tests/test"$#".tst > test"$#".asm
spim -f test"$#".asm > temp
diff temp ../results/test"$#".out
The gist of the above code is to:
Run Program on a test file in another directory, and pipe the output into an assembly file.
Run a MIPS processor on that program's output, piping that into a file called temp.
Run diff on the output I generated and some expected output.
I made this shell script to help me automate checking of my homework assignment for class. I didn't feel like manually checking things anymore.
I must be doing something wrong, as although this program works with one argument, it fails with more than one. The output I get if I use the $# is:
./test.sh: line 2: test"$#".asm: ambiguous redirect
Cannot open file: `test0'
EDIT:
Ah, I figured it out. This code fixed the problem:
#!/bin/bash
for arg in $#
do
java Parser ../tests/test"$arg".tst > test"$arg".asm
spim -f test"$arg".asm > temp
diff temp ../results/test"$arg".out
done
It turns out that bash must have interpreted a different cmd arg for each time I was invoking $#.
enter code here
If you provide multiple command-line arguments, then clearly $# will expand to a list of multiple arguments, which means that all your commands will be nonsense.
What do you expect to happen for multiple arguments?

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