
Practical Makefiles, by example - jeffreyrogers
http://nuclear.mutantstargoat.com/articles/make/
======
radialbrain
To anyone implementing the automatic dependency generation mentioned in this
article, you can actually make things even simpler by combining the compiling
and dependency steps.

This works because if you add a new dependency to a file, that information
will only be needed for the next build - the current file will already be
considered out of date seeing as it was edited to add the #include.

    
    
      gcc -MD -MP foo.c -o foo.o
    

Will compile foo.c into foo.o, and also generate foo.d (-MD). Foo.d will
contains make style dependencies, and also a phony target for every dependency
(-MP). This allows you to delete dependant files, as make considers the target
of a rule that has no perquisites or commands to be up to date if said target
does not exist.

~~~
exDM69
I second this, using CFLAGS=-MMD or -MD makes writing a Makefile a lot more
simpler. This also gets rid of the need to add a rule for building dependency
files and you can rely on the built-in rules (see `make -p`) to build object
files.

A good Makefile should have any rules for building object files if you're
using a language like C or C++, which Make has built-in rules for. If using
another language, adding a few generic rules should be enough.

Here's a Makefile template I've been using for some time. It may look
complicated initially but only the first 70 or so lines are the actual beef.
The rest of the Makefile is helpful rules for tooling (tags, cscope, coverage,
profile) but that doesn't work too well at the moment. It also supports out-
of-source-tree builds (using vpath to locate _source_ files, object files and
other outputs go under $PWD, vpath is does not work for object files).

