How make decides to build target - makefile

One sign is that target does not exist, understand this.
Another is by comparing modification timestamp of target and prerequisites. How it works in more details? What is the logic of comparing target and prerequisite timestamps and how it works when there are multiple prerequisites?

make first gets the modification time of the target, then compares that value to the modification time of each prereq, in order from left to right, stopping as soon as it finds any prereq that is newer than the target (since a single newer prereq is sufficient to require the target be rebuilt).
For example, suppose you have a rule like this:
foo: bar baz boo
Further, suppose that the modification times on these files are as follows:
foo: 4
bar: 3
baz: 6
boo: 2
In this case, make will compare the modification time of foo (4) to the modification time of bar (3); since bar is older, make will move on and compare the modification time of foo (4) to the modification time of baz (6). Since baz is newer, make will decide that foo must be rebuilt, and will stop checking the prereqs of foo (so boo will never be checked).
If you have multiple dependency lines for the output target, as in:
foo: bar baz
foo: boo
The prereqs in the second and subsequent dependency lines are simply appended to the end of the list of prereqs for the output target -- that is, this example is exactly equivalent to the first example above.
In general, all make variants behave this way, although some variants have extensions that modify this behavior (for example, GNU make includes order-only prerequisites; Sun make has "keep state" features; etc).

Unix make has pretty complicated inference rules to determine if the target needs to be rebuilt. For GNU make you can dump them by running 'make -p' in a directory that doesn't have a Makefile.
Also the rules could be chained, more explanation about it is here
Standard Unix make and Microsoft nmake work in similar fashion

Related

Makefile rule with no target

I'm debugging a makefile, and in a macro expansion it creates a rule with no target (as so:)
: | directoryA
#echo running $#
...
I've looked it up online, and the makefile documentation seems to hint (but not explicitly state) that there should be at least one target.
With my current version of make (gnu Make 4.2.1), it's not killing me, but I'm just wondering whether this is considered undefined behavior or whether this is supported, and if so, what it should do.
I've looked it up online, and the makefile documentation seems to hint (but not explicitly state) that there should be at least one target.
Different makes may behave differently. They may even exhibit variant handling of specific makefile syntax matters depending on the content of the makefile -- for example, a makefile may be interpreted differently if it starts with a rule for the .POSIX: special target than an otherwise identical makefile without that rule is interpreted.
Overall, however, if you want some sort of general idea of what should be considered correct then the POSIX standard's defintion of make is a reasonably good baseline. It says:
Target rules are formatted as follows:
target [target...]: [prerequisite...][;command]
[<tab>command<tab>command...]
line that does not begin with <tab>
Target entries are specified by a <blank>-separated, non-null list of
targets, then a <colon>, [...]
(emphasis added). It furthermore goes on to say that
Applications shall select target names from the set of characters
consisting solely of periods, underscores, digits, and alphabetics
from the portable character set
, from which we can infer that the syntax description is talking about the rule text after macro expansion, since macro references can appear in the target lists of rules (or literally anywhere in a makefile, per the spec), but the characters $, (, ), {, and } appearing in macro references are not among those that can appear in targets.
That specification of makefiles' expected contents does explicitly state that target lists are non-empty, and it is reasonable to treat it as authoritative where your specific make's documentation does not override it.
I'm just wondering whether [an empty target list] is considered undefined behavior or
whether this is supported
Your combination of makefile and runtime macro values does not conform to the requirements of POSIX make. The spec does not define what should happen in this case, so in that sense the behavior is undefined, but "undefined behavior" isn't as strong a concept in this area as it is in, say, the C and C++ language specifications.
In view of that, I would account it a makefile flaw for any rule's target list to be empty (after macro expansion). Although the make you are presently using may accept it without complaint, other makes, including future versions of your present make, may reject it or worse.
Rule does expect one or more targets, there really are no two ways about it in the docs. For instance GNU make docs notation:
targets : prerequisites
recipe
Or 1p section manpage:
target [target...]: [prerequisite...][;command]
Illumos:
target [:|::] [dependency] ... [; command] ...
[command]
...
After all how would you refer to a target that had no name? I would assume no target rule should be an error...
However, I've tried different flavors of make (BSD, Illumos, GNU) and with varying degree of leniency (GNU make for instance seemed to also not care about syntax of prerequisites any more) or lack thereof they all seemed to have processed the line and possibly following tab indented block as a rule (with a recipe)... which then was ignored (also for the purpose of determining the default target).
I guess a rationale for this actually being consider valid Makefile... you could end up in this situation also with:
$(VAR):
#echo foobar
other:
#echo barbaz
In case VAR is undefined or empty, you'd end up with a such empty target as well.

What are the consequences of having almost duplicate target rules in a Makefile?

