how to stop make -n from echoing same command multiple times - makefile

I am using GNU make and have a Makefile which looks like this:
AB = A.txt B.txt
${AB}: makeAB.py
python makeAB.py
C.txt: ${AB} makeC.py
python makeC.py
When I type make -n C.txt, assuming makeAB.py needs to run, I get the output:
python makeAB.py
python makeAB.py
python makeC.py
Is there any way to write the Makefile so that the line python makeAB.py is not repeated? This is just a toy example, but in my actual application AB consists of many files, so I potentially get a whole screen of unnecessary output.
p.s. When called without -n, make (sensibly) only runs python makeAB.py once. So my problem is just with make -n.

The double output arises because the recipe is scheduled to run twice, once to build A.txt and again to build B.txt. This is normal behavior for make. In particular a rule such as your (as expanded) ...
A.txt B.txt: makeAB.py
python makeAB.py
... means that each of those two targets can be built via the associated recipe, not that a single execution of the recipe builds both (regardless of whether a single run does build both). It is 100% equivalent to:
A.txt: makeAB.py
python makeAB.py
B.txt: makeAB.py
python makeAB.py
When called without -n, make (sensibly) only runs python makeAB.py once. So my problem is just with make -n.
When you run with -n, make does not execute the recipe, so it cannot evaluate whether doing so to update (say) A.txt might also update B.txt. All it knows is that both targets are out of date, so it outputs the recipes that would be executed to update each one. This is completely sensible.
When you run make without -n, it has the opportunity to to observe that after updating one of A.txt and B.txt, the other is up to date. It might very naturally not even have noticed that the other was initially out of date. Having observed this, of course it does not execute the recipe again. The output would be clearer about what was happening if the recipe executions expressed which target was being built. For example, try this variation on the rule, which is more like how a multiple-target rule would ordinarily be written.
A.txt B.txt: makeAB.py
python makeAB.py $#
So, both make outputs are right in their own ways. Arguably, however, the makefile is wrong, because it does not capture the expectation and fact that running the recipe once would generate both outputs. This is a situation that the makefile language traditionally has difficulty expressing, and you will find other question about that here on SO and elsewhere.
If you are using a new enough version of GNU Make, then you can make use of its concept of "grouped target" rules, which addresses exactly this issue. By using &: as the separator in the first line of the rule, you communicate (only to pretty recent versions of GNU Make) that one execution of the rule creates all the designated targets. Example:
A.txt B.txt &: makeAB.py
python makeAB.py
Traditional makes and older GNU Make will just interpret the & as another target name. That means that those makes will accept such makefiles, but not behave the same as recent GNU make. Among other things, it means that if asked to build target &, they would try to do so, quite possibly with a surprising effect owing to the special significance of & to the shell.

Related

Makefile execution properly [duplicate]

I tried to use a make file in code::blocks but I am doing it wrong. I have the version installed with the compilers included. http://sourceforge.net/projects/codeblocks/files/Binaries/10.05/Windows/codeblocks-10.05mingw-setup.exe/download. What do I do with the make file? It starts with:
CC=gcc
best, US
You don't tend to execute the make file itself, rather you execute make, giving it the make file as an argument:
make -f pax.mk
If your make file is actually one of the standard names (like makefile or Makefile), you don't even need to specify it. It'll be picked up by default (if you have more than one of these standard names in your build directory, you better look up the make man page to see which takes precedence).
As paxdiablo said make -f pax.mk would execute the pax.mk makefile, if you directly execute it by typing ./pax.mk, then you would get syntax error.
Also you can just type make if your file name is makefile/Makefile.
Suppose you have two files named makefile and Makefile in the same directory then makefile is executed if make alone is given. You can even pass arguments to makefile.
Check out more about makefile at this Tutorial : Basic understanding of Makefile

How to view commands that `make` executes?

