
“The GNU Make Book”: probably more than you ever wanted to know about make - jgrahamc
http://blog.jgc.org/2015/04/the-gnu-make-book-probably-more-than.html
======
danieljh
Implicit makefile rules can be quite helpful in quickly building a few
binaries or small projects.

Take a look at this C++ example: for a file mybin this creates mybin.o and
then links it, spitting out a mybin executable:

    
    
        env CXXFLAGS="-std=c++14 -Wall -Wextra -pedantic" LDLIBS="-lstdc++" make mybin
    

To see what's going on, and what kind of file types are supported:

    
    
        make --print-data-base | egrep 'COMPILE.cc|LINK.cc'
    

This not only shows you what is going on, but also what kind of environment
variables are involved and can therefore be customized.

For small projects I would create a config.mk (e.g. with CXXFLAGS, CXX, ...)
and provide a small Makefile, something along the lines of:

    
    
        include config.mk
    
        all: mybin
    
        mybin: mybin.o
    
        watch:
            while ! inotifywait -e modify *.cc; do make; done
    
        clean:
            $(RM) *.o mybin
    
        .PHONY: all watch clean
    

This allows you to easily 1/ add dependencies for binaries and 2/ speed up the
development proccess, using the make watch target (note: this does not include
header dependencies).

Disclaimer: Makefiles seem to be wonderful build-systems (not dependency
managers!) for small projects; but as soon as you find yourself searching for
hacks to build into your little Makefile, ditch it and switch to something
serious. That's at least my experience.

~~~
sdevlin
> something serious

What do you recommend? Autotools, bespoke shell scripts, or something else
entirely?

~~~
mackwic
It will depends on you platform and technology. I can only recommend you to
_not_ be fancy and stick with the conventions or else you could have a lot of
trouble to interact with dependencies. By dependency I mean anything your
program would need to run: from system libraries, headers, local libraries
linked either statically or dynamically, or even syscall. A lot of things can
go wrong, our whole software cathedrals are build upon years of conventions
and patches. Anything can break. Don't even try too look what `ld(1)` is
doing.

