OK, I can reproduce this here. The minimal repro is to build a few files in the root objdir (.cargo/config, etc.) and then cd to toolkit/components/updateagent, where you can
make target, make edits,
make target, and
make target again. The second one will build but not install.
I can't decide whether we are giving a bad graph to make, or whether make is making a hash out of the graph we do give it. The graph looks like:
+--- dist/bin/updateagent [---> x86_64/release/updateagent]
target ---+ |
+--- x86_64/release/updateagent ---> force-cargo-program-build
make -n -d target, make sees the "lower" updateagent node, and determines that it has to build the
force-cargo-program-build node, which is fine. The
dist/bin/updateagent node is then considered, and make considers its input to not be new enough to trigger a rebuild of
dist/bin/updateagent... which ignores that
x86_64/release/updateagent might have been updated by the previous build step!
updateagent' is rebuilt, everything works out OK; make sees that cargo'supdateagent
is already newer thandist/bin/updateagent`, and schedules an installation of the latter.
This seems incredibly weird to me, but I think it is a peculiar consequence of using double-colon rules to hang dependencies off of
target (comment 4). The documentation for
Double-colon rules with the same target are in fact completely separate from one another. Each double-colon rule is processed individually, just as rules with different targets are processed.
The double-colon rules for a target are executed in the order they appear in the makefile. However, the cases where double-colon rules really make sense are those where the order of executing the recipes would not matter.
Double-colon rules are somewhat obscure and not often very useful; they provide a mechanism for cases in which the method used to update a target differs depending on which prerequisite files caused the update, and such cases are rare.
I guess the first paragraph is saying that the dependency chains for double-colon rules do not actually interact in any way? So the above vertical dependency doesn't actually exist and the bracketed dependency is the one that's actually considered? (The debugging output seems to support this hypothesis, as the debugging output for each dependency of
target is not related to the other(s) by indentation...)
If that is the case, then a) fixing the problem here is a bit involved and b) why haven't we noticed this before? Have people just dealt with the problem and muttered imprecations in the direction of the build system every time?
If it's not the case, then I am at a loss to explain what is going on.