1. The syntax is very complex
2. It's just a wrapper around shell command execution
3. There's no single standard everyone fully implements
If I implemented a makefile then I'd have to make sure it's compatible with MacOS and GNU Make. The syntax for make files and target deps are also very complex "Do I want to use % or $ or @?" Make also implements very few pieces of functionality. It forks out SHELL for most things and because of this you need to have everything your makefile is using installed on your system. If you have a makefile, invariably, someone implements some tool that's super helpful and works.... until it doesn't. It depends on some system configuration or utility that is no longer a dep of something you've manually installed and the makefile breaks. If you use containers for all of your functionality this is no longer an issue because you can vendor base layers of OSs/images and make sure they don't break. You can also test these changes, that could be breaking, without rolling out to other developers. I cannot test if my Makefile will run on a developer's mac if I don't have a mac myself and even then it's a crap shoot (do they have homebrew? is their PATH correct? etc).How is this any more complex than any programming language? Take javascript. Do I want to use =, ==, or ===?
> I cannot test if my Makefile will run on a developer's mac if I don't have a mac myself and even then it's a crap shoot (do they have homebrew? is their PATH correct? etc).
Containers suffer from these kinds of problems as well. For example, if your ip tables are not set up just so, you get no network access from inside your container.
Or you can just make everyone wrap their build tools in make.
Make is not a "wrapper" it's a "translucent layer on top of" since it doesn't hide the deps on the underlying tools.
When I do `docker build -t ... something` or `bazel build //something` I don't need to care if it's node, C++, Java, etc. I just need to know that it is a thing that I want to build. Make cannot deliver that to you as you need all of your system toolchains installed and you need to make sure your makefile works on every OS/system config.
For me, that's kinda the point. If (when!) the underlying layers break, I can open up the Makefile and see exactly what was called, without too much abstraction. It's not there to provide complex build options, it's to provide aliases to the commonly used commands in a platform agnostic way.
Most of my make commands are simply aliases for one or more commands, which are often something like `docker run --rm -it project_runner_image some_command`
There's some real problems with Makefiles in the form of tabs as the prefix, running everything as a shell, weird platform specific versions, etc - but I've yet to see anything else which is as small, as universally available, with such a low barrier to entry. Most of the other options I've seen so far (and I'll be the first to admit I haven't looked very hard) seemed to either be overly complex for simple dev setups, or bound to a particular language.
I agree that blaze is the better option, but all the benefits it provides comes with a greater up-front cost, where its not necessarily possible to drop-in on a project and run with. Also notable is that blaze is inspired by and is a replacement for make. So in a lot of ways, make is a poor mans blaze now.
Just learn it then? Running make commands is trivial. Writing basic make targets is trivial too.
[1] Yes, our Makefiles sometimes call docker/npm/ant/maven/gradle/cargo under the hood. Its been worth it, in my experience. One syntax on all projects to set up the workspace, refresh dependencies, deploy to dev env, clean, etc.
Actually I find most answers either in official documentation or on StackExchange sites. And I much prefer digging in mailing lists over digging in GitHub issues. You access both over web anyway.