when I use a makefile I often see in my output make[1]... make[2] ...
for example :
make all-recursive
make[1]: Entering directory `./splint-3.1.2'
Making all in src
make[2]: Entering directory `./src'
grep "FLG_" flags.def > Headers/flag_codes.gen
make
make[3]: Entering directory `.splint-3.1.2/src'
what the [n] in the make[n] means ?
The comments are correct - [n] refers to the level of recursion. At this point I wanted to point to the relevant documentation, but my scan through the GNU make documentation turned up nothing in this regard - perhaps I'm missing something.
Failing that, we can turn to the source code. [n] is the int makelevel variable in main.c. This corresponds to the MAKELEVEL automatic make variable:
As a special feature, the variable MAKELEVEL is changed when it is passed down from level to level. This variable's value is a string which is the depth of the level as a decimal number. The value is ‘0’ for the top-level make; ‘1’ for a sub-make, ‘2’ for a sub-sub-make, and so on. The incrementation happens when make sets up the environment for a recipe
Related
Question:
How can I disable implicit rule searches on a prerequisite while still ensuring that the prerequisite actually exists?
Background:
Consider the following initial Makefile:
b: a
#echo MAKING B
cp a b
a is a file which is required in order to make b. If the file a exists, make b runs successfully. If it doesn't exist, we obtain the following error:
make: *** No rule to make target `a', needed by `b'. Stop.`
This is exactly what we expected, however on inspecting the output of make --debug=a b, we see that even when a exists, make is searching through pre-defined implicit rules fitting a in order to see whether it can be re-made. For example, if the file a.c happened to exist, then make would try to compile a.c to produce the file a. To prevent this, we define an explicit rule for a with an empty recipe. This gives us the updated Makefile:
a: ;
b: a
#echo MAKING B
cp a b
The problem now is that the recipe for make b runs even if a does not exist, which results in a failure. Is there any other way to indicate that a should exist, while not searching for implicit rules to build a? I would like to do this without giving a recipe for a which checks its existence.
I'll try to sum up state of our discussion so far. Perhaps someone still pop's up with another/better insight.
Besides the option also mentioned in the question itself (see bellow for explainer on latest iteration for this approach):
a:
$(error missing file "$#")
b: a
#echo MAKING B
cp a b
In theory it should be possible to disable implicit pattern rule altogether or for specific (set) of target(s) by either defining a no recipe target rule (% : %.c) or defining a static pattern rule (a: % : %.c). Nonetheless the resulting behavior, in case there is an a.c file, seems to be the same as with an empty rule for a:. I.e. make b just proceeds without file a being present (and we'd later fail trying to access it).
Since at least some of the implicit rule seem to be implemented as suffix rules, it's possible to disable consideration of inputs like a.c by purging list of default suffices:
.SUFFIXES:
Or inhibit use of implicit built-in rules altogether by invoking make with -r (or --no-builtin-rules) option. These however are rather heavy handed as they impact processing of all the rules across the Makefile.
To work the comment in:
as mentioned disabling couple of the built in rules for C compilation would appear to yield the desired result, namely:
% : %.c
% : %.o
Would result with a.c present and no a in make: *** No rule to make target 'a', needed by 'b'. Stop.
However (like -r) it's rather intrusive as in all other targets relying on the implicit rule would be impacted. While at the same time it's not as very far reaching, because it does not cover other cases like a.C, a.cpp, a,v,...
Static rule should be able to replace pattern rules where applicable (a more specific rule being applied over the more generic one when matching). But indeed limiting its to a single target does basically put it on par with just a specific a: rule.
I am actually not sure what the rest of the tree looks like and what all possible build steps could occur. With current understanding I would still gravitate to explicit target with file existence check should files with colliding names be a possibility and concern.
Explanation for the latest version of simple failing rule:
As #Stein followed up on the topic, he actually very helpfully pointed out: Simple (always) failing rule for "building" a is perfectly sufficient. If a file of that name (a) exists, the rule for target a never gets to run its recipe. For the case the file is not there, we can just have a recipe that fails with an error message.
Given a Makefile:
ifeq "$(MAKELEVEL)" "0"
0 ::
#$(MAKE)
else
1 ::
#echo 'foo is: "$(foo)"'
endif
And executing, we get:
$ make foo='$#'
make[1]: Entering directory '/home/myname'
foo is: "1"
make[1]: Leaving directory '/home/myname'
$ make foo='$#' --environment-overrides
make[1]: Entering directory '/home/myname'
foo is: "0"
make[1]: Leaving directory '/home/myname'
So we have here a recursive variable foo with the value: $#, which - of course - expands to the name of the target. Now, we have two options here:
Either, Make expands first the variable, and then export the variable to a sub-make.
With this "logic", when Make runs the first makefile (MAKELEVEL = 0), it will build the target 0, Hence: expand the variable foo(and its value:$#) to 0, and then export - this already expanded value - to the sub-make.
This result, with the sub-make running its makefile, with a variable foo that has the simple value: 0.
This is in-fact the case, when we run make --environment-overrides, as you can see in the second run of the makefile, in the example above.
Another "logic" is, for Make to pass the value "verbatim". That means, with no expansion!
Hence all recursive variables will be still intact, when passed to the second Make.
For this logic, only the sub-make is allowed to expand its variables recursively, hence: any recursive-expansion will be done in the context of the sub-make.
In our example above, that we had foo with its value $#, if we are to follow this logic, Make will pass the value $# "verbatim", with no expansion at all, so the sub-make will effectively see a value $# for its foo variable, hence: when expanding in the context of its target, that happens to be 1, it will recursively expand foo(and its value: $#) to 1.
Actually, this is the "normal" behaviour that is evident in the first run of makefile, as evident in the example above.
So, for a lack of clear methodology, we are left to conclude, that this behaviour of either expand and then export or export and then expand is inconsistent.
That is, sometimes Make will choose the first method, where sometimes it will chose the second.
In our example, it was a command-line option (--environment--overrides), that acted as a deciding factor, as to what method Make has to choose.
But, can we really justify, that these - seemingly - unrelated features (i.e export/recursive vs. environment-overrides), will end up to have such a dramatic effect on each-other?
(Versions note: 4.0 and up).
make does export foo in expanded form, as can be seen here:
target:
#echo "'$$foo'"
Output:
$make foo='$#'
'target'
However, to pass its argument to sub-makes, it does not use the environment directly -- instead it stuffs everything into the variable MAKEFLAGS. And there it passes foo unexpanded:
target:
#echo "'$$MAKEFLAGS'"
Output:
$make foo='$#'
' -- foo=$$#'
To be clear: the sub-make does import foo from the environment, but that is then overridden by the setting from MAKEFLAGS.
When you specify --environment--overrides, that means that environment variables take precedence over settings in the makefile. The GNU make documentation does not explicitly specify what happens to variables passed in via MAKEFLAGS in the presence of --environment--overrides, but apparently they are overridden too.
I've been trying to get a makefile, a, to include another makefile, b, if the target specified is not found in file a. I'm using this snippet to try and achieve this, but from echos I've put into the file I can see that makefile b is being accessed even when the target is found in a and run.
The snippet I'm using from the link above is:
foo:
frobnicate > foo
%: force
#echo "No target found locally, running default makefile"
#$(MAKE) -f Makefile $#
force: ;
Specifically I'm getting "Nothing to be done" outputs when makefile b is being used, and makefile a is behaving as expected. This is shown below:
$ make all # all target appears in both make files
No target found locally, running default makefile
make[1]: Entering directory `/home/user/currdir' # (b)
make[1]: Nothing to be done for `Makefile'.
make[1]: Leaving directory `/home/user/currdir'
Local all # (a)
Is there a better way to be doing this?
addition: After adding another echo to the % rule, I've found that $# is "Makefile", when it should be the target trying to be built.
I don't really understand your question based on the example you gave; there is no "a" or "b" in that example, just one Makefile.
However, the behavior you're seeing is due to GNU make's re-making makefiles capability. When you create match-anything pattern rules as you've done, you have to consider that every single target or prerequisite that make wants to build will match that rule. That's a large burden.
You can avoid having remade makefiles match by creating explicit rules for them, such as:
Makefile: ;
When I try to run "make all" on a makefile with some complexity I get this errors:
C:\BITCLOUD\BitCloud_PS_SAM3S_EK_1_10_0\BitCloud_PS_SAM3S_EK_1_10_0\Applications\ZAppSi\Dem o\SEDevice>make all
make -C makefiles/PC -f Makefile_PC_Gcc all APP_NAME=DemoSE
make[1]: Entering directory
'C:/BITCLOUD/BitCloud_PS_SAM3S_EK_1_10_0/BitCloud_PS_SAM3S_EK_1_10_0/Applications/ZAppSi/Demo/SEDevice/makefiles/PC'
A sintaxe do comando está incorrecta.
make[1]: *** [directories] Error 1
make[1]: Leaving directory
'C:/BITCLOUD/BitCloud_PS_SAM3S_EK_1_10_0/BitCloud_PS_SAM3S_EK_1_10_0/Applications/ZAppSi/Demo/SEDevice/makefiles/PC'
make: *** [all] Error 2
where the line
A sintaxe do comando está incorrecta.
translated to english means: "The syntax of the command is incorrect"
I already tried to change the project to different directories, check spaces in file names, using GNU make and also use MinGW make (mingw32-make) and the result is the same with both "make". I also checked for all files that are included in the makefile and they correspond.
Im not an expert in makefiles, so Im asking for help.
What is the main problem that occurs when make throws this type of error?
It is likely not make that throws this error, but a command executed by make returns with a nonzero exit status, in this case with status 1 (due to Error 1); then the top level make stops with Error 2. Note that make by default stops as soon as a command fails.
Since the output doesn't show what command was executed, there is no way to tell what went wrong exactly.
EDIT: from the GNU make manual:
-d Print debugging information in addition to normal processing.
The debugging information says which files are being considered
for remaking, which file-times are being compared and with what
results, which files actually need to be remade, which implicit
rules are considered and which are applied---everything inter‐
esting about how make decides what to do.
--debug[=FLAGS]
Print debugging information in addition to normal processing.
If the FLAGS are omitted, then the behavior is the same as if -d
was specified. FLAGS may be a for all debugging output (same as
using -d), b for basic debugging, v for more verbose basic
debugging, i for showing implicit rules, j for details on invo‐
cation of commands, and m for debugging while remaking make‐
files.
I suggest running make --debug=j to see the commands.
Let me illustrate it with an example.
mkdir test
cd test
touch target
make target
This will result in: make: Nothing to be done for 'target'.
So make tells me there is nothing to do. This is because make did not find a rule to make target, but because the target already exists make tells me there is nothing to do.
Now, I don't want that. I want make to give me an error when it cannot find a rule for target, even though the target already exists.
I have tried the following:
echo '.DEFAULT:
echo make: *** No rule to make target `$#'. Stop.
false'> Makefile
But this does not stop the make when making multiple targets.
The problem is, that make assumes the target name is also a file which will be build by the given commands.
But sometimes this is not true (e.g. think of "clean").
To tell make that some targets don't build this file, you need to make them "phony". Put the following line into your Makefile:
.PHONY: target
If you think about it, you would end up with a chicken-and-egg situation (or infinite regress). Suppose you managed to have a rule that said 'You must have a rule to create target before it is legitimate', then you'd have a rule that says 'target depends on X' for some other file X. That's written:
target: X
command to build target from X
But then you'd be back to the starting point: you'd also want a rule to create X. How can you do that? You might have a rule that depends on nothing and magically creates the file X when it is needed:
X:
command to build X from nothing
Without a rule like that, you have an infinite regress.
So, make is designed to ensure that files exist and are up to date. If a file exists and there are no rules - implicit or explicit - to specify how it is made, then the file is up to date. What you are seeking to do is not possible.
Actually this sounds like a perfectly reasonable (if misguided ;-)) request. You will have to explicitly list every source file with a rule with an empty recipe though.
Here you go:
Makefile: ;
.PHONY: dodgy
dodgy%: dodgy; $(error You must provide a rule for $*)
%: dodgy% ;
The proof of the pudding:
$ rm aa
$ make aa
Makefile:4: *** You must provide a rule for aa. Stop.
$ touch aa
$ make aa
Makefile:4: *** You must provide a rule for aa. Stop.
Note that the line Makefile: ; is necessary. After all, the first thing make tries to do is rebuild the Makefile.
Note also that the catch-all pattern rule is non-terminal. This can be a massive performance hit. As the manual says about match anything rules "They are very useful, but it can take a lot of time for make to think about them."