what the following makefile means? - makefile

Here is Makefile as following, I want to ask what step1 and 2 will do seperately? thanks
DIRS = modules utils library
BUILDDIRS = $(DIRS:%=build-%) step1
all: $(BUILDDIRS)
$(BUILDDIRS):
$(MAKE) -C $(#:build-%=%) step2

This looks like a dispatching Makefile. Its job is to expose the build targets build-modules, build-utils and build-library. If it is not given any target, it builds the all target which depends on all of these. We can also think about, for instance, make build-utils being directly invoked.
Each build-<whatever> corresponds to a <whatever> dir without the build- prefix.
For instance to update the target build-utils, the action is to recursively invoke make with -C utils step2 as the arguments: change to the utils directory and look for a Makefile there, invoking its step2 target.
This Makefile has a flaw: the targets all and the build-<dir> targets are all phony, but there is no .PHONY: declaration for them. This means that make will probe the filesystem, looking for files named all, and build-modules, etc. If you create files with these names, such as by touch build-modules or touch all, the Makefile will then malfunction.

Related

Global prerequisite in GNU make - is it possible

I have a Makefile with tons of targets and would like for a certain script to get executed first, irrespective of what target is being called. I like to call it a global prerequisite.
I do not want to create a target for the script and set it as a prerequisite for all existing targets (which, as I said aren't few). Besides, someone else could add a target in future and not add my script as a prerequisite for their target, so the global prerequisite would take care of that.
Does GNU-make provide for a means to achieve this?
Another approach:
-include dummy
.PHONY: dummy
dummy:
run-the-script
Make will always attempt to rebuild any file which the makefile attempts to include (if it is out of date or does not exist). In this case there is no such file, and the rule to build it runs the script and does nothing else.
There is a solution without modifying your existing Makefile (main difference with the answers pointed to by tripleee). Just create a makefile containing:
.PHONY: all
all:
pre-script
#$(MAKE) -f Makefile --no-print-directory $(MAKECMDGOALS) MAKE='$(MAKE) -f Makefile'
post-script
$(MAKECMDGOALS): all ;
The only drawback is that the pre- and post- scripts will always be run, even if there is nothing else to do. But they will not be run if you invoke make with one of the --dry-run options (other difference with the answers pointed to by tripleee).

copying only changed files between directories using Makefile

I read this: Makefile: Copying files with a rule but couldn't do it.
To make it simple, suppose I have two directories dir1 and dir2. Under dir1 I have three files: rabbit.c, tiger.c and bus.c .
I made Makefile like this:
dir2/rabbit.c:dir1/rabbit.c
dir2/tiger.c:dir1/tiger.c
dir2/bike.c:dir1/bike.c
dir2/%:
cp -f $< $#
I specified the prerequisites in three separate lines and specified the unified recipe for the three targets. I expected when I touch any file under dir1, make will copy that file to dir2. But this happend only for rabbit.c. What is wrong?
ADD(after selecting an answer) :
After realizing what's wrong by Takkat's answer, I fixed it and later modified it further and I think this is the correct simplest Makefile for this case.
.PHONY:all
LIST:=rabbit.c tiger.c bike.c
DSTFILES:=$(addprefix dir2/, $(LIST))
all: $(DSTFILES)
dir2/%:dir1/%
cp -f $< $#
Make chooses a default target in your makefile and, unless you specify differently on the command line, it builds just that target (and all prerequisites required to build that target).
The default target in a makefile is, by default, the first explicit target listed.
So in your makefile the first rule is:
dir2/rabbit.c:dir1/rabbit.c
so the first explicit target is dir2/rabbit.c, so that's all make builds.
If you want to build multiple targets by default, you need a first target that lists all the "real" targets as prerequisites; put this line first in your makefile:
all: dir2/rabbit.c dir2/tiger.c dir2/bike.c
and it will work. It's often considered good practice to declare targets like this, which don't relate to real files on the disk, as phony:
.PHONY: all

Default Makefile for Sphinx

I'm trying to understand the Makefile that is automatically produced by sphinx-quickstart. Here it is:
SPHINXOPTS =
SPHINXBUILD = sphinx-build
SPHINXPROJ = myproj
SOURCEDIR = source
BUILDDIR = build
.PHONY: help Makefile
%: Makefile
#$(SPHINXBUILD) -M $# "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
The lines that confuse me are:
.PHONY: help Makefile
%: Makefile
I think I understand:
The % target means capture anything (wildcard). E.g., if I typed make html, % would capture html.
.PHONY Makefile means that make shouldn't look for a file called Makefile in its directory, thus, shouldn't check the file's modified time to determine whether or not to run a rule.
I don't understand:
Why Makefile is listed as a prerequisite for the target %. The way I interpret this is:
The target rule captured by % should run when the Makefile is changed.
But that doesn't make any sense in the context. What I would expect is:
The target rule captured by % should run when the source files for the project documentation or the API source files have changed.
Directory structure
.
├── build
├── Makefile
├── source
└── utils
The .PHONY: foo has the effect that foo is never to be considered up-to-date. (but see https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html for the more detailed explanations: the main use is for targets which are not filenames)
If you then have bar: foo, the rules for bar target will always be executed on make bar because the target depends upon foo but foo is considered never up-to-date. This can also be achieved with declaring bar target to be PHONY itself.
The problem with the catch-all % target was in case the repertory where the Makefile is located contained a repertory or a file having same name as a Sphinx builder. Say for example there is an html or a man in repertory where Makefile is located: then make html will not do anything if % has no dependencies, because html is then a file or repertory with no dependencies, hence never to get updated.
Thus the % was made to depend on Makefile pseudo target, and Makefile itself declared PHONY so that it is considered never up-to-date.(*) Even if repertory contains a file html then make html will get executed (and html repertory in build dir modified; the html in Makefile repertory will not be modified).
(*) edit: I had forgotten the exact details: Makefile is always considered a target, see a surprising (?) behaviour of GNU Make when using ``%`` as target. For reasons explained here % was made to depend upon Makefile, and the Makefile was declared PHONY in fact to avoid make complaining about circular dependency...
The idea is that the Makefile should not contain the hard-coded list of all possible builders: else they could have been declared PHONY targets individually, but then Sphinx maintainers would have to worry about keeping the Makefile template up-to-date when adding a new builder. It would also cause problems when projects keep same Makefile but a new Sphinx release adds a new builder.
The Makefile now created by sphinx-quickstart does not have to be modified if a new builder is added to Sphinx. It is of course certain that never will Makefile be the name of a builder...

Calling makefile in a subdirectory

I have a source code folder structure as follows
src
|-tests
|-abc
I have a makefile in src which has a target called tests. tests has its own makefile which it uses to compile the source code into binary.(multiple targets).All that is managed by the Makefile in the test directory.
My src make file has the following targets.
all: main tests
main: $(DEPENDENCY IN SRC and ABC)
command
tests: ??
make -C tests
What dependancy can I specify for tests target in the main Makefile.. I don't want this Makefile to be aware of the source files in the tests folder.
all: main tests
main: $(DEPENDENCY IN SRC and ABC)
command
tests:
$(MAKE) -C tests
this will unconditionally invoke make of tests on its private subdirectory. Note that usage of special $(MAKE) variable helps to propagate command-line parameters and reduces overhead.
Just declare the target as PHONY meaning that make will not check for any produced file. Instead it just always executes the rule, letting the secondary call to make to decide what needs to be built.
Think about this: What happens if you have an aditional file src/tests? make will notice that the file already exists and, as no prerequisite is indicated, it will decide not to make that file. Preventing your rule tests from being executed.
all: main tests
main: $(DEPENDENCY IN SRC and ABC)
# Recipes (That is the word to describe commands in a make rule)
.PHONY: tests
tests:
$(MAKE) -C tests
Also add the answer by Alex: using $(MAKE) is a good practice. And allows your makefiles to work independently from the name of the make program. Imagine that you have a distribution where the program is called xyz-make.
I don't want this Makefile to be aware of the source files in the tests folder.
Perhaps, but you may want to reconsider. Peter Miller's Recursive Make Considered Harmful makes a strong case that one Makefile is all you ever need, or want. It changed my mind a long time ago.

How do I check dependencies when invoking a sub-make to build when there are changes?

If I have a makefile that calls another makefile, how to I get the master makefile to correctly check if the dependencies of the subordinate makefile have changed?
For example, if I have the rule
server:
#cd $(SERVERDIR) && $(MAKE)
That invokes make in the subdirectory in which I build an executable "server". However, if I change one of the files that make up server, the parent make doesn't see the changes and refuses to rebuild server - "make: `server' is up to date."
How can I get the master makefile to correctly detect when there's a change in one of the dependent files (something like $(SERVERDIR)/server.c, for example?
It looks like you want to use a phony target
.PHONY: server
server:
#cd $(SERVERDIR) && $(MAKE)
There's a detailed description of the Phony target here, but the short description is you're telling the makefile that there will never be a file that corresponds with this server target, and therefore it won't consider server up to date if there is a file named server in the directory.
Your target name matches the name of one of the files or directories in your main Makefile directory.
Assuming you need to build everything in a subdirectory called server, this rule:
server:
$(MAKE) -C server
will not work, as the target server is a directory, has no source files and doesn't need to be built then.
This one:
srv:
$(MAKE) -C server
will work, as long as there is no file or directory called srv.
You don't:
Recursive Make Considered Harmful
Implementing non-recursive make
But yes, if you have no choice, e.g. because you don't control the sub-makefile, a .PHONY target is what you are looking for.

Resources