points by obezyian 7 days ago

Articles like this one are more likely to drive people away from make(1) than teach them to appreciate it.

This Makefile is anything but simple. It uses advanced features that are meant for complicated situations, just to create a few symlinks. The same symlinks, every time. And if you introduce a new dotfile to the repo, you have to update the Makefile too.

It also makes no use of the main feature of make(1) - to track files for changes, and update them.

For demonstration, here is the same functionality, in sh(1):

  files=$(find files -type f | sed s=^files/==)
  echo "$files" | sed s=[^/]*\$== | sort -u | { cd; xargs mkdir -p; }
  echo "$files" | xargs -I{} -n1 ln -sf $PWD/files/{} ~/{}
Doesn't use advanced features, shorter, and you don't need to update the script for new dotfiles. And more "ubiquitous" than GNU make.
globular-toast 7 days ago

What's funny is people use make as just an imperative task runner. For some reason people prefer to write a makefile with 10 commands rather than write 10 short shell scripts.

The real point of make is it's a declarative build system. You just tell it to make and it will do what needs to be done by figuring out dependencies and rebuilds.

  • cassianoleal 6 days ago

    Make is also a highly discoverable entry point to a project.

    A Makefile with tasks that just run external scripts is much easier to find than the scripts directly. Add some help texts and it’s a great DevEx multiplier.

    • Ferret7446 5 days ago

      As opposed to bash scripts documented in a README file, that will be understood by more people and not have to deal with the quirks of make?

      • cassianoleal 5 days ago

        Yes.

        With a Makefile I can generally just run `make` or `make <tab>` to have a feel for what's available. It's right there on my terminal, which is usually the first thing I interact with when I open a repository. If enough of the engineers use it, it stays up-to-date as it gets fixed and updated along with any other changes.

        Documentation OTOH has a tendency to be forgotten and left for dead. IME this is especially true for internal documentation, and the closest to the code the docs are, the less attention they receive - since higher level documentation is more likely to be consumed by people outside of the team.

        With a README, I need to:

        * remember to read it * trust that it will have the information * trust that the information is up-to-date * finally, figure out paths to scripts, arguments and/or copy-paste commands

      • sudahtigabulan 5 days ago

        INSTALL is also a standard location, for the commands that are related to building and installing the software.

  • blop 6 days ago

    I think people like using makefile as a simple task runner because it's pretty much ubiquitous and also a kind of auto-descriptive standard. Interactive shells usually do autocompletion on makefile targets so it's easy to see what you can run on a project (more so on old or foreign projects)

matheusmoreira 4 days ago

> And if you introduce a new dotfile to the repo, you have to update the Makefile too.

Not at all. The rules are generic. I can give make any path inside my home directory and it will try to match it against an equivalent file in the repository.

  $ make /home/matheus/.vimrc
  ln -snf /home/matheus/.files/~/.vimrc /home/matheus/.vimrc
I only need to update the makefile if I want easy to use phony targets. These phony targets in turn simply depend on the paths to the real files which activate the generic rules I described in the article.

It looks complicated because I used functions to compute all these paths from the items in the repository. Here's what the final result looks like:

  $ phony-targets GNUmakefile
  git
          /home/matheus/.config/git/config
  mpv
          /home/matheus/.config/mpv/mpv.conf
  vim
          /home/matheus/.vimrc
  # ...
I could have used any of those paths and it would have worked. The phony targets are nice but not strictly needed.

The bulk of the makefile is dealing with environment variables such as XDG_*_HOME and GNUPGHOME variables which affect where the links are supposed to end up.

lloeki 7 days ago

> This Makefile is anything but simple.

This makefile does look simple to me, although it is not easy; but TFA never claimed it was supposed to be "easy".

The shell you mentioned is not in any way "simpler" nor even "easier". The same thing can be done with bash substitutions and loops (all supported by zsh), and someone would argue that it'd be simpler by virtue of not suffering e.g gnu vs bsd vs posix sed nor needing xargs; also, pipefail and such.

Also it doesn't do "the same thing": you have to be at a specific pwd and not in any subdir + you can't do a subset (e.g "make git")

Note I'm not saying it's better or worse.

I really like the article as it showcased a few advanced make features in a concrete and limited use case (symlinks). The result is simple to use and maintain.

  • obezyian 7 days ago

    > but TFA never claimed it was supposed to be "easy".

    TFA> Another reason to use it is this turned out to be a surprisingly easy task.

    • lloeki 6 days ago

      I stand corrected.

      • matheusmoreira 3 days ago

        I suppose I'm biased. I'm used metaprogramming it by now.

        I'm very prone to being entranced by the eerily lisp-like nature of GNU Make. Got side tracked in one of my projects trying to recreate GNU autoconf inside it. That was the day I finally understood what autoconf was even doing.

robenkleene 6 days ago

Adding to the sh implementation, `find -L "$HOME" -maxdepth 1 -type l -exec rm {} +` will clean up dead symlinks in your home directory, e.g., if a dotfile is deleted because it's not needed anymore.