Why .PHONY:target and not target:.PHONY? - makefile

I still don't understand why "phony" rules in Makefiles have ".PHONY" as their target. It would be much more logical as a prerequisite.
Do I have to elaborate on this? If A depends on B and B is phony, then A is phony too. So the dependency graph .PHONY←B→A is waay surprising compared to .PHONY→B→A. (Another argument is that an implementation of make must handle the .PHONY target very special.)
While this critique may seem rather theoretical (to pointless) - "since make is so ancient, its syntax is here to stay". But I am not proposing any syntax change, there is an alternative:
With GNU Make (at least), the following Makefile declares a phony target_A:
target_A: _PHONY
touch target_A
_PHONY:
#noop
Question 1: This is so simple and clean, surely I am not its first inventor. In fact, given this alternative, why did make ever need the special syntax?
It seems to me that this would also quite nicely solve questions about wildcards in phony targets, and could even shed some light on .PHONY's meaning when beginners doubt.
Question 2: Can you think of any circumstance where this approach is inferior? (Is invoking make .PHONY of any use?)
(I should mention that while I have invoked other makes, GNU Make is the only implementation that I have some experience with - reading and writing Makefiles.)

One big problem with using target_A: .PHONY is that it makes it much harder to use many of make's built-in variables. Take this common recipe as an example:
%.a: $(OBJ_FILES)
$(LD) $(LFLAGS) -o $# $^
The $^ variable pulls in everything that's listed as a prerequisite. If .PHONY was also listed there then it would be passed to the linker on the command-line, which would probably not result in anything good happening. Using meta-targets like .PHONY as prerequisites makes these built-in variables significantly less useful, as they require a lot of extra processing like $(filter-out .PHONY,$^) every time they are used. Inverting the relationship and instead making .PHONY the target is a bit awkward for the sake of thinking about dependency trees, but it cleans up the rest of the makefile.

Related

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 - does using .PHONY for running commands was intended when creating make?

I know we can set up commands such as all, clean, install etc in makefile and use .PHONY to tell make they're not associated with files.
But I was wondering - when creating make and makefile - was this kind of use (to run such commands) combined with .PHONY designed for that purpose? Or maybe .PHONY was added later to easily extend make to support those kind of commands?
I also read this but there wasn't anything else there except the regular known usage.
Thanks!
I do not know the history of GNU make.
The use of .PHONY is exactly what you suspect: have targets (which can thus be goals, or commands, if you wish) that are not files, and that work even if, by accident, a file with the same name exists. It is one single and clearly defined purpose.
In certain cases you want to force a target file to be re-built even if it is up-to-date, and you can declare it a prerequisite of .PHONY for this purpose, but it is frequently the sign that your makefile is not what it should be.
Another frequent situation is the grouping of several targets (real or phony) as prerequisites of one single other phony target.
But in both cases, we can say that the resulting phony target is a kind of command. In the first case it is a command that forces the build of a file. In the second it is a kind of alias for a series of actions.

make file, what is the idea behind coining of special variables as described below

In make file, for one example, $# is the name of the file being generated,
Find it difficult to remember these special variables
Is there a systematic way that this been coined?
or How this can be remembered?
No, there is no mnemonic that I can think of. The list of automatic variables is documented here. There are really only three that are typically used, so they're not that hard to remember once you get used to them: $# for the target, $< for the first prerequisite, and $^ for all the prerequisites. The others are more for special situations.
What you really need is a cheat-sheet. There are plenty available (search for makefile cheat sheet , and maybe specify the variant, eg gnu).
As an example: http://www.cheatography.com/bavo-van-achte/cheat-sheets/gnumake/

Dealing with dependency poisoning in makefiles

