The follow makefile is created for generate the difference from two files,
file1 and file2:
.PHONY: patch
patch:
diff file1 file2 > file12.patch
The content of file1:
xxx
and file2:
xxx
yyy
But when I issued make patch, error comes:
diff file1 file2 > file12.patch
Makefile:3: recipe for target 'patch' failed
make: *** [patch] Error 1
However, patch could be generated in terminal by:
diff file1 file2 > file12.patch.
Content of file12.patch:
1a2
> yyy
Surprisingly, I went back to check the folder, the make patch did produce the right patch file.
What I cannot understand is the make error? e.g. This error certainly will stop the make process, skip all the commands afterward.
Could someone explain this make behavior? Thank you!
Your quoted makefile above cannot be create: recipes for .PHONY targets are ignored. It must be something like:
.PHONY: patch
patch:
diff file1 file2 > file12.patch
Make determines that a command succeeded or failed by looking at its exit code. If the exit code is 0 then make assumes the command succeeded. If it's non-0 make assumes it failed.
The error you're seeing implies that the diff command exited with a non-0 exit code.
The manual for diff says:
An exit status of 0 means no differences were found, 1 means some
differences were found, and 2 means trouble.
So, since your diff does find some differences it exits with a code of 1, which make interprets as failing. You'll probably want to change your recipe to something like:
.PHONY: patch
patch:
diff file1 file2 > file12.patch || [ $? -eq 1 ]
so if the diff fails you further check to see if the exit code was 2 or not.
Related
When I execute Make, I'd like to know what shell commands / recipes are executed (and perhaps which line in which Makefile invoked these). Is there a way of doing this (print onto the stdout or write to a file) without modifying the Makefiles?
The commands will be echoed to stdout by default, unless you disabled that by prefixing them with #.
A few options you can pass to make:
-n: echos commands that would be run, but without running them. This will also echo commands that are prefixed with #.
-d: print debug output. This will output the process that make goes through in attempting to find rules that match the targets that it's trying to make. There will be a lot of useless information in here, as it will try many default build rules (like how to build .o files from .c).
There are a few ways to cut down on the noise:
-r: disable implicit rules. If you don't depend on any of the default rules , this can be used in conjunction with -d to just print the parts you (mostly) care about
--debug=b: basic debug mode. prints what it's trying to make, but not any information about implicit rules.
None of these print the line numbers of the commands, but make -n --debug=b will print both the targets being built and the commands being run, so it's almost as good. Example below.
$ cat makefile:
c: a b
cat $^ > $#
a:
echo 'foo' > $#
b: a
cat $^ > $#
echo 'bar' >> $#
$ make -n --debug=b:
Reading makefiles...
Updating goal targets....
File 'a' does not exist.
Must remake target 'a'.
echo 'foo' > a
Successfully remade target file 'a'.
File 'b' does not exist.
Must remake target 'b'.
cat a > b
echo 'bar' >> b
Successfully remade target file 'b'.
Prerequisite 'a' is newer than target 'c'.
Prerequisite 'b' is newer than target 'c'.
Must remake target 'c'.
cat a b > c
Successfully remade target file 'c'.
I want to pass some recipes to a makefile, like comp1.mt comp2.mt comp3.mt and have the makefile agregate them into a single list of MTs (it could also be mt.compN) to run them in bulk.
%.mt:
#echo $* >> list_of_mts.txt
mt: %.mt
#cat list_of_mts.txt
I want to pass these recipes in any order to the makefile so the specific case of calling make comp1.mt comp2.mt mt is not desirable.
I do not understand why you need this implemented in makefile, but here you are:
MT_TARGETS:=$(filter %.mt,$(MAKECMDGOALS))
.PHONY: $(MT_TARGETS)
$(MT_TARGETS):
#echo $# | sed -e "s:.mt$$::" >> list_of_mts.txt
mt: $(MT_TARGETS)
#cat list_of_mts.txt
Testing:
$ make mt comp1.mt comp2.mt comp3.mt
comp1
comp2
comp3
make: `comp1.mt' is up to date.
make: `comp2.mt' is up to date.
make: `comp3.mt' is up to date.
This is using special variable MAKECMDGOALS.
Note: list_of_mts.txt will grow endlessly...
Note2: writing to list_of_mts.txt is unsafe in parallel execution (the list_of_mts.txt file may get corrupted).
Using GNU Make 4.1, in my Makefile I can create a timestamp log file with this::
flush_log:
#echo "==> flush logs"
cat file > file_`date +%FT%T%Z`.log
But who to put:
file_`date +%FT%T%Z`.log
in a var inside the Makefile e.g to make a wc on it ?
I've try (with no success):
flush_log:
#echo "==> flush logs"
logfile:=file_$(shell date +%FT%T%Z).log
cat my_log > $(logfile)
echo `wc -l $(logfile)`
I get this error:
$ make flush_log
==> flush logs
logfile:=file_2016-12-24T20:09:52CET.log
/bin/sh: 1: logfile:=file_2016-12-24T20:09:52CET.log: not found
Makefile:7: recipe for target 'flush_log' failed
make: *** [flush_log] Error 127
$
I was following recommendation from https://stackoverflow.com/a/14939434/3313834 and Simply expanded variables https://www.gnu.org/software/make/manual/html_node/Flavors.html#Flavors
Every line in a makefile (that appears after a rule statement) that is indented with a TAB character is part of the rule's recipe. Lines in the rule's recipe are passed to the shell for handling, they're not parsed by make (except to expand variable/function references).
So your line logfile:=file... is being passed to the shell and being interpreted by the shell... and there is no valid := operator in the shell, so the shell thinks that entire line is a single word and tries to run a program with that name, which obviously doesn't exist.
You probably want to create a make variable, which must be done outside of the recipe, like this:
logfile := file_$(shell date +%FT%T%Z).log
flush_log:
#echo "==> flush logs"
cat my_log > $(logfile)
echo `wc -l $(logfile)`
I was thinking about using Make for small checks for my dev setup. One thing I want is to check that a particular string exists in a file before doing some action. If I wanted to create the entire file it would be trivial
action: filename
...
filename:
echo 'blah' >> filename
But how can this logic be applied to actions, like grep? My dependency isn't that a file exists, it's that the file has correct content.
I'm asking specifically about Make and not other solutions like chef/puppet
You can run any shell commands you want in a make recipe. As many of them as you want also.
So if you need to run grep before doing something else just do that.
Just remember that every line in a recipe is run in its own shell session so they don't share state.
So this:
action: filename
...
filename:
grep -qw blah $# || echo 'blah' > $#
runs grep on filename (via the automatic variable for the current target $#) looking for whole words and quitting on the first match (-q).
If grep finds blah then it will return success and the || will short-circuit and the recipe is done. If grep fails then the || will trigger and the echo will run.
You might be tempted to do things that require the inverse logic do X only if Y is true:
filename:
grep -qw blah $# && echo blah2 > $#
but that doesn't work correctly. When grep fails the && short-circuits and make sees a recipe failure and bails the make process out with an error.
You need this instead.
filename:
! grep -qw blah $# || echo blah2 > $#
to invert the logic and ensure that the "failure" from grep is seen as success as far as make is concerned.
That all being said in this specific example if filename exists at all then that recipe won't ever run as it has no prerequisites so make will always consider it up to date. To work around that you need to give the file a prerequisite that will force it to be considered out of date. Specifically a force target.
Don't follow the advice about .PHONY for this case though. .PHONY targets should never be prerequisites of non-.PHONY targets.
Expanding on what #john wrote I got the following to work:
TEST_FILE=filename
.PHONY: ${TEST_FILE}
string=testing
filecheck=$(shell grep -qw ${string} ${TEST_FILE} || echo ${TEST_FILE})
all: ${filecheck}
${TEST_FILE}:
echo 'changing the file'
echo ${string} >> ${TEST_FILE}
Here the file on which I'm operating is a .PHONY target. I think that's ok because I'm actually not creating the file, just modifying it. This will work if the file does not exist, or exists without the needed string.
You could add a test in the target's recipe (As Etan posted before I could complete this answer...). If you do want to do this using just make logic, you could do something along the lines of:
actions: $(if $(shell grep -q $$string filename && echo y),filename,)
filename:
echo blah >> $#
If filename contains the string, then there will be an actions: filename dependency, and filename will be built when you build actions. Notice, though that this will check whether the string exists in filename at the time the makefile is parsed -- if filename is generated, or modified in this makefile, then it would not effect whether the action is run. If you want to test right before overwriting the file, then you would use a bash if statement in the recipe itself.
How does GNU make decide which of the messages to emit? The Makefile I am using causes Nothing to be done for 'target' messages to be emitted when the target is up do date. But I think 'target' is up to date would be more appropriate.
The chief difference is in whether gmake has a rule to build the target or not. If there is no rule for the target, but the target exists, then gmake will say, "Nothing to be done", as in, "I don't know how to update this thing, but it already exists, so I guess there's nothing to be done." If there is a rule, but the target is already up-to-date, then gmake will say, "is up to date", as in, "I do have instructions for updating this thing, but it appears to already be up-to-date, so I'm not going to do anything."
Here's a concrete example:
$ echo "upToDate: older ; #echo done" > Makefile
$ touch older ; sleep 2 ; touch upToDate ; touch nothingToDo
$ ls --full-time -l older upToDate nothingToDo
-rw-r--r-- 1 ericm ericm 0 2011-04-20 11:13:04.970243002 -0700 nothingToDo
-rw-r--r-- 1 ericm ericm 0 2011-04-20 11:13:02.960243003 -0700 older
-rw-r--r-- 1 ericm ericm 0 2011-04-20 11:13:04.960243001 -0700 upToDate
$ gmake upToDate
gmake: `upToDate' is up to date.
$ gmake nothingToDo
gmake: Nothing to be done for `nothingToDo'.
Since gmake has no rule for "nothingToDo", but the file already exists, you get the "nothing to be done" message. If "nothingToDo" did not exist, you would instead get the familiar, "No rule to make" message.
In contrast, because gmake has a rule for "upToDate", and the file appears to be up-to-date, you get the "is up to date" message.
I research this problem, and test a lot of scenes, the result I got is:
If the target has no recipe and if no any prerequisites' recipes are executed, then Nothing to be done for "top target" will printed
If the target has recipe, but the recipe is not executed, then is up to date is printed.
If no rules for a existing file, and make that existing file as target also print Nothing to be done for "xxx"