

Do More and `make` Less with GNU Make and Less.js - martian
http://www.thumbtack.com/engineering/makefiles-for-less-and-css/

======
DSMan195276
This example seems to have a few issues with ordering and what
should/shouldn't have their own rules. In general, a good rule of thumb is
that _any_ file which is generated should have a coresponding rule to generate
it, whether or not that's a generic rule or a specefic rule. Also important,
rules should only generate the file they claim to generate (IE. If a rule
generates '%.c' and also happens to generate '%.d', it definitely shouldn't
act like it only generates '%.c' \- An exception can be made for temporary
files, but in general if they're not going to stick around you should remove
them when the rule is run anyway, or give them a proper rule if they're
sticking around). The biggest reasons for these rules is so that your rules
are honest about what they create (And this makes 'make clean' much easier to
implement), and the second is that at some point you'll need that generated
file somewhere else and won't have a rule to generate it on it's own.

The examples break these rules more then a couple of times. Their very last
examples won't work, because they generate the %.d file in the same rule that
is only supposed to generate the %.css file. Because of this, 'make' has no
way of figuring out what rule to run to create the %.d file, so the -include
will fail from the .d files not existing in the first run (-include and
include-file generation happen before the default rule is started, because it
happens at parsing time). Providing a separate %.d rule would fix this issue
(And also fix the issue that every time you compile your dependency info will
be generated again, even if it hasn't changed.). For example, if you wrote a
'make clean' which only cleaned the %.css files, all of the %.d files would be
generated again when you generate the %.css files, even though it's not
nessisary. There's also a small error that 'all' isn't the default rule to
run, the default is simply the first rule in the file. It's common to see
'all' defined high-up in a Makefile as something like 'all: real-all', where
'real-all' is defined below after other various things take place, and it does
the actual heavy lifting of kicking off the compilation.

~~~
cgrubb
> Providing a separate %.d rule would fix this issue

Yes. The following is an example of how to handle C header dependencies. It
could be adapted to build css from less and would be an improvement on the
blog post technique.

    
    
        sources := $(wildcard *.c)
    
        -include $(subst .c,.d,$(sources))
    
        %.d: %.c
            $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
            sed 's,\($*\)\.o[ :]*,\ 1.o $@ : ,g' < $@.$$$$ > $@; \
            rm -f $@.$$$$
    

It uses the fact that if you include a file which doesn't exist but for which
there is a rule to build it, GNU make will build it for you.

~~~
DSMan195276
Yep. Though with newer versions of gcc (I don't know how new though) you can
avoid the nasty sed stuff. I'm currently using this to generate my .d files
for C files:

    
    
        $(objtree)/%.d: $(srctree)/%.c
            @$(CC) -MM -MP -MF $@ $(CPPFLAGS) $< -MT $(objtree)/$*.o -MT $@
    

That generates a dependency file in the form:

    
    
        $(objtree)/%.o $(objtree)/%.d: (dependency list)
        (dependency-list-entry-1):
        (dependency-list-entry-2):
        etc...
    

It's pretty handy. Avoiding all the sed stuff is nice.

------
igl
I threw out all gulp/grunt fluff from my shelve after learning make and never
looked back. Makefiles are way smaller (40 vs 300 lines) and straight forward.
It reduced my npm install time from 40s to 10s. Builds may take 2 seconds
longer than gulp though.

------
Touche
> So, when there are so many build systems out there, why make? > * it is
> supported on almost all systems

Except the elephant in the room, Windows.

~~~
davexunit
GNU Make can be used on Windows. Of course, it's easiest to use it on
GNU/Linux or one of the other UNIX-like operating systems.

~~~
Touche
Yes but most Makefiles, including the one in this article, use commands that
do not work on Windows.

------
joshstrange
I really like make and use it when it makes sense but I'm failing to see the
advantages to doing something like this (other than support for make being
fairly ubiquitous).

To accomplish the same/similar thing with gulp in one of my projects:

    
    
        var gulp = require('gulp');
        var less = require('gulp-less');
        var concat = require('gulp-concat');
        var minifyCSS = require('gulp-minify-css');
        var rename = require('gulp-rename');
    
        gulp.task('styles', function() {
        	return gulp.src(['assets/styles/**/*.less'])
        		.pipe(less())
        		.pipe(concat('app.css'))
        		.pipe(rename({suffix: '.min'}))
        		.pipe(minifyCSS())
        		.pipe(gulp.dest('www/css/'))
        });
    
    

The make example is really cool but I'd be lost if I needed to modify it even
ever so slightly. Maybe this speaks more to my lack of experience using the
sed/tr/etc but make just seems more complicated to manage. That's just my two
cents.

------
callesgg
I generally like make and I got some nice tricks from the article.

However the resulting Makefile became a complete mess. Which unfortunately is
a very common problem one when it comes to Makefiles.

~~~
taeric
I would rephrase that as "Which, unfortunately, is a very common problem when
it comes to making software." The tool doesn't even seem to matter that much.
Typically one tool does a decent job at _something_ but then completely drops
the ball on other things.

Which I think is what plays to make's advantage. The one thing it does is
track dependencies between files and the shell commands it takes to make them.
The rest is punted to the shell commands.

