How I stopped worrying and loved Makefiles

gagor.pro

227 points by ___timor___ 14 days ago


frankwiles - 14 days ago

If you’re really looking for a tool to collect small steps/script I highly recommend you check out the ‘just’ cli tool. It’s completely replaced our use of Make and the syntax is much easier.

sam_bristow - 14 days ago

If you're going to use Makefiles as a top-level build wrapper you might be interested in self-documenting targets.

https://marmelab.com/blog/2016/02/29/auto-documented-makefil...

unmdplyr - 14 days ago

Even the slightest attempt at guessing the host system or searching for tools present on a system will quickly convert this into a blog article earnestly begging for deep societal changes and analyses the inevitable marching of time.

keyle - 14 days ago

I use makefiles a lot as make-do but I must admit the syntax does my head in at times. If anyone has a good resource that teaches makefile progressively, I'd be interested.

The main issue I have is that it goes from dead simple to pit of what the hell is happening with various things interacting with each others.

da-x - 14 days ago

This pattern of usage always seems like abuse.

When `make` is used as a glorified front-end to `bash` scriptlets, why not use `bash` directly instead of having two-level of scripting?

See: https://blog.aloni.org/posts/bash-functional-command-relay/

Mister_Snuggles - 14 days ago

My favourite (ab)use of `make` is as a batch runner: https://news.ycombinator.com/item?id=32441602

This (ab)use of `make` runs multiple times a day, every day, and works perfectly every time.

The inspiration of this was an (ab)use of `make` as a way to paralellize Linux system startup: https://web.archive.org/web/20110606144530/http://www.ibm.co...

matheusmoreira - 14 days ago

GNU Make is a surprisingly lisplike language. At some point I realized it had an eval function which I could use to metaprogram it. This actually ruined one of my projects, I got so lost trying to create the perfect makefile system that nothing short of a rewrite would fix it. As a side effect, I finally understood what autoconf's purpose was.

dissent - 14 days ago

One issue I don't hear mentioned often is reuse.

A task runner's tasks could be arbitrarily complicated, pulling in all sorts of dependencies of their own. This is less true for the traditional compile targets make was designed for.

Because the things we do in a Makefile are pretty much always project local and don't get reused, it limits how much heavy lifting these tasks are likely to do for us. Whereas if you built your our CLI in Python with Click or something, you would be able to make it a development dependency of your project. You can afford to invest in those tasks more because they'll be reused.

The Just command runner has the same problem, but at least it's designed to be a task runner.

yboris - 14 days ago

I don't like makefiles, but I've been enjoying justfiles: https://github.com/casey/just

lifthrasiir - 14 days ago

Ninja is simple and fast, but intentionally limited in order to not be programmable. Make is powerful and versatile (especially the GNU variant) but has an arcane syntax and lots of pitfalls. I feel that there is a niche between make and ninja for the task runner.

ris - 14 days ago

Unfortunately make's behaviour around dynamically setting variables/environment variables is insane and quickly leads you towards hairy eval commands with extremely tricky quoting & escaping.

Fire-Dragon-DoL - 14 days ago

What's the rationale for using makefiles as script runners over just having a directory with scripts inside?

Not for compiling, just as script runner.

I see this practice often and I haven't found a good reason

nesarkvechnep - 14 days ago

I’m tired of seeing articles full of examples of .PHONY targets. Make works with the file system!

liampulles - 13 days ago

I've gotten so used to using Makefiles with Go dev that for my other side projects with node, python, ruby, etc. I wrap the tools and commands I can't remember in a Makefile. A quick squizz after a few months away reminds me of how that environment works with building, testing, etc.

zokier - 13 days ago

The "Simple Makefile for Python projects" exemplifies why I dislike (ab)using make. It doesn't actually track deps properly, so venv doesn't get updated if requirements.txt changes, and nor does the dependency change tracking work properly for test target. To make it more correct you'd need bunch of .stamp files and/or globs, and even then it might be iffy. For lots of uses the simple file mtime based change/dep tracking is just too crude, and phony targets are largely an antipattern.

For script-running just is great, for full dep tracking build tool something like buck2 is an improvement.

The one place where make shines is when your workflow is truly file-based, so all steps can really be described as some variations of "transform file A to file B".

1oooqooq - 14 days ago

i always hated make. until i read the manual...

jaza - 14 days ago

Thanks! That article demystified quite a bit of the magic of Makefiles for me.

However, even after 10+ years of professional dev work during which I've regularly crossed paths with Makefiles, they still scare me, and I've still never written one from scratch myself. I cling to bash scripts, which I'm also a rookie at (or, for more complex cases, I write Python scripts, which I'm much more comfortable with).

I guess one day I'll read the manual, and digest some tutorials, and actually learn make. But I've made it this far...

akdor1154 - 14 days ago