I have inherited a problematic Makefile.am that has been causing build issues. In this makefile, there are a couple instances where there are almost duplicate target rules. They are almost duplicate because the second one has one or two extra prerequisites. Here is an example:
target1 target2: prereq1 prereq2
ACTION
target1 target2: prereq1 prereq2 prereq3
ACTION
The action is identical, and target1 and target2 are identical. What is the consequence of this? Will both rules be executed?
To extend this question a bit, if prereq3 was auto generated during the make process, how would this play out? If make is run in parallel, could this cause big issues?
The action is identical, and target1 and target2 are identical. What
is the consequence of this? Will both rules be executed?
The consequence is that the makefiles generated based on this Makefile.am, which will include both rules verbatim, will fail to conform to the POSIX specifications for makefiles. POSIX forbids that more than one target rule provide a recipe for any given target.
If you happen to use GNU make to build, then instead of rejecting the makefile outright, it will use the last-given recipe for each target; all other target rules for each target will be treated as prerequisite-only rules, whether they provide a recipe or not. If you use a different make (which the Autotools expressly support), then results may differ. Relying on implementation-specific behavior such as this is very poor form in Autotools build systems.
Since the recipes are the same, the targets are the same, and the prerequisite list of the earlier rule is a subset of the prerequisite list of the later rule, I see no reason whatever to retain the earlier rule. Just delete it wholesale. No behavior will change under GNU make, and you will not have to worry about the behavior of other makes differing on account of this issue.
That does presume, however, that there are no other target rules for either target1 or target2. If the last-appearing rule for target2 that provides a recipe is a different one than the last-appearing rule for target1 that provides a recipe, then two recipes will run: one to generate target1 (maybe with a side effect of also generating target2), and the other to generate target2 (maybe with a side effect of also generating target1). The relative order of those is unspecified, and the result might be inconsistent.
You should also read the Automake manual's comments on tools and rules that generate multiple targets.
To extend this question a bit, if prereq3 was auto generated during the make process, how would this play out?
No differently than already described, at least for GNU make. It is possible that the construction you describe was motivated by a misunderstanding of this issue, or perhaps that it targeted the implementation-specific behavior of some other make implementation than GNU's, but if, currently, the software builds correctly with GNU make then removing the first rule just converts the resulting makefile to a POSIX-conforming one (in this respect), with no reason to expect any change in behavior.
There may be nuances and alternative solutions associated with the specifics of your situation, but all of the above comments apply regardless of any such details.
If make is run in parallel, could this cause big issues?
Rule duplication of the form you describe has no particular interaction with parallel make. However, you will likely run into issues with parallel make if you do not express the full dependencies of each target, and especially the dependencies on other built targets. But note that you don't generally need to express dependencies on C or C++ header files, even built ones, because Automake-generated makefiles include code for detecting and tracking these automatically.
BUT, if you have other target rules that provide recipes for one or both targets, as mentioned above, then yes, that will be an issue for parallel make. Do yourself a favor, and ensure that no target has a recipe specified by more than one target rule.
Also, although the rule duplication might not be an issue for parallel make, if one run of the recipe generates both targets, then that might create issues for parallel make. Refer to the Automake manual, linked above, for more commentary on that point.
Assuming you are using gnu make, the warning indicate that the first rule is ignored. Running make with lol execute the ACTION from the 2nd recipe. The ACTION from the first recipe can removed (which will remove the warnings!).
make
Makefile:5: warning: overriding recipe for target 'target1'
Makefile:2: warning: ignoring old recipe for target 'target1'
Makefile:5: warning: overriding recipe for target 'target2'
Makefile:2: warning: ignoring old recipe for target 'target2'
echo "Action2"
Action2
Quoting from gnu make manual: https://www.gnu.org/software/make/manual/make.html
warning: overriding recipe for target xxx'
warning: ignoring old recipe for targetxxx'
GNU make allows only one recipe to be
specified per target (except for double-colon rules). If you give a
recipe for a target which already has been defined to have one, this
warning is issued and the second recipe will overwrite the first. See
Multiple Rules for One Target.

Is it legal to override target in Makefile by order in a file?

I have a Makefile:
.PHONY: all
all: target1
target1:
$(info "target1")
target1:
$(info "target1 override")
If to execute "make" from a bash it will respond:
$ make
Makefile:8: warning: overriding recipe for target 'target1'
Makefile:5: warning: ignoring old recipe for target 'target1'
"target1 override"
make: Nothing to be done for 'all'.
This behavior is expected by me, because I expect that the latest definition of the target will be taken by Makefile's parser.
Is it legal to expect that the latest rule from the Makefile will be taken if the rule is overridden?
Is it possible to get rid of warnings?
P.S. Also I have tried answers from another StackOverflow's questions like the use of "override" keyword and "::" symbols. It doesn't help (errors and the same warnings from Makefile appears).
Is it legal to expect that the latest rule from the Makefile will be
taken if the rule is overridden?
A makefile that contains multiple target rules that provide recipes for the same target violates the POSIX specifications for make:
Only one target rule for any given target can contain commands.
Violating that will not bring the police down on you, but it may, rightfully, bring down the wrath of other developers and managers who have to work with your code, now or later. Implementations of make are not bound by the spec to any particular behavior when a makefile containing such multiple recipes is presented.
The diagnostic messages you present and the behavior you describe appear characteristic of GNU make. To the extent that you are willing to be dependent on that particular make implementation, it would be reasonable to rely on section 4.11 of its manual, which says:
There can only be one recipe to be executed for a file. If more than
one rule gives a recipe for the same file, make uses the last one
given and prints an error message.*
(Footnote mine.) But reliance on that renders your makefile non-portable. Other make implementations might instead reject the makefile, choose the first recipe, choose a random recipe, choose all matching recipes in some order, or exhibit any manner of obvious or non-obvious breakage. Alerting you to that is the purpose of the message.
Is it possible to get rid of warnings?
Continuing to assume GNU make, the manual says definitively that a diagnostic will be emitted, and its summary of command-line options does not describe any that I would expect to suppress the output in question without also suppressing the actual build.
Bottom line
The question conveys the impression that you think the usage described ought to be acceptable, so that the diagnostic is merely a nuisance. This is not the case. Such usage is poor style, at least, and it can present genuine problems for yourself and others. Whatever you're trying to accomplish that way, there are better alternatives.
*It's referring to target rules. Suffix and pattern rules that match the target are a different matter.

