1. 23

  2. 3

    I think the fact that it’s mostly gmake-specific should be made more prominent.

    Disable magic

    Disagree. The magic is part of the “convention over configuration” idea in make. It’s what lets you do:

    $ ls Makefile
    ls: cannot access Makefile: No such file or directory
    zsh: exit 2     ls -F Makefile
    $ make foo
    cc     foo.c   -o foo
    $ cat >Makefile
    foo: foo.o bar.o
    $ touch bar.c
    $ make foo CFLAGS=-O2
    cc -O2   -c -o foo.o foo.c
    cc -O2   -c -o bar.o bar.c
    cc   foo.o bar.o   -o foo

    Neat, huh?

    Besides that, a good article. I use a similar approach, except that I tend to use less gmake-specific syntax unless I have a reason to give up portability.

    Everything discussed here should be possible to implement in BSD make.

    Everything discussed here, and much more, has been a standard part of BSD for decades, and I find BSD make better suited for this. It’s a shame we don’t have this luxury elsewhere.

    1. 1

      Configuration is typcially [sic] done with a small program, generally written in shell script, named configure.

      I’m always iffy on this sort of thing, but I realize there are times where you (at least seem to) need it. I honestly don’t know how to deal with it, but I’ve never liked the configure approach. autoconf has caused me no end of trouble and it’s pretty much un-debuggable. Writing your own configure script is like meeting the devil halfway.

      I’ve started to try working with a config.mk file that is only variables and have that adjusted manually. You use $(shell ...) when you need to and make sure it uses the := assignment to prevent multiple evaluations. That works alright and it’s what the suckless folks do as well. That said, the projects I’ve done this on are pretty small (although at work we have the basically the same approach, although we don’t have to worry about distributing the code).

      To turn them off, define an empty pseudorule: .SUFFIXES:

      This isn’t true of GNU Make 4.1, at least (see below). Also, I’m not sure you need to go to such lengths all the time. I say embrace the pattern rules and override them when you need them.

      $ make --version
      GNU Make 4.1
      $ echo "int main() { return 0; }" > t.c
      $ echo "SUFFIXES:" > Makefile
      $ make t.o
      cc    -c -o t.o t.c
      $ echo "%.o: %.c" > Makefile
      $ rm t.o
      $ make t.o
      make: *** No rule to make target 't.o'.  Stop.

      By the way, if you want to read a great resource on making advanced use of GNU Make, I can’t recommend John-Graham Cunning’s The GNU Make Book enough. One of the best tech books I’ve ever read. It changed the way I looked at Make.

      1. 2

        Flow control in make is pretty awkward. A ten line configure script that prints the right lines based on a few [ -f example.h ] && grep banana tests goes pretty far without any of the complexity of autoconf. Sometimes you can get by with config.mk, but it’s hard to write reusable functions. And if it’s going to be half $(shell), just write it in sh.

        1. 1

          Yeah, if the amount of $(shell) is too large, then it’s time for some sort of configure. But I’m not going to use it if I don’t have to.

          It all feels unsatisfactory, but that may just be the way it is for some time, so I probably just have to get used to it.