I'd love some minor tweak of Make to compare/cache with hashes instead of mtime. A worse-is-better Bazel if you will.

ceving - 14 days ago

Most "modern" build tools do ruin make. Recently I did this for Go: https://gist.github.com/ceving/edeb6f58429d552e8828a70640db3... But it does not feel right.

web3-is-a-scam - 14 days ago

I’ve replaced my Make usage mostly with taskfile.dev and/or Warp workflows/notebooks

JohnFen - 12 days ago

There is quite a lot to love about make! I still haven't seen an alternative that is substantially better, and most are worse in one way or another.

My opinion may be a bit skewed by the fact that I write code that gets built on a variety of different platforms, though, and make is essentially universal. It lets me have a consistent build process regardless of platform.

It's also very useful for automation that isn't related to building code.

kevincox - 12 days ago

One minor tip is that you can define .PHONY multiple times. I find this much easier to manage because the .PHONY definition is right next to the target itself.

    .PHONY: foo
    foo:
        echo foo

    bar: barin
        cp barin bar

    .PHONY: baz
    baz: bar
        echo baz
lfmunoz4 - 12 days ago

For people using make and vscode my plugin is a must have:

https://marketplace.visualstudio.com/items?itemName=lfm.vsco...

It allows you to click above target to run target.

wodenokoto - 13 days ago

I'm a bit unsure what this does better than just calling those few lines directly in a shell script.

TheRealPomax - 14 days ago

The fact that make is basically useless on Windows still makes it "not the first thing to try", to be honest. And it's rare to still see a project that can't be cross-platform, only lots that went "well my computer runs XYZ so I'm only compiling on that" =)

john-tells-all - 13 days ago

I adore Makefiles as they're a very simple way to create a higher level abstraction in my projects. It builds data and runs small bits of code, so I can concentrate on the business-level value. I haven't found a better/simpler way that good old Makefiles.

shepherdjerred - 13 days ago

Make is excellent if you use it properly to model your dependencies. This works really well for languages like C/C++, but I think Make really struggles with languages like Go, JavaScript, and Python or when your using a large combination of technologies.

I've found Earthly [0] to be the _perfect_ tool to replace Make. It's a familiar syntax (combination of Dockerfiles + Makefiles). Every target is run in an isolated Docker container, and each target can copy files from other targets. This allows Earthly to perform caching and parallelization for free, and in addition you get lots of safety with containerization. I've been using Earthly for a couple of years now and I love it.

Some things I've built with it:

* At work [1], we use it to build Docker images for E2E testing. This includes building a Go project, our mkdocs documentation, our Vue UI, and a ton of little scripts all over the place for generating documentation, release notes, dependency information (like the licenses of our deps), etc.

* I used it to create my macOS cross compiler project [2].

* A project for playing a collaborative game of Pokemon on Discord [3]

IMO Makefiles are great if you have a few small targets. If you're looking at more than >50 lines, if your project uses many languages, or you need to run targets in a Docker container, then Earthly is a great choice.

[0]: https://earthly.dev/

[1]: https://p3m.dev/

[2]: https://github.com/shepherdjerred/macos-cross-compiler

[3]: https://github.com/shepherdjerred/discord-plays-pokemon

renewiltord - 14 days ago

Taskfiles are pretty cool. The tab/space things makes Makefiles painful for me.

IkemenSensei - 14 days ago

I learned to stop worrying about Makefiles and loved Rakefiles instead because they allow you to write Ruby code anytime you need to do slightly complex tasks.

banish-m4 - 14 days ago

For simple things, make is fine. It does file caching and the GNU tool does parallel concurrency.

For anything needing light-to-moderate software configuration management, cmake is readily available and simple.

If you're running a Google then you're using a build and DVCS that make use of extensive caching, synthetic filesystems, and tools that wrap other tools.

I won't say what not to use. ;)

xg15 - 13 days ago

Obligatory reminder that the phrase "How I stopped worrying and loved X" was supposed to be a sign of insanity, not an endorsement of X.

alhirzel - 14 days ago

> on my system binary is only 16kB in size,

I don't believe that.

DeathArrow - 14 days ago

$ make love

make: ** No rule to make target `love'. Stop.

lessbones - 14 days ago

tell me you've never seen Dr. Strangelove without telling me you've never seen Dr. Strangelove

throwaway290232 - 14 days ago

Makefiles fill that great need for a high-level 'scripting DSL', where you have a lot of different programs (or scripts), with a loose set of dependencies or order of operation, and you want a very simple way to call them, with some very simple logic determining the order, arguments to pass, parallelization, etc. Their ubiquity on all platforms makes it even easier to use them.

I much prefer Make to alternatives like Just or Taskfile. Besides the fact that more people know Make, Make actually has incredibly useful functionality that alternatives remove 'for simplicity', but then later you realize you want that functionality and go back to Make. Sometimes old tricks are the best tricks.