Phony Targets
gnu.org
gnu.org
For whatever reason, a makefile full of little baby shell scripts that are wired together seems cleaner and tidier and overall nicer to me.
Even ones that in no way at all ever depend on anything like a build state or looking to see if files have changed or whatever.
`make <action>` as the front-end to automate common tasks in my projects seems nicer than 15 shell scripts littering the top level of the repo, even if it is grossly underusing what make is capable of.
Makefiles can be horrendous when you encounter them in C projects, with all the templating and generation and what not. But just a single Makefile at the project root with phony targets for all common tasks is a godsend.
One pet peeve of mine is to make `make` the only requirement to bootstrap a project dev environment from scratch. Since make is so ubiquitous you can pull in just about any requirement and dependency with clever use of targets, order only prerequisites, and files.
Bash scripts used for these tasks tend to accrue a lot of boilerplate and every script has it's own conventions. So every time you need to debug them you need to debug a lot of code.
With make every target can be it's own little isolated piece of code with input and output which makes reasoning about them a lot easier.
A few tips when learning makefiles: terminology[0]: it's a lot easier to find answers if you know what it's called what you are searching for. Automatic Variables[1]: learn these by heart, and the way they allow DRY targets. If you have a dependecy that is not a file you can use a dot prefixed file as a proxy.
[0] https://www.gnu.org/software/make/manual/html_node/Rule-Synt... [1] https://www.gnu.org/software/make/manual/html_node/Automatic...
But when you are developing, typing "make" will rebuild the file you just edited plus anything that depends on the contents of that file (assuming a well written Makefile, which is not that hard to write for most cases). Trying to make that work in a bash script would involve lots of manually written tests, which would be easy to get wrong / get out of sync.
`just` doesn’t have the ubiquitous availability of `make`, but I’ve found it’s much more user friendly for this use case, especially with the documentation features and ability for commands to accept arguments.
> Mike Bostock
I strongly suspect that Golang choosing make is responsible for its reintroduction into the broad mainstream in the last 5-10 years. A lot of repos I interact with at work are full of makefiles.
Make is the bell bottoms of build tools.
The command to do so is trivial, but when do you need to actually execute it?
Normal make targets have prerequisites and outcomes (I think they are called goals). These must be files and make works by comparing their modification timestamps to see if a recipe has to be (re-)executed.
Now what is the prerequisite for your virtual environment?
What is the output? venv/bin/python ? What if you need to pip install some stuff (maybe only for testing)? What happens when the installation of a single package fails?
I think having a script (or a phony target for people with strange tastes ;) ) makes at least clear that there is no half-assed dependency tracking ongoing.
I think one way to figure this out would be to have a test script that runs inside the venv and outputs some kind of checksum.
venv/site-packages: requirements.txt pip install -r $< touch $@
It was very easy to update code, add new compilers and compiler options without rerunning benchmarks for everything. Only for what was changed.
Check it out: https://hackage.haskell.org/package/shake