[https://github.com/rikusalminen/makefile-
for-c](https://github.com/rikusalminen/makefile-for-c)

~~~
radialbrain
I can't say I share your love for make's built in rules. I find using them
often just makes the build system harder to understand and debug. I usually
disable all of the built in ones using:

    
    
      # Disable built in suffix rules
      .SUFFIXES:
    
      # Disable builtin pattern rules
      MAKEFLAGS+=-r

~~~
exDM69
> I can't say I share your love for make's built in rules.

Yes they can be a bit limiting, but even if you do not want to use built-in
rules it's still a good idea to use generic rules using wildcards.

This is what lots of "Makefile tutorials" get wrong, they _start_ by writing
rules to build _individual_ object files and targets.

Even if you want to write your own build rules, you should not need more than
a few good rules for building and linking your object files.

~~~
radialbrain
Completely agree with you here - there should never be the need to hardcode
file names in a makefile or repeat a rule multiple times - just use pattern
rules.

------
pdq
One other dependency often forgotten is on the Makefile itself. This way if
the Makefile changes, everything gets rebuilt:

    
    
        DEPS = Makefile
        %.o: %.c $(DEPS)
            $(CC) $(CCFLAGS) -o $@ -c $<

~~~
exDM69
This may or may not be what you want, depending on the use case. If you change
an important variable in the Makefile (e.g. CFLAGS), you might want to
recompile everything. However, if you're just adding a new source file to the
Makefile, you definitely do not want to rebuild everything.

I prefer to run `make clean` manually when necessary rather than adding a rule
to rebuild everything "just in case". But I can imagine that this might be
useful in some cases.

~~~
atrn
I like to put CFLAGS/CXXFLAGS et al in separate files that just define the
corresponding macro. These get included in the makefile which has dependencies
added to rules that reference such a macro on the file that defines the macro.
E.g. the .o rule for C++ has a dependency on the CXXFLAGS which defines
CXXFLAGS. Change CXXFLAGS and things rebuild, mess with LDFLAGS and you re-
link etc... Handy if you need it but you can end up with lots of little files.

------
krapht
I disagree with this. I don't find CMake any less easy to use than make in the
simple case, but it is far better than Autotools in the complex case. Just
learn CMake and be done with it. As a bonus, it saves you some typing making
your program cross-platform, although that is a pain no matter what tool
you're using.

~~~
exDM69
CMake works really well when you are building a normal user space application
with only popular libraries (or ones that use CMake themselves) as
dependencies that CMake can find and configure. Some CMake generators are
better than others (e.g. ninja-build is really nice with CMake). Creating MSVC
Project files was _badly_ broken the last time I tried and even when it
worked, the resulting project files are awkward for MSVC IDE users (I prefer
nmake makefiles if compiling on Windows with MSVC).

CMake falls apart when you try to do something more complicated, e.g. building
a bootable kernel image which requires special handling for compiling and/or
linking. I have done a bare metal project using CMake and GNU Make and the
latter was _a lot_ easier.

To name a few other platforms where using GNU Make works better: Android NDK
(default Android.mk build system is GNU Make, there are CMake-based hacks for
Android but they were _atrocious_ ) and doing micro controller work like
Arduino (when writing C, not using the Arduino language).

To give an example where CMake works a lot better than GNU Make is cross
compiling, e.g. building Windows binaries on a Linux host. All it takes is a
few lines of "toolchain specs" and apt-getting the mingw toolchain. But even
this falls apart when you need to build both, "host" and "target" binaries
like you often need with hardware projects.

CMake is by no means perfect and GNU Make is still a very useful tool to know.

------
gshrikant
Is anyone aware of the reasons for choosing the particular symbols that Make
uses i.e. '@' (targets), '^' (list of dependencies) and '<' (first in the list
of dependencies)?

I have admittedly limited experience with make and I always seem to forget
what symbol stood for what. They don't seem to be particularly intuitive
mnemonics to me.

For example, one could argue that '<' for target and '>' for dependencies
would be a tad clearer.

~~~
mewo2
I always think of '^' and '<' as being arrows pointing at the relevant
dependencies, i.e "that list of things up ^ there" or "that thing on the far
left <". It can also help to think of '<' as being like a stdin redirect, so a
simple rule might look like "myprog < $<".

I'm not sure what the deal is with '@' though.

~~~
sigjuice
I have always thought of '@' as an archery target.

------
golergka
Very appreciated. I'm trying to make small hobby projects with a simple C and
Makefiles, to get a taste of a stripped-down, basic environment, and after I
got accustomed with basic Makefile usage (which is taught in any of thousands
tutorials on the matter), I found myself lacking coherent and easy to read
material that would get me to a more advanced level. Tutorials and stack
overflow questions either cover really basic stuff or suggest things that seem
like awful practice in the first glance, and GNU Make manual is written in way
that suggests you sit down and read it for a few hours instead of just giving
you a quick and sane way to solve a particular problem.

------
sandij
See also this post by Mike Bostock (d3.js developer), ‘Why Use Make’, with
practical non-C examples:

[http://bost.ocks.org/mike/make/](http://bost.ocks.org/mike/make/)

------
cjdrake
With all the news lately about Bazel, kind of refreshing to talk about this
war-horse.

Consider: 1\. Paul Graham recommends to "do things that don't scale". 2\.
Google designed Blaze when gmake started to scale badly.

Chances are, gmake plus some shell scripts and language-dependent build flows
is all you really need. Worry about replacing it with something more scalable
when you actually have that problem :).

------
Roboprog
An elegant weapon from a more civilized time, indeed.

Frack Windows, and frack XML :-(

------
greggman
Getting into JavaScript there's grunt. I know it's not really comparable to
make as it doesn't check dependencies but ... it really seems like it would be
cool for a "new" build system that took plugins the way grunt does. Maybe
they'd wouldn't fit most people's use cases enough?

------
ahaltindis
This is nice introduction for someone just beginning gcc like compilers. For
example I would use this back then when I started to use avr-gcc. It doesn't
have to be cross-platform or need any other super complex fancy things. It
just needs few extra rules and some basic stuffs. Make is great choice for
this kind of things.

------
nimrody
Object files should not be placed in the same directories as source files.

------
flohofwoe
It's interesting that under the section "Handling cross-platform differences"
the author calls 'uname -s'. It's not cross-platform if you ignore Windows
(and requiring to install cygwin doesn't count), or cross-compiling scenarios.
Also makefiles don't help all that much if you want to work in the platform's
'native' IDEs (like Visual Studio or Xcode). These 3 points (cross-platform,
cross-compiling and IDE support) are exactly the points that meta-build-
systems like cmake (or scons, or premake) fix. Remember that cmake isn't a
replacement for make, for command line compilation it usually makes sense to
let cmake generate makefiles (except on Windows).

------
tempodox
Nice, but the page's color scheme starts hurting my eyes after about 15
seconds. Dark / colored text on a light background would be much more reader-
friendly.

------
nirvanis
Practical Makefiles: nice oxymoron.

------
k_sze
Great idea. But awful theme. And no longer really relevant.

CMake is now all the rage. Like krapht said, just learn CMake and be done with
it.

~~~
ffkklf
ugh. CMake is atrocious. It covers maybe .1% of the cases that autotools
handles while having some of the worst documentation known to man. Not to
mention yet another language to learn. It's not more "modern" than autotools
and it's in no way shape or form "newer" than autotools, seeing that
automake/autoconf have been in active development since inception.

~~~
krakensden
It does let you avoid shell, which makes cross platform stuff less fraught.

This should not be interpreted as an endorsement of CMakes miserable, quarter-
assed BASIC-in-almost-s-exprs language.

~~~
bch
Upvoted, and re: documentation, I will say that I enjoyed the print book[0]
when I was reading it years ago. Your comment re: quarter-assed BASIC... is
about what I was thinking when I wrote
[https://news.ycombinator.com/item?id=9283016](https://news.ycombinator.com/item?id=9283016)
\-- a big missed opportunity.

[0] [http://www.amazon.com/Mastering-CMake-Ken-
Martin/dp/19309342...](http://www.amazon.com/Mastering-CMake-Ken-
Martin/dp/1930934262)