Autotools has never be a great tool, only a necessary evil for when you need
to package cross-Unixes software. I heard that CPack
([http://www.cmake.org/Wiki/CMake:Packaging_With_CPack](http://www.cmake.org/Wiki/CMake:Packaging_With_CPack))
do the job while being exactly as good as CMake (which can be a compliment...
or not. YMMV).

So, if you use Rust, use Cargo, with Java use Maven, with C# use MSBuild, with
ruby use Rake, etc. And C/C++ ? Well, for once if you can chose you're lucky.
You can try CMake or premake.

The only thing you must do is get away of most of the Google's build projects:
Gyp, Lunch, Ninja, etc. I have horrible experiences with those. Even worse
than Rubygem's native compilation, which is quite a performance.

~~~
bla2
What's wrong with ninja? It's CMake's best output format as far as I know. A
lot more enjoyable to use than, say, msbuild.

------
mturmon
The author is a master. I first encountered his byline when trying to debug a
Makefile (that I had written!), and came across his article in DDJ
([http://www.drdobbs.com/tools/debugging-
makefiles/197003338](http://www.drdobbs.com/tools/debugging-
makefiles/197003338)). It was invaluable, because I had been stuck between
using make -d and @echo "building foo now", and I hadn't wanted to admit I was
actually debugging and so I needed some specialized tools. I'm sure the book
is excellent.

~~~
dima55
A general comment on debugging GNU Make: there's a fork
([http://bashdb.sourceforge.net/remake/](http://bashdb.sourceforge.net/remake/))
that adds interactive debugging facilities to GNU Make. Since this is a fork
and not a reimplementation, it's 100% compatible. Much nicer than "make -d"
generally.

~~~
LukeShu
Yeah, but it's based on an old version of Make; we're on to 4.1 now, it's
still based on 3.82.

~~~
dima55
True. You're unlikely to be using anything that's in 4.1 but not in 3.82,
however. I wish the remake stuff would get merged into the main tree, but
there're probably political issues there, or something.

~~~
lmz
[https://github.com/rocky/remake](https://github.com/rocky/remake) the sources
there claim to be from version 4.1

------
haberman
If anyone (the author or anyone else!) wants to demonstrate their make-fu,
here is a very subtle issue I ran into with make that I never did get to the
bottom of.

[http://stackoverflow.com/questions/25589586/why-does-
patsubs...](http://stackoverflow.com/questions/25589586/why-does-patsubst-
stop-working-when-using-secondary-expansion-of)

Someone pretty knowledgable chimed in, but we were both stumped. In the end I
found a workaround, but never did get to the bottom of this peculiar behavior.

~~~
LukeShu

        > EDIT: I had a theory that the % characters inside the patsubst
        > were getting evaluated early, using the stem match (foo), so
        > that the patsubst itself was looking something like this:
        >
        >    $(patsubst foo.c,foo.o,bar.c baz.c)
    

That is what happened. The answer on SO explains how to work around it.

    
    
        > To test this theory, I added a file called foo.c to foo_SRCS:
        ...
        > That resulted in something even weirder:
        >     make: *** No rule to make target `foo.a', needed by `all'.  Stop.
    

Which resulted in Make seeing the line as

    
    
        %.a: %.o bar.c baz.c
    

Now, Make will only choose to use a pattern rule if it knows how to make all
of the prerequisites. If Make doesn't know how to make foo.o (which it
wouldn't if you don't have an actual file named foo.c), then it won't even
consider the rule as a possibility to make foo.a.

------
rbanffy
If it prevents the invention of the next Maven, Buildout or Grunt, I'm sold.

------
ludwigvan
Also see O'Reilly freely available GNU Make book:
[http://www.oreilly.com/openbook/make3/book/index.csp](http://www.oreilly.com/openbook/make3/book/index.csp)

------
unhammer
One thing I've never figured out a good solution for in make, is multiple-
pattern rules. Say I have

    
    
      LANGS=nob sme sma smj
      POS=V N A
      

and want to run something on all combinations of these, like

    
    
      ./something --pos=V --f1=nob.f --f2=sme.f nob.txt sme.txt > nob-sme.V
    

– how can I make a pattern goal for that? I invariably end up with some
redundancy, where e.g. only the "V" in the example above turns into my % (and
$ * ), e.g.

    
    
      nob-sme.%: nob.f sme.f nob.txt sme.txt pos/%
              ./something --pos=$* --f1=nob.f --f2=sme.f nob.txt sme.txt > $@
    

Fortunately I haven't yet had to do this for anything too large to just copy-
paste stuff, but it feels like something someone would have solved at some
point, I've just never seen examples like that in any of the make-alternatives
I've looked at.

~~~
the_why_of_y
You can't have more than 1 pattern variable but if they are all of the same
form you can generate all these rules via $(eval); first define a function
that generates one rule, then invoke it for all combinations.

Unfortunately this sort of thing is not very readable because make function
parameters are numbered, not named.

    
    
      define genrule
      $(1)-$(2).$(3): $(1).f $(2).f $(1).txt $(2).txt pos/$(3)
        ./something --pos=$(3) --f1=$(1).f --f2=$(2).f $(1).txt $(2).txt > $$@
      
      endef
    
      $(foreach lang1,$(LANGS),\
         $(foreach lang2,$(filter-out $(lang1),$(LANGS)),\
             $(foreach pos,$(POS),\
                 $(eval $(call genrule,$(lang1),$(lang2),$(pos))))))

~~~
unhammer
Wow. I had no idea you could have that kind of meta-rules in make, nor am I
sure I really want to :-) but that's still pretty neat.

------
nathell
I wonder what this book's take on the classic Peter Miller's paper "Recursive
`make` considered harmful" [1] is.

[1]:
[http://aegis.sourceforge.net/auug97.pdf](http://aegis.sourceforge.net/auug97.pdf)

~~~
e12e
The sample chapter might give some hints:

[http://www.nostarch.com/download/GNU_Make_sample_ch4.pdf](http://www.nostarch.com/download/GNU_Make_sample_ch4.pdf)

------
teddyh
Please note: Despite the title, this is _not_ the official GNU Make manual,
and is not associated with the authors of GNU Make or its manual. (Just in
case anyone was confused.)

~~~
LukeShu
The author of the book is also the author of the more-confusingly-named "GNU
Make Standard Library" :)

That said, I'd bet money that Paul Smith (the maintainer of GNU Make) would
vouch for John Graham-Cumming's expertise.

------
legulere
I wonder why you would want to learn "GNU make" in contrast to POSIX make when
one of the advantages of make is that you have it on all unix systems.

~~~
pubby
What computers don't have access to GNU make? I don't see why you would give
up all those extra features in order to be a tiny bit more portable.

~~~
legulere
The BSDs don't use GNU make (OS X interestingly does). You can also install
other build systems, the advantage with posix make is that you don't have to
on unix systems.

~~~
swhipple
GNU make isn't part of the base system for the BSDs, but I've found that it is
often installed on BSD systems anyways (as gmake), due to much software having
a build dependency by using Makefiles with GNUisms.

If your project is targeting a generic POSIX environment with build tools
available and you want the portability, I can see why you might go with the
lowest common denominator. For a lot of projects though, there are additional
non-base dependencies (e.g. a python interpreter), and having a build
dependency on GNU make is usually acceptable if you're using the extra
features (e.g. % matching is a big convenience).

------
troydj
I'm waiting for jgrahamc to post a 40% off No Starch Press coupon code for the
loyal HN readers (in celebration of his newly-published book, that is :).

------
malkia
Btw, for people that are somehow stuck with Microsoft's make - "nmake" and its
syntax, but lack threading (e.g. make's -j), you should try out Qt projects
jom. It was mainly done so Qt and rest of the projects recompiles faster for
Windows. It can even integrated with Xoreax's IncrediBuild:

[http://wiki.qt.io/Jom](http://wiki.qt.io/Jom)

It's wonderful!

------
buro9
"having written a complete emulation of GNU make".

The conversation in the office on this is fascinating... writing a complete
emulation based on how the GNU Make Manual says
[https://www.gnu.org/software/make/manual/](https://www.gnu.org/software/make/manual/)
.

------
jonahx
I'm curious how many HN readers use make to manage their frontend builds,
similar to the process described here:

[http://www.sitepoint.com/using-gnu-make-front-end-
developmen...](http://www.sitepoint.com/using-gnu-make-front-end-development-
build-tool/)

~~~
bjt
I just did a project with a Python backend and JS single-page-app frontend. My
Makefile looks like this:
[https://gist.github.com/btubbs/c790111ff24357293ee2](https://gist.github.com/btubbs/c790111ff24357293ee2)

I'm happy so far. I'm an expert in neither make nor Grunt, but I'd still
rather write a Makefile than a Gruntfile.

------
ExpiredLink
Not to mention the proverbial simplicity of Unix utilities ...

------
Shorel
I need one of these but for cmake =)

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

~~~
bch
I remember _enjoying_ reading this book. If you're wanting/needing cmake
information, find a copy of this book. Hopefully you enjoy it as much as I
did.