I'm working on re-writing an old build that was originally "designed" (or not, as the case may be) to be recursive. To preface, there will come a day when we'll move to something more modern, expressive, and powerful (eg, scons); however, that day is not now.
As part of this effort I'm in the process of consolidating what should be generic variables/macros & targets/recipes into a few concise rulefiles that'll be included as part of the primary build. Each sub-section of the build will use a small makefile that adds targets & dependencies with little in the way of variables being added in these sub-makefiles. The top level makefile will then include all the makefiles, allowing everything to contribute to the dependency tree.
I must admit I'm not at all confident that people will use good judgement in modifying makefiles. As an example of what I'm worried about:
CFLAGS = initial cflags
all: A.so
%.so %.o:
#echo "${#}: ${CFLAGS} : ${filter 5.o,${^}} ${filter %.c,${^}"
%.c :
true
%.o : %.c
A.so : B.so a1.o a2.o a3.o
B.so : b1.o b2.o b3.o
A.so : CFLAGS += flags specific to building A.so
Provided I didn't screw up copying that example, the situation is thus: A.so would link to B.so, and A.so's objects need special flags to be built; however, B.so and B's objects will inherit the changes to CFLAGS.
I would prefer to have a single target for building most if not all object files, even to the extent of modifying CFLAGS specifically for those those objects that need slightly different flags, in order to promote re-use of more generic targets (makes debugging easier if there's only one target/recipe to worry about).
After I finish re-architecting this build, I'm not at all confident someone won't do something stupid like this; worse, it's likely to pass peer review if I'm not around to review it.
I've been kicking around the idea of doing something like this:
% : CFLAGS = initial cflags
... which would prevent dependency poisoning unless someone then updates it with:
% : CFLAGS += some naive attempt at altering CFLAGS for a specific purpose
However, if there's, just 1000 targets (an extremely conservative estimate), and approximately 1k in memory allocated to variables, then we're up around 1mb of overhead which could significantly impact the time it takes to lookup the CFLAGS value when working through recipes (depending on gmake's architecture of course).
In short, I suppose my question is: what's a sane/good way to prevent dependency poisoning in a makefile? Is there a better strategy than what I've outlined?
edit
If anyone out there attempts to go down the path of scoping variables as described above, I ran into a nuance that wasn't entirely obvious at first.
% : INCLUDES :=
# ...
SOMEVAR := /some/path
% : INCLUDES += -I${SOMEVAR}
...
SOMEVAR :=
When a variable is created using :=, everything to the right of := should be evaluated immediately, whereas if it just used = it would delay evaluation until the target recipe evaluates INCLUDES.
However, SOMEVAR evaluates to nothing when a target recipe is evaluated. If you change the definition to:
% : INCLUDES := whatever
# ...
SOMEVAR := /some/path
% : INCLUDES := ${INCLUDES} -I${SOMEVAR}
...
SOMEVAR :=
... then it forces SOMEVAR to be evaluated immediately instead of delaying evaluation, but INCLUDES doesn't evaluate to its previously scoped definition, rather to the global definition.
$(flavor ...) says INCLUDES is simple, and $(origin ...) returns file; this occurs whether you use := or +=.
In short, if you use += on scoped variables, it'll only use the definition of the variable scoped to that target; it doesn't look at globals. If you use :=, it only uses globals.
If you abstain from unusual characters in your filenames, you can select target-specific variables with variable name substitution:
A.so_CFLAGS = flags specific to building A.so
%.so %.o:
#echo "${#}: ${CFLAGS} ${$#_CFLAGS} : ${filter %.o,${^}} ${filter %.c,${^}}"
Which obviously doesn't propagate the name of the currently built archive to the objects built for that library, but I don't know if this is desired.
This approach has some obvious deficiencies, naturally, like the inability to actually override CFLAGS. However, considering that automake has the same problem to solve and resorts to stupid text substitution, I think a lot of people already failed to find a nice solution here.
As a side-note, you might consider using automake instead of re-engineering it.

Building hierarchical Makefile with GNU Make

I have a project divided in modules, each hosted in a directory, say:
root
|_module_A
|_module.cpp
|_Makefile
|_module_B
|_Makefile
|_main.c
|_Makefile
main.c depends on targets defined in Makefiles related to module_A and module_B.
I want to write my root/Makefile with respect to targets defined in Makefiles of both modules.
Now, I know that I could use the include directive, but the problem here is that targets and filenames in module_A and module_B aren't prepended with their directory, so I get something like this:
make: *** No rule to make target `module.o', needed by `main.c'. Stop.
There is a good way to solve this?
Thanks.
There are a couple of ways to do this, none of them perfect. The basic problem is that Make is good at using things there to make things here, but not the other way around.
You haven't said what the targets in module_B are; I'll be pessimistic and suppose that module_A and module_B both have targets called module (different source files, different recipes), so you really can't use include.
The biggest choice you have to make is whether to use recursive Make:
If you don't, then root/Makefile must know how to build module_A/module and module_B/module, so you'll simply have to put those rules in. Then you must either leave the redundant rules in the subdir makefiles (and run the risk that they'll drift out of agreement with the master makefile), or eliminate them, or have them call the master makefile recursively (which you wouldn't have to do very often, but it sure would look silly).
If you do, then root/Makefile will look something like this:
main: main.o module_A/module.o Module_B/module.o
...
main.o: main.c
...
%/module.o:
$(MAKE) -C $(#D) $(#F)
This will work well enough, but it will know nothing about dependencies within the subdirectories, so it will sometimes fail to rebuild an object that is out of date. You can make clean (recursively) beforehand every time, just to be on the safe side, crude but effective. Or force the %/module.o rule, which is less wasteful but a little more complicated. Or duplicate the dependency information in root/Makefile, which is tedious and untidy.
It's just a question of your priorities.
Can't you write the makefile in a non-recursive way?
Recursive Make Considered Harmful

Resources