Replacing make with python is a huge step back. The makefile language is simple yet extremely powerful for describing a dependency tree such as that for building an executable from sources. Its perhaps strongest point is that it completely agnostic to what the different steps actually do rather than consist of a predefined set of canned rules/tasks with, if you're lucky, a convoluted way of adding your own using e.g. python (or worse, java). This means that as long as a shell command can turn a set of inputs into an output, describing it takes (usually) just two lines of makefile, one naming the target and prerequisites, one providing the command to perform the transformation. If a particular rule is too complicated for a few shell commands, invoking a separate script (or even a just-built executable) is trivial. Every other system I've looked at needed a comparatively enormous amount of code for adding even the slightest tweak to the built-in rules.
GNU make is actually two different languages coexisting in the same file (the makefile), a declarative language for describing the targets and their dependencies as well as a functional language for the variables/macros. Once you realise this, a whole new world of possibilities opens up. If more people took the time to actually understand proper use of makefiles, perhaps we'd see fewer poorly reinvented wheels.
I've written a few complex Make based portable build systems over the years and in my experience Make script is its major limitation.
Make is a great system for declaring dependencies - the basic syntax is wonderfully concise (not that that's everything) and clear, and the system is a great platform on which you can build your build system (unlike Scons which tries to abstract away all sorts of things and just ends up hiding them).
The problem is that when you are trying to do anything more complicated than simple rules you are lacking basic language features. You don't even get function calls - the templates work under many circumstances, but not all (and are a pain to debug).
Also don't get me started on invisible syntax errors (tabs vs spaces), and the only error message Make has' Missing separator. Stop'.
Writing a build system in Python loses you that concise declaration syntax (but again characters typed isn't everything, as long as you maintain clarity it doesn't matter), but gets you ugh more flexibility to produce rules under complex circumstances, which saw at you need for portability.
Firstly, you call it "make script," suggesting that you view makefiles as a typical (procedural) script that is executed from top to bottom. I base this on my experiences working closely with others who also used the term "make script," all of whom suffered from this misconception.
Secondly, GNU make does have function calls. Look up the $(call ...) construct. When the built-in functionality is insufficient (and of course such cases come up), it is trivial to call an external script, written in your language of choice, using either the $(shell ...) syntax or as part of a target recipe.
As for the "Missing separator. Stop." it is not fair to dismiss an entire tool because of one slightly obscure error message.
I also find it ironic that you complain about tabs vs spaces, then go on to suggest using python, which also has invisible whitespace as part of its syntax.
It's obvious you have exactly 0 experience with waf, yet feel qualified to dismiss it based on objections you have against completely different make alternatives.
Make's rule system completely breaks down when you need to create a zip file of all *.c files in a directory tree. But it's a side-point, for complex software, build variants, configuration, installation and distribution are much harder problems to solve than dependency-based compilation. Waf is a replacement for the whole autotools suite, not for GNU make.
To bad I'm not using git. I still want a zip file of a directory. Really, don't say "use a command like" actually show me exactly how you would accomplish that task, using (gnu) make, in an efficient and cross-platform way without causing unnecessary target rebuilds. You can't? Now you see why make is insufficient.
Let's assume for sake of argument that you are right (although as ori_b shows, you are not). Why do you expect this functionality from _make_ specifically? Nobody ever claimed it can do everything. In fact, it's a good thing it doesn't even try to do tasks for which other, purpose-built tools exist. Creating compressed archives is a very different task from managing dependency graphs. Make was built for, and excels at, the latter. For the former there are better choices (and they can be called from make if need be).
> Creating compressed archives is a very different task from managing dependency graphs.
What? Creating a compressed archive is exactly the sort of thing that Make was designed for. A binary file or library, if you squint the right way, is just an archive of object files, which are just transformations of .c files.
Make's biggest problems for me (and the reason that I'm slowly gravitating towards writing a replacement for my own purposes) come from the fact that it can't handle inferring dependency graphs correctly. The usual 'gcc -M' hacks that work for C source don't work for code where dependency tracking is more than just an optimization. For C, remember, as long as you have the appropriate headers and .c files, you can build a .o file completely order-independent.
If you have a dependency digraph that looks like this:
a -> b, c, d
b -> c, d
c -> d
d
Then you need to build in this order:
d, c, b, a
Without some way of explicitly generating these dependencies ahead of time (which, I admit, is doable), you can't get make to do this properly. The best hack I can think of would look something like this:
depfile: $(SOURCES)
update-deps -o $@ $?
include depfile
But at that point, you're pretty much generating a makefile with another tool, scanning all changed sourcs, at which point you might as well move on to just building the DAG and running the build on them while you're at it.
Actually creating the archive is not make's job, which is what bjourne seems to be complaining about. Collecting a list of files and passing to a command is what make does. It doesn't care if that command is a compiler or an archiver, nor should it.
Regarding your chained dependencies, how do you expect _any_ tool to figure this out without either being told or examining the inputs (which implies knowledge of their formats)? Relegating this to an external tool seems perfectly appropriate to me.
Note, $? will only include the prerequisites that are newer than the zipfile, and therefore, will only update the files that have changed. You will not be re-zipping things repeatedly.
That's for trying, but 1. doesn't work unless you have zip installed, 2. doesn't recurse the whole directory tree, 3. doesn't rebuild the target if a file is renamed or deleted, 4. uses volatile time stamps instead of content hashes to detect targets needing update. And is GNU make specific. Then what if you want bz2 compression instead of zip?
1. Are you seriously complaining over make itself not creating the zip file, duplicating the functionality of the 'zip' tool?
2-3. This command does what you want: zip -R -FS foo.zip '*.c'
4. In practice timestamps work just fine unless you deliberately sabotage them. To use content hashes, the hashes of the input files when creating a target would need to be stored somewhere for future reference. This storage place could just as easily be corrupted. Make is a build tool, not a VCS. Treat it as such.
Yes, some things are specific to GNU make, but it is the de facto standard, something waf can only dream of. If you're going to complain about something being non-standard, your suggested alternative should be more of a standard, not less.
GNU make is actually two different languages coexisting in the same file (the makefile), a declarative language for describing the targets and their dependencies as well as a functional language for the variables/macros. Once you realise this, a whole new world of possibilities opens up. If more people took the time to actually understand proper use of makefiles, perhaps we'd see fewer poorly reinvented wheels.