They can cause a lot of annoying bugs, and sometimes it's hard to track down where they are coming from (especially when dealing with stuff running in containers).
Like sudo for example.
So many problems related to that.
Of course it's a damn payment terminal, no one is ever going to actually build the app on the terminal so it has no compiler either.
I'm wondering what sort of dev machine GP has that is used to build software but doesn't have make...
I dare say that developers like environment variables more than before. Consider that Docker images, and hence Helm charts, are entirely controlled via environment variables. These very popular dev tools suffer from the same problem of having near-zero easy discoverability of what those environment variables might be. Yet they are very popular.
But I don't think Make usually uses all that many environment variables. You're usually specifying build targets as the command line arguments. Automake and autogen usually generate these makefiles with everything hard-coded.
Also, it makes it very easy to get started with, and it is universally available. Makes it very easy to like.
You could go for something closer to exactly what you want, but now you've got an extra set up step for devs and something else for people to learn if they want to change it.
I would say if you're looking for cli args then you shouldn't be using any wrapper like make at all. Just call the underlying tool directly. Make is for doing big high level things in the standard way, nowadays quite often in CI pipelines.
I personally like going to a project folder and run "make run", no matter what language or setup I have, to run the project. It enables me to unify access to projects.
I also take great care to make these runs reproducible, using lock files and other things of the ecosystems I am using, whenever possible. I work on another machine? git clone, make run. Or perhaps git clone, make init, make run.
I know, I know, what developer on windows uses git via the official git windows client, right? /s
Where it's less great is complicated recipes and debugging
Make excels at what it's design to do: specify a configurable DAG of tasks that generate artifacts, execute them, and automatically determine which subgraph requires updates and which can be skipped by reusing their artifacts.
I wonder: which tool do you believe does this better than Make?
But the Internet’s make mind-share means you still have to know make.
Edit: and make lets you use make to essentially run scripts/utils. People love to abuse make for that. Can’t do that with tup.
Sufficiently complex project need to invole alot of wierd extra scripts, and if a build system cannot fulfil it... the n it needs to be wrapped in a complex bash script anyway.
I don't think Tup managed to present any case. Glancing at the page, the only conceivable synthetic scenarios where they can present Tup in a positive light is built times of > 10k files, and only in a synthetic scenario involving recompiling partially built projects. And what's the upside of those synthetic scenarios? Shaving w couple of seconds in rebuilds? That's hardly a compelling scenario.
`tup` relies on a stateful database, which makes it incomparable to `make`.
does this happen to support IDE like vscode?
VSCode Extension
1. Open VSCode
2. Go to Extensions (Ctrl+Shift+X)
3. Search for "mbake Makefile Formatter"
4. Click Install* https://git.maandree.se/makel
Or unmake.
* https://crates.io/crates/unmake
Or checkmake.
* https://github.com/checkmake/checkmake (https://news.ycombinator.com/item?id=32460375)
Or make-audit.
* https://github.com/david-a-wheeler/make-audit
Or the Sublime linter for makefiles.
* https://github.com/giampaolo/SublimeLinter-contrib-makefile
It hasn't taken quite the 50 years that we are told, has it? (-:
group_phony_declarations = false
I think the visual clutter of .PHONY on each recipe declaration is better since there’s always a lot of copy-paste coding.It's hard to say what's intent and what not, maybe linters with many custom rules would work best.
It’s almost comical to see “why Python” comments after all these years. I would’ve chosen Go to write this, but that’s beside the point.
Yes, Python installation is tricky, dependency management is a mess (even with uv, since it’s not standard tooling; another one will pop up), and performance is atrocious. But even then, some Python libraries have bigger communities than the combined communities of all these “better, faster, more awesome” languages.
Python is here to stay. Newcomers love it because you need to know so little to get started. People don’t care about the little quirks when they begin, and eventually they just live with the warts. That’s fine. LLMs write better Python than Go (my preferred language, or whatever yours is). And if you know anything about the AI research community, it’s C++, C, Python or GTFO.
Going forward, a lot more tools will be written in Python, mostly by people entering the field. On top of that, there’s a huge number of active Python veterans churning out code faster than ever. The network effect keeps on giving.
So whatever language you have in mind, it’s going to be niche compared to Python or JS. I don’t like it either. But if languages and tools were chosen on merit instead of tribalism, we wouldn’t be in this JS clusterfuck on the web.
I'm not sure if this is news to you or if you already know it, but, just to be explicit -- you know that the overwhelming majority of end users aren't gonna have `pip` installed on their systems, right? And that any project with "Installation instructions" that begin with a `pip` command aren't really gonna work in the general case?
Just wanna make sure that's well-understood... it's fine if you wanna build a tool in Python, but if you expect it to be practically usable, you need to do distribution of binaries, not `pip` targets...
One of the reasons I write my tools in Go is exactly this. But if the tool was written in Go, people would complain about why not Rust and such. The point wasn’t to convey that Python doesn’t have its fair share of flaws, but to underscore that the HN crowd doesn’t represent any significant majority. The outside world keeps on using Python, and the number of Go or Rust users is most likely less than PyTorch or Scikit-learn users.
Shipping Python is hard and the language is slow. Also, tooling is bad. The newfangled ones are just a few in the long stream of ad hoc tooling over the past 20 years. Yet people write Python and will continue to do so. JS has a similar story, but it’s just a 10x worse language than Python.
There’s a famous one that does the same thing but is written in Python. So it has its issues.
My point is, pip exists in most machines. pip install sucks but it’s not the end of the world. HN crowd (including myself) has a tendency to beat around the bush about things that the majority don’t care about IRL.
A great PL should stand on its own without the need for external tooling.
At this point I have given up on python except for if it’s a little script that only uses standard libraries. Otherwise I’m choosing a compiled language.
Some more thoughts: http://calvinlc.com/p/2025/06/10/thank-you-and-goodbye-pytho...
For example instead of requests, you can use http.client, instead of flask, http.server, or socket.tcpserver, or just socket. If you want sqlite, don't jump to pip install sqlite or whatever, use sockets to talk to it.
If you had to use sqlite without library, you can trivially call the c api from python directly with the ctypes builtin (or compile a python module with c api)
https://www.gnu.org/software/make/manual/html_node/Phony-Tar...
I also use a similar pattern to provide a `help` target, which shows all targets, and a blurb about its purpose
The “make file” is all about file dependencies based on last modified date. Outdated target files can be rebuilt using source file. It’s is dependency management and the essence of an incremental compiler, but all revolving around files, not tasks.
At a certain point we seem to have stopped adding tools to POSIX.
Does anyone know why exactly?
POSIX-2024 added at least three new utilities: readlink, realpath, and timeout.[1] (It also added the gettext localization framework, which includes new C APIs and a few additional shell utilities.) Many utilities gained new flags and features, including Make. For example, POSIX Make now supports "!=" variable assignment for capturing shell command invocations, as well as guaranteed computed macro name evaluation (i.e. `$($(FOO).$(BAR))`). The latter actual gives a standards compliant way to implement conditionals, and interestingly had already been supported on all common Make implementations for a very long time.
These days anybody can meaningfully participate in POSIX. You can get started by checking out https://austingroupbugs.net/, where both errata and suggestions for new features can be added. There's also a mailing-list you can join, though most of the discourse happens in the ticket tracker. But please don't spam new feature requests, a la GitHub drive-bys. Spend a good amount of time understanding the specification and existing review processes, e.g. by reading alot of ticket discussions.
You can indeed shoehorn them into what you know but really you need to fully embrace their weird world.
See also forth, dc, awk, jq ...
It'd be nice to have a dedicated crash course on these things for people who understand conventional programming and have been doing the normal stuff for a number of years.
Also see supercollider, prolog, haskell, apl...
I think the most mainstream exotic bird people learn is Lisp. Doing all these things well is as different as Lisp is from say conventional python.
On Lisp, exotic? it's damn easy. Haskell it's far worse.
But most people don’t realize in many cases they can do better than that.
.PHONY: clean
all: $(TARGET)
$(CC) $(CFLAGS) -o $@ $^
.PHONY: install
clean:
rm -f *.o
And changes it to this with a consolidated .PHONY, but still no install target. Surely it should complain “there is no install target, what are you marking it as phoney³ for?” .PHONY: all clean install
all: $(TARGET)
$(CC) $(CFLAGS) -o $@ $^
clean:
rm -f *.o
I will not say that this way of writing it is unreasonable; users unfamiliar with the available targets can benefit from such a thing up the top (though in practice there’s normally a block of other stuff first, and other ways of achieving it). But this is also a reasonable way of writing it, with strong advantages of its own: .PHONY: all
all: $(TARGET)
$(CC) $(CFLAGS) -o $@ $^
.PHONY: clean
clean:
rm -f *.o
.PHONY: install
# Um… where’s the `install:` line?
Treating .PHONY as more an inline attribute like this rather than a target of its own makes it much more obvious that the install target is missing, and makes desynchronisation of .PHONY and the actual targets much less likely.—⁂—
¹ The first atrocity is that it’s not even a legal makefile: barring a .RECIPEPREFIX override, recipes must be indented by one tab. Running make with this file produces “Makefile:10: ** missing separator. Stop.” Taking invalid code and making it valid is not the domain of a linter or formatter. The Markdown is also abysmal because it doesn’t use tabs, but rather a single space in the output. Given that tabs are structural in makefiles, this is an astonishing lapse.
The second atrocity is the mismatching of .PHONY targets, despite joining the lines (by not having a blank line after the .PHONY line), which is completely unrealistic. Or at least I find it so.
² I have normalised whitespace so we can focus on the .PHONY changes. Assume tabs are where they need to be. Unfortunately HN hates interesting whitespace.
³ Ah, the number of times I’ve written .PHONEY… stupid americentric software.
A while back I attended an open-source conference (which was a lot of fun). After the presentations, people would "set up shop" at tables and jam on whatever was their fancy.
One evening there was a person using make as a SAT solver[0]. That blew my mind to be honest. I had used make for years as a build tool and never thought of it in that problem space.
This memory isn't relevant to this project. I was just reminded of the experience is all.
jtwaleson•7mo ago