1. 22

  2. 7

    I think this article is a specific instance of a more general principle: stick to de facto standards unless there’s a real need to stray. We’re not choosing from the set {Make, Ninja, Bazel, …} based on their merits; instead, we’re using Make unless one of {Ninja, Bazel, …} is compelling enough to choose. The article also says:

    If $OTHER_LANGUAGE has a tightly integrated build system, then you should use it. Make is not a good choice for those languages, with small exceptions for use as a dumb task runner on the periphery.

    In other words, try sticking to the standard; it just-so-happens that Make is the de facto standard for things like C. If something else is the standard, use that.

    1. 5

      Clicks link. It’s gonna be GNU make, it’s gonna be GNU make, it’s gonna be GNU make…

      (GNU) Make is probably fine


      1. 2

        Clicks link. Article is tagged ‘rant’, definitely a rant, yep it’s tagged ‘rant’ but here it is not.

        1. 2

          I agree. It’s just a series of counterpoints with lots of examples. The examples also let the reader judge for themselves. Rants usually have more rhetoric with fewer facts to check.

          Meta: I’d normally suggest remove rant. The author classified his own page as a rant on that page. calvin might have added rant here for consistency. I guess we leave it on to avoid confusing readers.

      2. 5

        I don’t know why he tagged it a rant. Maybe is because I’ve been working with with GNU make since I started in computing but the post is pretty reasonable.

        I understand many of the complains of people not used to make, but I found few complains that are specific to make and do not apply to other building systems.

        1. 6

          If you’re after a simple task runner I suggest writing a shell script instead of a Makefile. One language* is much easier to deal with than two languages with conflicting syntax, even when that language is shell. Shell has functions! Loops! It’s already installed! You do lose parallel builds, but if that matters your project is too complex for Make anyway.

          When your shell script grows too large — a few hundred lines — rewrite it in your favorite scripting language. Something like Python will be easier for new collaborators members to understand than shell or Make.

          At this point, you might consider if you need a build system. Maybe you do.

          Whatever you do, don’t try to abstract a Makefile beyond simple pattern rules. If you find yourself using define and $(eval), generating files to include, or using target-specific variables you should ditch Make as quickly as possible before the cyst grows.

          * Well, four.

          1. 11

            Hmm I dunno. I really like the declarative dependency stuff in Make, and I would hate to lose it, or have to reinvent it, in shell.

            1. 2

              I found out about Just last week and it fixes quite a few warts of make, and was actually designed to be a task runner. It’s worth having a look!

              1. 2

                It looks great, thanks for the link. Reposted here: https://lobste.rs/s/bvbglo/casey_just_just_command_runner

            2. 2

              Idk why people write posts like this. Ok keep using it, but make is fucking as fuck.

              1. 0

                One unsaid disadvantage is, that your makefiles will most probably slowly grow and accumulate cruft when you’re not looking. At some later point in time, you may still understand what they’re doing, but no one else will. (That said, it doesn’t mean you’re automatically free from this concern with other build systems.)

                Another one is, IIRC, that make does not detect (and rebuild) when you remove a dependency file from disk. So, you’ll think the project still builds OK, until it hits your CI. Ah, you have no CI? Then until it hits your co-developer’s build time. Ah, you have no co-developer? Then, you might not realize you’ve broken your source control for a few years.

                1. 3

                  make does not detect (and rebuild) when you remove a dependency file from disk

                  Can you explain this one in more detail? I’m seeing a different result when I test it:


                  hi : hi.o
                  hi.o : hi.c hi.h


                  #include "hi.h"
                  int main(void)
                  	return 0;


                  /* hi */

                  Now run this

                  $ make
                  cc    -c -o hi.o hi.c
                  cc   hi.o   -o hi
                  $ rm hi.h
                  $ make
                  make: *** No rule to make target `hi.h', needed by `hi.o'.  Stop.
                  1. 2

                    I think what parent says applies when the rules use a glob pattern which is quite common in Makefiles as far as I know.

                    1. 1

                      The solution is to never use glob. Just specify all your source/object files in a variable.

                    2. 1

                      Sorry, my recollection of the exact details is murky, I’m not an active user of make currently, and I remember the scenario may be somewhat tricky. I tried googling around with some keywords. Given that one doesn’t usually manage .h dependencies by hand, as they change too much, and instead defers it to gcc -MM, I found for example this description: https://stackoverflow.com/q/239004 Maybe that’s the issue? Sorry if you see my claims as FUDish. I think I’m right, but it was really long ago, so I can just close my mouth if that’s preferable. Otherwise, if someone knows what I’m trying to recall, I’d be super grateful for chiming in.

                      1. 3

                        It is certainly possible to write makefiles that don’t work with fresh source checkouts, but that’s possible with literally any build system. I don’t think you’re wrong, just overstating the problem a bit. And the fix is usually pretty easy: do a clean checkout from time to time and test that it builds. “A few years” seems a bit excessive.

                        1. 2

                          I would add “to a parallel make” as well. I’ve had projects build fine if done serially, but a parallel build would break. That happens if the dependencies aren’t specified correctly.

                          1. 1

                            Void Linux packages have an optional variable to disable parallel make for exactly this reason