4 ms·
A shell wrapper could do that, but Makefiles are a DSL to do exactly that with less boilerplate.
by dymk 4y ago
A shell wrapper could do that, but Makefiles are a DSL to do exactly that with less boilerplate.
- marcosdumay 4y agoAnd have a nice inbuilt graph runner if you decide one task depends on another...
- tom_ 4y agoComplete with automatic parallelization if you ask for it! And automatic KEY=VALUE command line parsing, default echoing of commands (easily silenced), default barf on subprocess failure (easily bypassed). The variable system also interacts reasonably sensibly with the environment. I've never rated Make for building C programs, but it's pretty good as a convenient cross-platform shell-agnostic task runner. There are also several minimal-dependency builds for Windows, that mean you can just add the exe to your repo and forget about it.
- marcosdumay 4y agoTo tell the truth, make sucks incredibly for building modern C programs. There are just too many targets. It's why all of them generate their makefile with some abomination. But it is still a great task runner.
- natrys 4y agoTbf, that particularity is easily achieved in shell scripts too: task1() { echo hello } task2() { task1() echo world } "$@"
- garblegarble 4y agoBut now update it to not re-run tasks unnecessarily - it's already wordier than a shell script right now. Meanwhile, in Make that's task1: echo hello task2: task1 echo world
- natrys 4y agoTrue, that's where Make shines. Though given the popularity of so many Make alternatives (the strictly subset of command runner variety, like just[1]) who keep its syntax but not this mechanism, I wonder if for command runner unnecessarily re-running dependencies is really a big deal. Because quite often the tasks are simple and idempotent anyway, and then it's a bit of a hassle to artificially back the target by a dummy file in Make (which your example doesn't do here e.g.). [1] https://github.com/casey/just https://github.com/casey/just
- Izkata 4y ago> I wonder if for command runner unnecessarily re-running dependencies is really a big deal. I've used in in the past with python/django roughly like so (untested from memory, there may be a "last modified" bug in here that still makes something run unnecessarily): .PHONY: runserver environ: python -m venv $@ environ/lib: requirements | environ . environ/bin/activate && pip install -r $< touch $@ runserver: | environ/lib . environ/bin/activate && python manage.py runserver [foo] Setting up these prerequisites takes a while and doing every time you start the dev server would be a pain, but not doing it and forgetting when requirements were updated is also a pain. This would handle both.
- datashaman 4y agoWhat is the | doing in the dependencies?
- Izkata 4y agoSpecifies order without a hard more-recent-than dependency on everything after the |. So if the timestamp on "environ" is updated, that won't cause the "environ/lib" recipe to run, but if they both have to run then it ensures "environ" happens before "environ/lib". It might not be necessary for this example, but I've found being more liberal with this feature and manually using "touch" has been more reliable in stopping unnecessary re-runs when the recipe target and dependency are directories instead of just files.