1. 38
  1. 14

    Every project I touch gets a Makefile, regardless of its ecosystem.

    • make deps - installs dependencies and makes it so that I can run the other tasks if there’s not a clear way to make the other tasks depend on the deps task
    • make check - runs any linters
    • make build - builds any artifacts, may not necessarily run tests
    • make test - runs any tests, generally depends on build
    • make publish - publish the artifacts, if and only if certain environment variables are set; this ends up generally only working in on a CI system but there should be enough “code as documentation” herein to tell what happens when CI runs it

    Make is just kinda always available. It’s installed by ~default for Linux and macOS and *BSD. I rarely develop on Windows, and when I do, I get it with scoop install make. Things like just, xmake, ok, and whatnot are great but I’m still going to want make deps to install it somehow! A few of my projects’ make deps just runs brew bundle && pip install -U -r requirements.txt or brew bundle && peru sync.

    Side note: I like to use peru sometimes to retrieve dependencies when I don’t want to install a whole ecosystem, mostly npm packages with no/few dependencies.

    1. 2

      I used to do this, until I joined a team that was doing C++ (with Qt) and all Makefiles were autogenerated. :P

      Yes, if you are able to decide to have all your code in a src/ dir or whatever, it still works and in most of my personal projects I still do this.

      But even though I do this, I’m not sure it’s a good idea to push it in a team where everyone just does javascript and prefers their own way, you need to win people over with arguments, and “uniform everywhere” only works if there are projects in several languages, or several projects at all.

    2. 12

      Maybe your language ecosystem has a sweet build tool that can do all of the above. I’d love to be proven wrong, but as far as I know in Node.js (especially with Typescript), there isn’t.

      There’s a perfectly functional reimplementation of Make for JS called Jake. I’m more comfortable using that instead of Make for a JS/TS project because:

      • Make might be an unfamiliar tool for JS devs, and its syntax has tons of quirks. Jake is just plain JS, so anybody picking up the project won’t have issues figuring it out.
      • You have access to the Node stdlib and all the libraries you have in your node_modules, so you have no reason to use shell scripts. I don’t care what you wrote the other day in the “bully the guy who prefers to write their scripts in Node instead of shell” thread, JS is a strictly better language than shell, and since you’re using it for your project anyway all the arguments about dependencies are moot.
      • It works on Windows without issues. In the environment I work in it’s not uncommon to use Windows and I’d prefer not to force whoever comes next to work on my projects to use WSL or git bash or what have you.
      1. 10

        I use Make in all my projects just to leave breadcrumbs for my future self on how to get started if I revisit something old. Build systems and installed software come and go, Make is forever.

        1. 7

          Make is forever

          Yeah! You just gotta put the effort to learn it once and it’ll be useful and relevant forever for any build pipeline or task running. I’ve used it for programming languages, but I’ve also used it for a video pipeline with ffmpeg.

        2. 5

          The biggest gain of using make, for c/c++ developers is thar it doesn’t recompile what it doesn’t need. Which can represent a different of minutes to milliseconds.

          Using make just for its command interface is, IMO, just glorified and to some extent worse shellscripting. I personally would pick a shellscript. Command dependencies are trivially to implement.

          1. 4

            If someone uses make just for its command interface, the tool they really want is just. See What are the idiosyncrasies of Make that Just avoids?

            1. 4

              Let me agree 95%:

              The biggest gain of using Make for C/C++ development for any workflow is that it doesn’t redo what it doesn’t need. Fast and correct incremental builds has come to be – at least in the C/C++ realm – the defining characteristic of a buildsystem: If a no-change rebuild takes more than mere milliseconds, it is a bug, and if a buildsystem can’t do that, it is not a buildsystem.

              Make’s selling point nowadays is generality: Forget C/C++: In this niche, CMake and Meson are easier to use correctly, but Make can be used for everything that reads and writes files.

              Using Make just for its command interface may be innocent enough, but if you have recipes that do more than one command invocation, you are 100% definitely doing it wrong. This is what’s called a “glorified shellscript”, but the naming doesn’t matter: Because Make is so great, yet so horrible, it should either be used the beneficial way, by generating a target for every file, or that glorified shellscript recipe would be better off put in a script of its own.

              1. 1

                “What it doesn’t need”, in the case of make is defined as: what a typical C/C++ project on an unix environment doesn’t need. It doesn’t apply to most projects in most languages these days which have dependencies in the form of remote urls. Pretty much all of them.

                Make’s selling point nowadays is generality: Forget C/C++: In this niche, CMake and Meson are easier to use correctly, but Make can be used for everything that reads and writes files.

                It can be used for everything that reads and writes files as a worse replacement for shellscripts. Shells, which it very much relies upon. The advantages of make only manifest themselves under a set of conventions that are very much based on the GNU build system. How does it know what doesn’t need to be done in the presence of a home grown compiler?

                Using Make just for its command interface may be innocent enough, but if you have recipes that do more than one command invocation, you are 100% definitely doing it wrong.

                I’m confused. How is this a specific trait of make? It surely is trivially achievable with a shellscript.

                1. 3

                  How does it know what doesn’t need to be done in the presence of a home grown compiler?

                  That is a fundamental question! If you have ever written a makefile rule, that is how: You tell it for each output file which files it depends on. The deal is that whenever an output file is needed and is older than one of its inputs, its recipe is run again. Simple.

                  As you see, there is nothing special about home grown compilers or even downloading files from the internet. For something completely different, I’ve used Make to run custom tests and linters in parallel, migrate a vast number of customer databases, run video encoders and produce objective metrics of encoded videos. It is a true programming language. If your experience is more from generated makefiles (since you mention the GNU build system), I can see how this may not be obvious.

                  Then, you say that all of this is trivially achievable with a shellscript, which is true, but would miss the whole point of just expressing this dependency tree and have it rebuilt lazily with implicit parallelization. You don’t get that for free in many other languages!

            2. 4

              This is cool. I’ve just recently had to learn Make/Makefiles since I’m doing more C development lately, and I really like how flexible it is. And I stumbled on this Elixir/Phoenix forum post where someone uses Make instead of webpack, which feels much cleaner to me. I never realized you can use it for so many random tasks. Maybe I should have known that already, but I guess you live and learn.

              1. 4

                In Erlang universe exists Erlang.mk

              2. 3

                Where all the PHONY?

                1. 3

                  Make (is) love.

                  1. 2

                    From How it feels to learn JavaScript in 2016:

                    Makefiles? I thought that was mostly used on C or C++ projects.

                    Yeah, but apparently in the web we love making things complicated and then going back to the basics. We do that every year or so, just wait for it, we are going to do assembly in the web in a year or two.

                    1. 1

                      People reinvent the wheel, but some of the older tools are still alive and well.