`make` is different things to different people. What you describe, `make` as a tool to compute optimal strategies for recursive file-based build operations, is indeed its original purpose.
On the other hand, I tend to use `make` more as a standardized format for script collections. Whenever I open a new repository, and it has a Makefile in it, I'm very thankful because it's a useful jumping-off point for how to build and use the software contained in the repository. Therefore I do the same in my own projects. Even if the project is in a single language with established conventions, I tend to include a Makefile regardless as a way of documenting.
For example, if I have a Go project, I could rely on other people looking into it to know how Go is compiled, or I can just put in a little Makefile like:
PREFIX = /usr
build/foo:
go build -ldflags '-s -w' -o $@ ./cmd/foo
install: build/foo
install -D -m 0755 build/foo "$(DESTDIR)$(PREFIX)/bin/foo"
.PHONY: build/foo install
Which will make it entirely obvious to everyone, including non-Go-developers, how to build and install the software.> There are also various limitations, caveats, &c. such that I typically had a "build.sh" or some-such that did any necessary pre-tup work.
Frankly if I need to write custom wrapper scripts for a build system then the build system isn't up to scratch. On every project I work on, you can run
make list
To get a list of targets, and build/install/predeps/deploy are all defined. On any of of our projects, make predeps && make build will output a deployable binary.> Calculating this outside of tup is fine even if it's expensive, as long as it changes rarely.
So no include files? That's another deal-breaker!
One example of what I'm talking about is what another commentor mentioned: .java files will generate separate .class files for each inner-class in the file, so given "foo.java" you can't tell which .class files will be output when compiling "foo.java" without looking at the contents of "foo.java"
I actually originally had a Makefile with predeps/build/install targets where the "build" step just called tup. People complained that "if tup is supposed to replace make, why are you using make?" I switched it to predeps.sh/build.sh/install.sh and everybody shut up. I personally think it's less ergonomic but don't care enough to argue with a different person every week.
I'm with you here!
Huh? This definitely does work with Tup as expected.
"make install" for example is specifically something Tup can't do.
This is trivially solved by having "install.sh"
There are also various limitations, caveats, &c. such that I typically had a "build.sh" or some-such that did any necessary pre-tup work.
The most restrictive rule is the set of output pathnames cannot depend on the contents of input files; they must be fully realizable from just the set of input pathnames. Calculating this outside of tup is fine even if it's expensive, as long as it changes rarely. Tup will error if the list is wrong, so you can't accidentally build with out-of-date outputs.