Makefile generator creates two files

I have a generator program that creates two version files, say ver.h and ver.cpp. My ultimate build target depends on both of these files, and the rule for building both is that one program. If I did this:
build : ver.h ver.cpp
ver.h ver.cpp :
./gen/version/program
then a parallel build could run program twice, which, while not bad is just excessive. I figure I could have them both depend on a phony target:
ver.h ver.cpp : do-version-impl
do-version-impl:
./gen/version/program
.PHONY : do-version-impl
Is that the best way to do this? It smells a little funny to have to introduce a phony rule to do this.
Using the phony target as the prerequisite is a bad idea. program will be run even if ver.* files exist, which is a false positive error.
More subtly, GNU Make is only guaranteed to update its file timestamp, if that file is a target of a rule with a recipe. So here, even though program is always run, anything that in turn depends on ver.* files might not get updated at all!
In my opinion it is best to not make up unnatural patterns for each target, but instead, go explicit:
There is a "main" file that you are generating, that is ver.cpp. Use the "no-op" recipe ; for the other one, which can be put on the same line like this:
ver.h: ver.cpp ;
ver.cpp: Makefile
./gen/version/program
This method starts with what you wrote, but adds the very important ;.
If you did not have a natural candidate for the "main" file, then in my opinion it is best to use a "sentinel":
ver.h ver.cpp: sentinel ;
sentinel: Makefile
./gen/version/program
touch $#
Again, this method is similar to one of your methods, but very importantly, does not use a phony, but a real file.
See 10.5.1 Introduction to Pattern Rules specifically the last paragraph:
10.5.1 Introduction to Pattern Rules
...
A pattern rule need not have any prerequisites that contain ‘%’, or in fact any prerequisites at all. Such a rule is effectively a general wildcard. It provides a way to make any file that matches the target pattern. See Last Resort.
...
Pattern rules may have more than one target. Unlike normal rules, this does not act as many different rules with the same prerequisites and recipe. If a pattern rule has multiple targets, make knows that the rule’s recipe is responsible for making all of the targets. The recipe is executed only once to make all the targets. When searching for a pattern rule to match a target, the target patterns of a rule other than the one that matches the target in need of a rule are incidental: make worries only about giving a recipe and prerequisites to the file presently in question. However, when this file’s recipe is run, the other targets are marked as having been updated themselves.
So you could use something like this:
v%r.h v%r.cpp:
./gen/version/program
I believe you need that odd patterning to have make consider the pattern to match (I don't believe it will match % against an empty string as ver%.h ver%.cpp would need). (I can't find reference to this in the manual at the moment though.)

Writing a Makefile to be includable by other Makefiles

Background
I have a (large) project A and a (large) project B, such that A depends on B.
I would like to have two separate makefiles -- one for project A and one for project B -- for performance and maintainability.
Based on the comments to an earlier question, I have decided to entirely rewrite B's makefile such that A's makefile can include it. This will avoid the evils of recursive make: allow parallelism, not remake unnecessarily, improve performance, etc.
Current solution
I can find the directory of the currently executing makefile by including at the top (before any other includes).
TOP := $(dir $(lastword $(MAKEFILE_LIST)))
I am writing each target as
$(TOP)/some-target: $(TOP)/some-src
and making changes to any necessary shell commands, e.g. find dir to find $(TOP)/dir.
While this solves the problems it has a couple disadvantages:
Targets and rules are longer and a little less readable. (This is likely unavoidable. Modularity has a price).
Using gcc -M to auto-generate dependencies requires post-processing to add $(TOP) everywhere.
Is this the usual way to write makefiles that can be included by others?
If by "usual" you mean, "most common", then the answer is "no". The most common thing people do, is to improvise some changes to the includee so the names do not clash with the includer.
What you did, however, is "good design".
In fact, I take your design even futher.
I compute a stack of directories, if the inclusion is recursive, you need to keep the current directories on a stack as you parse the makefile tree. $D is the current directory - shorter for people to type than $(TOP)/,
and I prepend everything in the includee, with $D/, so you have variables:
$D/FOOBAR :=
and phony targets:
$D/phony:

Resources