So he's saying use 'make' instead of gulp/grunt and then he submits an example where it's as easy as piping through GCC.
He's making the wrong assumption that you don't need to setup a build environment when building with make, but to have gcc you will still also need to install g++ and build-tools. Also, he refers to building on Windows using yet another specialist tool, but have you recently tried building anything C++ on Windows when you don't have visual studio, or even worse, CYGWIN installed?
When you make such a statement, then please show me a makefile that's not 10.000 lines long, that will do the same as this, but without NPM and 'downloading half of the internet'.
gulp.task('scripts', function() {
// Minify and copy all JavaScript (except vendor scripts)
return gulp.src(paths.scripts)
.pipe(coffee())
.pipe(uglify())
.pipe(concat('all.min.js'))
.pipe(gulp.dest('build/js'));
});
I submit that's impossible, simply because this stuff took 2 years to evolve (for the Javascript toolchain, that is) and a lot of people went through hours of frustration trying out alternative methods.
I'm not that familiar with grunt. Can it do the equivalent of make -j4?
PS. I'll happily agree that collecting the list of script files to operate on -- and the list of script files after the transformation (eg $(UGLY)) -- is slightly annoying in make.
-j4 says use up to 4 processes in parallel. Make has a jobserver that does parallelism safely with respect to the dependency graph. So for example, even if we have workers to spare, it won't try to build all.min.js until all of the .ugly files have finished building.
The %.foo : %.bar things are pattern rules. [1]
The $<, $@, and $^ things are called automatic variables. [2] They correspond to the first input file for a rule, the target file for a rule, and the complete list of input files for a rule, respectively. Cryptic at first but really handy.
This is Make 001: $@ is your output file, $^ are your inputs (prerequisites, technically), and $< is your first input file. They're unfortunately ungoogleable, but just remember that they're called "Automatic variables" in the GNU make documentation.
"-j4" means to run up to 4 jobs in parallel. It's orthogonal to the issues at hand.
There are 42,000 issues filed for make. if you could resolve each of these issues in 10 minutes, you'd spend 291 days of frustration.
http://savannah.gnu.org/bugs/?group=make
_make_ was first released in 1977, but that was the PWB/UNIX version. The GNU variant of make didn't come along until sometime in the 1980's. It's hard to pin down the exact date of the first release because the developers didn't keep good records prior to the switch from RCS to CVS. However, the earliest ChangeLog entry now is dated July 15, 1988, and 1985 is the earliest date mentioned in any copyright statement in any of the GNU make source files.
make is a general-purpose tool for describing dependencies for regenerating files. It would be worth your while to learn make, and try it on your example. Understand that it's a declarative language ("A depends on B"; when "B" changes, here's how to update "A"), and not a scripting tool. This is a good thing.
In my experience, make is coupled to Unix. Make is not coupled to C.
On one hand, make typically comes with built-in rules for .c targets.
On the other hand, make can't cleanly handle #include dependency detection. I doubt that there is any major C project where "make extraclean" (or its equivalent) isn't occasionally necessary.
Well, #include resolution would require that make be able to parse C, which would add a heck of a lot of complexity, and be unscalable. For instance, you'd need to modify make to parse CSS to teach it about @import, or to parse javascript to teach it about require() (but only if you're using RequireJS)
Or, you could use the C preprocessor option "-M" and its variants[0] to get it to generate make rules with C #include resolution for you.
See also Recursive Make Considered Harmful[1] for a good description on how to set up this in combination with GNU make's "include" facility to autogenerate your per-source #include resolution fragments.
In my experience, make is coupled to Unix. Make is not coupled to C.
However, implementations typically include magic that is heavily biased toward building C and C++ code. As someone who works on a lot of projects, some using those languages and some not, I tend to think it's rather too magical at times. Personally, I'd prefer to have that kind of magic explicitly stated in some standard file that comes with the tool, so that file can be included with a one-liner for those projects that want it but there is nothing implicit going on by default.
Have you ever wished there was one-character symbol for the word "pipe", like maybe '|'? Such a symbol would even make all those .'s and ()'s redundant. While we're at it, if our build script is going to be in its own specially-named file, wouldn't it be nice if instead of namespacing under 'gulp', within the special build script file there was a DSL where you could specify the task name and its dependencies with a single character, like ':'? And instead of 'function() { return ...; }', your instructions were delimited with just indentation, like a Tab character?
Your example proves the opposite of the point you're trying to make. Starting from your example and trying to compress it with a DSL, you literally couldn't do better than Make syntax: the "gulp.task('" part is implicit, the "', function() { return gulp.src(" part is a single character (':'), every ").pipe(" is a single character ('|'), and ").pipe(gulp.dest('...'))" is a single character ('>').
I submit that's impossible, simply because this stuff took 2 years to evolve...
Before and during the entirety of those 2 years Make has been a better tool, for those of us JS coders who didn't dismiss it offhand as being always thousands of lines and only for dinosaur C coders.
Make has many problems, but taking thousands of lines to simply pipe together commands has never been one of them. Having to write .pipe() where in shell you could just do '|' has never been one of them, either.
Quite the contrary: I've had to maintain or incorporate some non-standard build processes into several build systems (mostly scons, waf, gyp), and in each one it was difficult or impossible to express what I wanted because the build system wasn't as general as Make.
The single most valuable thing Make has going for it is that the primitive is a Unix pipeline. Anything that can be built with tools you can invoke from your shell can be built with Make, and the language of action is about as universal as it gets for Unix-like systems.
Yes, the dependency syntax is somewhat confusing, and it's not obvious how to understand and debug Makefiles at first glance, but the GNU make documentation is decent, and time spent learning the language and the tools (e.g., "make -d") is much better than trying to reinvent the system, especially without understanding it. Every reinvention I've had the displeasure of working with missed some important (if not widespread) use case.
I think he's saying that re-implementing make in ruby is a bad idea.
Not that I agree with him. Being able to do some printf debugging (or even use a real debugger!) to troubleshoot issues is a big plus that he doesn't mention.
Indeed. Responding to the fetishization of web technologies by fetishizing Unix utilities is missing the point. They're both tremendously important and tremendously useful, but trying to ignore their shortcomings doesn't help anything.
He's making the wrong assumption that you don't need to setup a build environment when building with make, but to have gcc you will still also need to install g++ and build-tools. Also, he refers to building on Windows using yet another specialist tool, but have you recently tried building anything C++ on Windows when you don't have visual studio, or even worse, CYGWIN installed?
When you make such a statement, then please show me a makefile that's not 10.000 lines long, that will do the same as this, but without NPM and 'downloading half of the internet'.
I submit that's impossible, simply because this stuff took 2 years to evolve (for the Javascript toolchain, that is) and a lot of people went through hours of frustration trying out alternative methods.