To begin with, here’s the disclaimer: this article is not a tutorial or manual for make. Please read and understand the documentation for make before you try the experiment mentioned in this article. There are literally thousands of sources from where you can learn about make. The tutorial at www.wlug.org.nz/MakefileHowto is a neat and crisp one. The one at www.makelinux.net/make3/make3-PART-1.html is longer and more in depth.
With that out of our way, let’s get started, shall we? A make rule is composed of the following:
target: prerequisites commands
A target is considered ‘up to date’ if it exists and is newer than its prerequisites. The commands are executed only if the target is not up-to-date. The commands may end up updating the target. Each of the prerequisites can be the target in other make rules. Thus we have a whole tree of targets and prerequisites.
make is a very clever program. It works backwards, starting with the target of the first rule in the file. It walks down the recursion chain of target-prerequisite-target, until it finds a target that has no prerequisites, or whose prerequisites have no rules. Once it hits one of those, it walks back up its recursion chain and runs commands as necessary. It creates a recursion chain for every prerequisite it encounters that has a rule, and resolves it. It can also detect vicious circles of the following kind: A depends on B, B depends on C, C depends on A.
In the simplest of cases, the prerequisites are all files. But there may be situations in which you would like to use a directory as one of the prerequisites. make enables you a way to handle this too.
Imagine the following scenario: you have a directory lfy/ where you have files lfy1, lfy2, lfy3. You usually zip all the files of lfy/ and keep it as a fallback copy. Every time a new file is added to lfy/, or when any of the existing files in lfy/ is updated, you would like to zip lfy/ again, and store all files in a single zip file lfy.zip.
You can write a simple rule with the target as lfy.zip, and prerequisites as lfy1, lfy2, lfy3. But if you have 1000 files in lfy/, you cannot obviously list each of them by name. Or, if files keep getting added or removed from lfy/ frequently, you don’t want to keep rewriting the rules each time. You would like to use a wildcard expansion of lfy/ and let the wildcard do all the book-keeping. Try the following experiment:
- Create a directory lfy/ and add the dummy files lfy1, lfy2 and lfy3 in it using touch. In fact, you can fill up the directory with a 1000 files, if you want.
- Create a blank file testmake and enter the following in it:
# testmake start # Calling sequence "make -f testmake" objects := $(wildcard lfy/*) lfy.zip : $(objects) echo lfy is more recent zip lfy.zip lfy/* #end testmake
- Run make, using
make -f testmake. It will create lfy.zip.
- Run make using
make -f testmake. Nothing happens, since lfy.zip is up-to-date.
- Now run touch lfy/lfy1 and run
make -f testmake. It will update lfy.zip. In fact, lfy.zip will get updated every time any file in the lfy/ directory is touched (updated).
- Remember, lfy.zip should not be in the lfy/ directory, since it will cause an endless loop in the above script.
You can get all the files of the above experiment along with documentation, as a single zip/tar bundle by sending a mail to drpartha at gmail dot com. In fact, this is a more elegant solution than the one I proposed in an earlier article in LFY (‘Treasure Hunt with Find’, July 2008).