I have a Makefile, which fails at some point, with a git error. How can I view the git command that causes the whole make process to fail? More precisely, I am looking for a list of commands (including the ones that start with #) that I can run on an identical setup, to achieve the same effect as what make does.
I know for a script, instead of #! /bin/bash you would add a flag -x to it, and that would display all the commands before their execution. How do I do the same thing for make?
I am looking for a list of commands (including the ones that start with #) that I can run on an identical setup, to achieve the same effect as what make does.
By default, make echoes all recipe commands it runs, except those prefixed with #. The POSIX specifications for make do not describe a way to override that effect of # (but see below). It is conceivable that your make has an extension for that, but the make implementations you are most likely to be using (GNU make or BSD make, since you seem to assume that your standard shell is bash) do not.
Additionally, in POSIX-conforming make implementations, including the two mentioned above, the special target .SILENT can be used to suppress echoing the commands of some or all targets, and the -s command-line option can be used to suppress echoing for all targets.
You can print recipe commands prefixed with # if you run make with the -n (no-op) flag. That will print the commands for out-of-date targets without running them, except that those prefixed with a + are run even in no-op mode. Commands prefixed with # are included among those printed. Under some circumstances, the fact that most commands are not actually run in this mode can affect the output, but all the cases I can think of at the moment involve recursive make, and I think they are fairly unlikely.
POSIX seems to indicate that -n does not override -s or .SILENT, so if you have to deal with those then you may have no alternative but to modify your makefile. If you happen to be using GNU make, however, you will find that -n does override .SILENT and -s in that implementation. The same may be true of other makes.

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.

Force run a recipe (--assume-old=target)

I want to force a recipe for "output.file", even though it is up-to-date.
I have already tried make --assume-old=output.file output.file, but it does not run the recipe again.
In case you are curious: use case:
I want to use this together with --dry-run to find out the command that produce a target.
I ended up hiding the file to run make --dry-run output.file, but I was hoping for something more elegant + FMI: for future debugging makefile.
I think you're misunderstanding what that option does: it does exactly the opposite of what you hoped; from the man page:
-o file, --old-file=file, --assume-old=file
Do not remake the file file even if it is older than its dependenā€
cies, and do not remake anything on account of changes in file.
Essentially the file is treated as very old and its rules are
ignored.
You want output.file to be remade, so using -o is clearly not what you want.
There is no option in GNU make to say "always rebuild this target". What you can do is tell make to pretend that some prerequisite of the target you want to be rebuilt has been updated. See this option:
-W file, --what-if=file, --new-file=file, --assume-new=file
Pretend that the target file has just been modified. When used
with the -n flag, this shows you what would happen if you were to
modify that file. Without -n, it is almost the same as running a
touch command on the given file before running make, except that
the modification time is changed only in the imagination of make.
Say for example your output.file had a prerequisite input.file. Then if you run:
make -W input.file
it will show you what rules it would run, which would include rebuilding output.file.

Some Basic Questions about Make: Compiling a Report with Figures

I'm trying to get Make working for recompiling reports every time a figure gets updated. I have the following code:
fig1.eps : images/code/fig1.m
matlab -nodesktop -nosplash -r 'run ./images/code/fig1.m'
How do I match on all figures -- like fig*.eps. I want to check all figures and update those that are not up to date.
When I run the command above, it continually reruns. This is to say: fig1.eps is generated. After I run make again, it should give me a message "fig1.eps is up to date." But it doesn't, the script reruns. Why is it doing this?
How do I match on all figures -- like fig*.eps. I want to check all figures and update those that are not up to date.
If you are using GNU's implementation of make, then you can use a pattern rule:
fig%.eps : images/code/fig%.m
matlab -nodesktop -nosplash -r 'run ./$<'
If you are using another version of make then the best you can do without writing a separate rule for each figure is probably to write a suffix rule, which will generate files in the same directory as the corresponding Matlab script, something like:
.m.eps :
matlab -nodesktop -nosplash -r 'run ./$<'
.SUFFIXES: .m .eps
Either of these options, however, requires you to somewhere specify all the figures to be created. At its simplest, you would just enumerate:
FIGS = fig1.eps fig2.eps fig5a.eps fig17.1.eps
... and specify the figures as prerequisites for the default (or some other) target:
all: $(FIGS)
With GNU make, however, if your Matlab files are arranged and named conducively then you could also use wildcard expansion or a shell command to obtain the result:
FIGS = $(shell cd images/code && ls fig*.m | sed 's/\.m$$/.eps')
When I run the command above, it continually reruns. This is to say: fig1.eps is generated. After I run make again, it should give me
a message "fig1.eps is up to date." But it doesn't, the script reruns.
Why is it doing this?
Very likely because your matlab command is not producing the target of the rule. For example, maybe it is creating a file of the same name, but in a different directory, or maybe it is not writing its output to a file at all. Possibly because some other rule is also being triggered that causes the .eps file to be removed.

Resources