Make is such a horrifically awful thing to work with that I just end up using a regular scripting language for building. Why learn another language with all its eccentricities and footguns when I already know several others?
Because, like many other things in programming, you'll end up with a half-baked and buggy implementation of make anyways.
Incremental builds by looking for changed dependencies, a configuration file with its own significant identifiers (i.e. a build DSL shoehorned into JSON or YAML), generalized target rules, shelling out commands, sub-project builds, dry runs, dependencies for your own script, parallelization, and a unique tool with (making an generalization here) insufficient documentation.
If you're really unlucky, you'll even end up with the equivalent of a configure.sh to transpile one DSL and run environment into the DSL for your custom tool.
> Because, like many other things in programming, you'll end up with a half-baked and buggy implementation of make anyways.
I'd argue that make is a half-baked and buggy implementation of make - so that's not really a drawback so much as the status quo.
E.g. I have scripts that exist mainly to carefully select the "correct" version of make for a given project to deal with path normalization and bintools selection issues on windows - and none of these ~3 versions of make work on all our Makefiles. One of those versions appears to have some kind of IO bug - it'll invoke commands with random characters missing for sufficiently large Makefiles, which I've already gone over with a hex editor to make sure there wasn't some weird control characters or invisible whitespace that were to blame. So, buggy and brittle.
I'd argue that there are some major concerns with the makefiles if they require the use of 3 different versions of make to get it all working - a situation I've never personally seen before. I'd suggest prioritizing fixing that before attempting tracking down the cause of other issues. As it stands, there are too many points of interaction to attribute any bugs to any one program.
That said, Windows has never been a strong platform on which to run make (or git, gcc, or any other [u/li]nix originated CLI tools). When I hear of folks using make, I tend to make the assumption that they're running on a [u/li]nix or BSD derivative.
I've already had one upstream patch rejected on account of the additional complexity fixing it introduces, and would rather not indefinitely support my own fork of other people's build setups.
Or if I am going to indefinitely support my own fork, I might as well rewrite the build config to properly integrate with the rest of whatever build system I happen to be using - at least then I'll get unified build/compilation options etc.
That is, unless the folks who maintain and champion make want me to use make. It's on them to court me, the cross-platform developer, not the other way around.
I kind of disagree, it's quite possible to use gnu make on Windows with msys (though requires some scripting discipline and probably not for everyone).
I'm currently doing this for a cross platform c++ project. Same makefile used for Linux, Mac, and windows+msys+cl.exe. (yes, fair amount of extra variables and ifdefs to support the last one...)
Incremental builds. It's a pain in the ass to write this in a good, generic way yourself. If your build tools don't already understand it, then make (and similar tools) makes for a nice addition versus just a script that invokes everything every time.
EDIT: Oh, and parallel execution, but smart parallel execution. Independent tasks can be allowed to run simultaneously. Very useful when you have a lot of IO bound tasks. Like in compilation, or if you set it up to retrieve or transmit data over a network.
It's not too hard to do that in your custom script, but more care is required because until you custom script reaches make level internal complexity you will have to manually track dependencies or make sub-optimal assumptions.
I very much prefer Rake for orchestrating multiple build systems in a web project or dependency installation or just any sort of scripting. It comes with a simplified interface to shelling out that will print out the commands you are calling.
If for some reason the project is ruby allergic, I'll try to use Invoke [0].
Sometimes I feel like people's usage of Make in web projects is akin to someone taking an axe and hand saw out to break down a tree for firewood when there are multiple perfectly functioning chainsaws in the garage.
1) All dependencies are on only one output file (e.g. link stages that generate .map files, compile phases that generate separate .o and debug files). I just treat these as normal
2) I may need to depend on each of the files (I don't use yacc/bison, but it sounds like this would qualify). I select one file to be the main output and have the .do file for that ensure that the secondary outputs go to a mangled name; I then have the .do files for the secondary outputs rename the mangled file.
If the h output changes but the c doesn’t, this rule will miss it.
I once solved it by making a tar file or all the outputs and extracting it to both .c and .h but that’s incredibly kludgy, still looking for a better solution
As long as the timestamp changes on the C file, that's fine, right? At least with the version of redo I use timestamps are used by default, not file contents.
Do you honestly think Make has no advantages over conventional scripting languages when it comes to building software? I suspect you know that it’s designed for that task and has been used for that task for several decades. Presumably you respect the community over those decades sufficiently to have a strong prior belief that there are good arguments for Make (as well as downsides), even if you can’t be bothered to research them.
I honestly think any advantages it has are significantly outweighed by all its disadvantages.
And no, I don't respect the community. The community very often makes "The Way Things Are Done" its personal religion and refuses to ever change anything for the better.
Another advantage of using a scripting language is that the hard work of portability will already have been done for you by the authors of the scripting language.
Make, in contrast, works within a shell and invokes programs which may be either wildly or subtly incompatible across platforms. Add in the lacking support for conditionals in POSIX make and portability is a nightmare.
it is possible that if you need to do that much in a makefile that you are running into shell incompatibilities then perhaps you are attempting to cram too much complexity into your build system and perhaps should be using something like Docker to decrease incidences of “works on my machine/os/distro/et c”.
(I am aware that this advice does not hold true in all cases; just that for many of them overly complicated build systems is a code smell.)
To be fair, at the core much of what you're going to be doing is invoking command-line tools. I mean, most compilers are invoked as command-line tools.
because then people new to your project can see a makefile and know that “make” and “make test” and “make install” probably work without having to learn your homebrew, one-off build system.
I disagree. It’s an argument for convention. This is the same reason we have package.json or Dockerfile or Pipfile or Rakefile - it tells us the standard interface for “install this”. It’s not specific to make.
Docker is new and didn’t have any network effect until recently.