I used to write a column called "Ask Mr. Make" for CM Crossroads. I ended up turning it into a self-published book called "GNU Make Unleashed" and it contains lots of information like this (all the way to very advanced topics).
A digression but .. CM Crossroads has gone downhill for a while now.
Recently it took three or four emails from me for them to remove some spam hacked into their site.
Thank you for a good article. Even I learned some new stuff. However, there was a major omission: automatic dependency generation. Every now and then I forget how it's done and try to find a good source on the net, but they're really scarce. On the other hand, there are tons of small "your first makefile" tutorials (this article is better than the average).
Here's my Makefile boilerplate. It build single executable from all .c files in this directory and scans for include file dependencies to properly cause recompilation when a header file is touched.
I don't know about out-of-source building, but I know Make has a bunch of built-in rules that you can use to cut down your boilerplate.
For example, I'm pretty sure that a filename depending on objects will automatically be created by linking those objects (although you'd have to specify your libraries in LDFLAGS rather than LIBS. Also, your rule for building .o files from .c files would be automatic if you put your include-directives in CPPFLAGS instead of INCS.
This is generally a bad idea, unless you're explicitly trying to override #include <stdio.h> with a local file (and there are better ways to do that). <> are for system files, "" are for local files.
So off the bat, your makefile example is better than most makefiles out there. I still see things that look like some dumb IDE wrote them with explicit .d and x.c: x.o rules littered about.
Though I do note you aren't taking advantage of the built-in makefile rules (which are defined in POSIX), and you aren't taking advantage of gcc's -MMD flag, which does the dependencies during compilation instead of a separate step. That eliminates much of the file:
Furthermore, I like to name my objects explicitly instead of using * .c, which lets you order them on the command line, if you find that makes a difference. In particular, if your executable is named the same as one of your C source files then you don't even need the link line, as long as the C source file is the first dependency:
I tend to like to prefix variables with the thing you are making so that different executables in the same Makefile can have (drastically) different compilation parameters:
You might want to provide separate CFLAGS and LDFLAGS.
Also, I prefer adding -MMD to CFLAGS instead of having an additional rule for dependency generation: This way, you won't unnecessarily trigger dependency generation on targets which do not build objects like clean.
(Sorry, I misread the above post, but I believe LDLIBS is the Makefile built-in variable for libraries to link.)
Actually, in this case, I believe LDLIBS would be more appropriate since the OP isn't passing any flags to `ld` but rather the libraries for `ld` to link. I ended up getting hit be this in a simple Makefile a few weeks ago that worked in Fedora but failed in Ubuntu.
The target was "%.o: %.c", which make auto-expands to be (something like):
$(CC) $(CFLAGS) $(LDFLAGS) $@ $^ $(LDLIBS)
But I had placed the libraries in LDFLAGS, instead of LDLIBS which caused Ubuntu to fail at finding a function in one of the libraries. Moving the libraries to LDLIBS solved the problem.
I was more concerned about passing CFLAGS when linking - he already has a LIBS variable; you're right that the 'canonical' name for his LIBS variable is LDLIBS (as well as LOADLIBES - anyone an idea where that name came from?).
EDIT: stop editing your answer while I'm writing my own ;)
According to the manual, the built-in rule for linking an executable `n` from a single object file is
The built-in rules and variables for gnu make are worthless for anything but the most trivial project; don't bother with them. I'd be so happy if there was a makefile directive that forced make to run in "make -rR" mode.
I never found a good way to silo the .o and .d files though, the way I do it is put the main makefile in a separate dir from the tree so all the clutter can accumulate there.
Fair warning: GNU make cannot handle directory names or file names which contain spaces. This is a show-stopper defect which has been present since the day it was written and shows no signs of ever being fixed.
Also, why wouldn't I? Why shouldn't I? There isn't a single file system that prevents me from doing so and there isn't a single other computer program in the world which has a problem with it.
Make was made for *nix, it's not exactly surprising that it doesn't conform with Windows's preferences :-) I certainly wouldn't call that show-stopping.
Oh and there are some file systems that don't allow spaces by the way, though admittedly not in common usage.
That's a fair point. Strawberry Perl, I'm looking at you.
I stand by the rest of what I said, though. If a piece of software can't handle spaces in paths, the software is broken. I'm not adding a top-level directory to my C: drive just to appease it. I'll use something else.
Sigh, yet another article giving advice about how to use make as a kind of general-purpose language. It's not. Forget all the crap with wildcards, conditionals, filename globbing, etc. and use it for what it is: a program that takes as input a DAG and a timestamp for each node, and executes rules when predecessor(s) of some node are newer than the node itself.
Take make for what it is and use a proper programming language to handle Makefile generation, installation, etc.
I really appreciate that this article talks about using Make in contexts other than just compiling software. I've used it in the past to automate bioinformatics analysis pipelines. Unfortunately, I ultimately found that it did not really have the flexibility that I needed for more complex analyses, because of various limitations such as the inability to handle multiple output files from a single rule. I also couldn't figure out how to do automatic dependency generation in the general case (not just for C files).
It's worth highlighting here how Tup differs fundamentally from Make in that you specify the DAG from the bottom-up, rather than the top-down as in Make.
That is to say, with the top-down scheme used by Make you think about and write things down in this kind of order:
... which is more akin to how you would write a simple shell script for your build, with all of the commands in the order that they need to be executed. But you still get the time saving of files not being rebuilt if their sources haven't changed, which is the point of using a build system over a shell script in the first place.
To put it another way, Make is declarative like a functional language, whereas Tup more like an imperative language. If you're like me, building is a chore and a build system is supposed to make my life easier, so if it's very much more difficult than a shell script then I can't be bothered with it. Like most programmers I'm more at home with imperative languages than functional; and looking at other people's Makefiles tends to do my head in.
Having said that while Tup has less cruft and some better features (eg. multiple output files as per the parent poster's wish) than Make, it's still a domain-specific language and as such its overall features are limited to what its creator decided were sufficient to his definition of "building programs" for the sake of terser syntax. So, if you're like me you may prefer to hurry on to the 'ultimate' step which is to just use a general-purpose language with a helper library for running build commands. I currently use fabricate.py (http://code.google.com/p/fabricate/) which provides a 'run("shell command")' function to a Python script that runs the command while hooking system calls to spy on the command's inputs and outputs, then saves the command-line and the input/output file names to a file ('.deps') so next time it can check whether the command needs to be re-run or not.
Of course in a general-purpose language such as Python you can do just about anything you like and don't have problems with silly little things like spaces in strings (though see below). While the resulting script may not be as short as the 'ideal' Makefile or Tupfile which could be nearly empty with all their implicit rules taken into account, I'm of the view that explicit is better than implicit.
Couple of specific fabricate.py caveats - being on Windows, I had to do some hackery on my copy of the library to make the dependency detection work better, and to allow for supplying the dependency filenames manually as a fallback. And, the documentation of that 'run()' function could be better (in short, you shouldn't just supply a full string as you would type it at the command line; you should convert those space-seperated command-line arguments into comma-seperated Python arguments, and Fabricate will automatically quote any argument that contains a space. I have no connection with the project but I should really see if I can get into their wiki there and add a little doc laying out the subtleties of it; it does work out in the end). That said, I couldn't be much happier now; it works like a champ everywhere I've tried it including C++, Java, ActionScript and Haxe.
The other downside of bottom-up/imperative style is that it doesn't lend itself automatically to parallel builds (cf. an oft-noted difference between imperative and functional languages in general). I hear it's possible if you plan for it (http://code.google.com/p/fabricate/wiki/ParallelBuilding) though personally my projects have not been big enough to bother trying this so far.
Thanks for another interesting suggestion. Reading the fabricate "how it works" page, I see that you can subclass it to implement your own dependency-determination code, which is cool.
Great article! I could have only wished for such fine introductory material when I was starting off with Make. It would be nice if the docs themselves had a similar chapter.
One thing that I've always wanted from Make was a way of writing long commands with less escaping and without continuation characters. Something like heredoc for Make.
For example, the following is just too arcane and I would by all means move the body of the command into a separate file:
I used to be a pretty good GNU Make 'expert'. I must admit that I'm glad that I've been lucky enough to be able to purge this arcane and esoteric knowledge from my head. Long live .PHONY!
Is recursive make not considered harmful, i.e. best practice is to instead include makefiles from subdirectories ( http://aegis.sourceforge.net/auug97.pdf )?
Ehhh, that's what I said? In the article he takes about reinvoking make using $(MAKE), having mentioned changing to a subdirectory in the previous paragraph.
"Large projects can contain thousands of lines of code, distributed in multiple source files, written by many developers and arranged in several subdirectories."
http://www.lulu.com/shop/john-graham-cumming/gnu-make-unleas...
If you don't like the book format then the original articles (which I cleaned up and improved for the book) are here:
http://blog.jgc.org/2010/01/update-list-of-my-gnu-make-artic...
Also, I created a useful 'standard library' of functions for GNU Make which can be found here: http://gmsl.sf.net/