![]() |
|
![]() |
| > One of the things that makes make a great tool is how deceptively simple it is.
One of the worst things of Make is how deceptively simple it looks. Make does exactly one thing: it takes input files, some dependencies and generates _exactly_one_ output file. To have rules which don't generate output (like `install` or `all` or `clean` or all targets in the article) we need to resort to a hack, a special magic target like `.PHONY` (which hasn't been part of POSIX up to the 2017 version - IEEE Std 1003.1-2017 - https://pubs.opengroup.org/onlinepubs/9699919799/utilities/m..., only the current one - IEEE Std 1003.1-2024 - https://pubs.opengroup.org/onlinepubs/9799919799/utilities/m... includes `.PHONY`). If you want to generate more than one file (like an object file and a module or a precompiled header or ...) you are on your own to build some brittle hack to get that working. Don't forget that not every Make is GNU Make, BSD and other nix like Solaris/Illumos still exist. Don't get me wrong: Make has it's uses for sufficiently complex projects which aren't too complex yet to need some "better" build system. Problem is that such projects may get too complex when more code is added and they inevitably gain some sort of scripts/programs to generate Makefiles or parts of Makefiles (so, an ad hoc meta build system is created). And the problem isn't that they use it, but that they are proposing it as a solution to "everybody". And that their Makefile stops working as soon as there is a directory (or file) `build` (or `dev` or ...) in the project root. |
![]() |
| I work on a project with 4.4 million lines of code and using a single Makefile with no generated code works fine. It's really not all that difficult. |
![]() |
| > My Makefile is portable.
Oh yes, in the good old tradition of "... as long as it's some Linux on x86".
Sorry, it's actually AMD64 _and_ ARM64! |
![]() |
| > Projects of much smaller sizes often have recursive convoluted makefiles.
You name any technology and anyone can enumerate dozens of projects that use it wrong. |
![]() |
| WSL basically runs GNU/Linux distributions so I fail to see the significance of that point.
And for MacOS you do the same thing, you get them to use their beloved homebrew to install GNU Make. |
![]() |
| Why would they do this? I could understand using a non-GPL make because they hate it, but using an ancient GNU make is just handicapping your users for no gain. |
![]() |
| Yeah I've been following Buck2. Definitely interesting.
Xmake looks interesting too (even though I hate Lua). I wonder why it isn't more popular - I don't think I've seen a single project use it. |
![]() |
| In my PS script solution, I just added a clean option+command.
I rewrote my makefile in PS and don't miss anything from make and have no regrets, as it is simpler now. |
![]() |
| Who develops just? Will it be around in 5 years? Will it be ad supported? Will the developer sell my data? Etc.
I don't have any of those concerns with GNU Make. |
![]() |
| I believe you to be correct. I think it's important that one uses the right tool for the job, regardless of whether or not it's widely adopted or supported. |
![]() |
| > but it works
That it what a lot of SW developers forget: your code might be the best in the world, but , if someone is not able to build it, it is useless. |
![]() |
| > Because it isn't fun checking if the whitespace at the beginning of the line is a tab or spaces. And as said, you must know when to use tabs and/or spaces in rules.
that's why https://editorconfig.org/ exists, so that neither you nor your teammates have to think about these things |
![]() |
| why do you need a "command runner"? Have you heard of bash functions? Or... make? The thing is too simple to justify installing another tool, however nifty it is. |
![]() |
| There isn’t even a need for a shell script. The author is already invoking three separate tools, each of which has a mechanism for invoking custom commands. |
![]() |
| Sure but these are completely orthogonal to make. Might as well complain about gcc.
If anything, it's an argument for making better use of make's own features for configuration in the first place. |
![]() |
| A big mistake Make has is mixing phony and file targets in the same namespace. They should be distinguishable by name, e.g. phony targets start with a : or something.
Too late of course. |
![]() |
| At that point wouldn't you "just" download the source and compile locally? Since you presumably could compile stuff. Add a 'bin' folder in your home directory to your PATH and enjoy. |
![]() |
| It's funny such a simple title inspired a flamewar. The article itself is an insanely simple use case for make (that uses gulp in 2024?) that clearly no one read. |
![]() |
| > cargo is a bad example as it's universally `cargo build`.
Except if you want to use some specific feature. Or specific log level. Or build a specific crate in a workspace. Or... |
![]() |
| Who even implements an alternative implementation to GNU make? FWIW, no one "can't" use GNU make... even Apple uses GNU make (hell: they even ship GNU make, lol). |
![]() |
| I used to hate makefiles, but really I just hated the way C/C++ make it a manual task to decide what to compile, as opposed to something like Python modules.
Now I love Make, for non-C work. |
![]() |
| Make files: it’s a good build system in the same sense C is a good programming language. It’s also a terrible build system for the same reasons C is a terrible programming language. |
![]() |
| Just really is great, you should just give just a try. I put all the project-specific incantations in my Justfile and save my teammates lots of typing and copy-pasta. |
![]() |
| Make has been my favourite unix tool for years and a really useful tool to have in your pocket. It’s simple, elegant, and powerful. |
![]() |
| The correct answer is I don’t like makefiles when they are abused. They have no state yet people try use them as such and create pain for others. |
![]() |
| I also use make this way and have done for years. I even have the same kind of religious ritual the author has, like writing the Makefile is part of setting up the codebase and organising in my own head how the whole local dev environment is going to work.
The only thing is, this isn't what make is actually for. A number of commenters have recommended Just - the one I've been using on my personal projects is Task - https://taskfile.dev/ - which is pretty great. As other commenters have said, the problem is that make is installed everywhere already. I would love to see a task runner become standard to the same extent, and will have a look at Just if that's the one people are using. |
![]() |
| Thing is, make is not readily available on windows. It should’ve been in git bash, in my opinion, but just fills the gap in a cross-platform way |
![]() |
| While these npm examples are easy to grasp, they do not reflect any strength of Make. With same success one could use package.json's script property, code would be pretty much identical. |
![]() |
| I really was surprised that the main concern in the comments here was about the missing .PHONY.
And kudos for this article that gives a point of view, then fixes the main HN concern ;-) |
![]() |
| As a guy who doesn’t write code, but reads a lot of it, Makefiles have always been a PITA to deal with. But less so than cmake or other build systems. |
![]() |
| In my first job out of university, I inherited a data pipeline that had been written in Make using ~40 Makefiles. Needless to say, it was a hell to debug. |
![]() |
| Yup, I was sat here thinking "anyone complaining about Make really should go away and try using ant, then return here in a few hours licking their wounds, repentant". |
![]() |
| Makefiles are an eerily lisplike turing tarpit. I hand wrote the makefiles for my projects, they generate wonderfully organized build trees. Hell I use makefiles to manage my dotfiles repository, even blogged about it.
https://www.matheusmoreira.com/articles/managing-dotfiles-wi... The sanest way I've found to write makefiles is to think of it as a tool that maps input paths to output paths. When compiling a program, I want to map source/program.c to build/$(config)/objects/program.o so I write pattern rules that do just that.
Then I write make functions to convert paths in some tree to paths in another tree, which makes it easy to create lists of files which then match the pattern rules.
These functions are then augmented by lots and lots of project specific variables to organize things...
Then I add a real target which is supposed to get the makefile going.
Then I add a phony target for it.
Then typing "make program" triggers the rule to make build/$(config)/program which depends on all the object files which will be linked into it which in turn is derived from a dynamically computed list of source files, and making those object files triggers the pattern rule which builds the entire thing.Using make without phony targets is insane. Without phony targets, I'd need to type things like "make build/aarch64/program" in order to get a build started. So I use phony targets for everything. Much easier to type "make program". It got to the point I created a phony-targets shell script which parses make's database output and processes it into a sort of help text for any given makefile's phony targets interface: https://github.com/matheusmoreira/.files/blob/master/~/.loca... |
Don't be discouraged by all the people in this thread saying you're using make wrong. One of the things that makes make a great tool is how deceptively simple it is. Yes not using .PHONY can potentially get you in trouble. But for a small project that's the sort of trap you'll fall into a year later, if at all, and even then you'll only be scratching your head for an hour. 99% of the time you don't have to care about doing things the proper way. Make lets you just hit the ground running and only imposes as much complexity as you need to keep the thing from falling apart.