Why even use Make? I just use shell scripts for automation.
The only case where you really need the incremental behavior of Make is C/C++ builds (and arguably it's increasingly inappropriate for this domain as well). For all other kinds of automation I just use shell scripts, since Make is mostly a horribly reinvented shell script dialect.
I've spent the last couple of weeks playing the "front end build tool dance" (primarily a back end dev) to find a system I like and it simply never occurred to me I could write my own as a quick bash script or python if I think it'll grow.
Good :) Shell scripts will be around for a lot longer than any of those tools.
Shell is also significantly easier and faster, if you just want to say run jslint, then minify, etc.
I program in lots of languages, so shell is the first tool I reach for. Learning the language is enough; I don't have time for all these quirky build and deploy tools.
Build utilities like Grunt or Gulp will be hopefully more compatible across systems than shell scripts will be. I'm not too familiar with Node's support on various platforms, but I'd wager that it's probably decent.
Gruntfiles and Gulpfiles are in javascript too, which lowers the barrier for entry for developers who aren't as versed in linux.
Is there a shell script equivalent to npm? Sidenote, that could be really useful as a service.
For open-source JavaScript projects, using Grunt or another Node-based tool makes it easier for Windows users to contribute. Node has excellent Windows support, while shell scripts are mostly the domain of *nix.
Yeah. In the past three years I've gone from Windows, to a CentOS VM, to an Ubuntu VM, now on OS X. Node has worked on all of those platforms. I can't say the same for my .BAT files.
You can pack several shell scripts into one Makefile as .PHONY targets. You can share configuration values, subtasks between the tasks. It is somewhat easier to supply options to tasks e.g.:
make deploy SERVER=example.com
Shell syntax is horrible itself. Make doesn't add too much on top of that.
Make is the easiest way to map all .foo input files to .bar output files and have the outputs only rebuild when the inputs change. This has a ton of applications outside of C and C++, really anything where the build takes time.
A shell script cannot adequately express task dependencies, or one that did would become a build tool like make. As it stands, make has a very simple and light syntax for expressing dependencies and has remained useful with little modification for quite some time.
Make isn't necessarily the best automation tool, but it's a great build tool.
Not writing task dependencies is kind of a feature though, in a KISS way. One of the reasons I have been tending towards using stupid shell scripts is that its much easier to guarantee that everything is built correctly if you rebuild from scratch everytime. With make I often find myself dealing with bugs in the makefile due to forgetting to specify some dependency or things like that.
Saying that Make is a horribly implemented Shell dialect clearly seems like a misrepresentation of Make to me.
Make is a non-procedural way to describe the dependencies of your build process. You describe what you want as a result rather than the steps that the interpreter should follow.
It's possible to like or dislike this approach but it's clearly qualitatively different from Shell scripting.
I understand that distinction, but my point is that for automation like running jslint or minify, the dependencies aren't that necessary. Those commands don't take very long, and often don't have long dependency chains.
Make basically adds a very small "declarative" dependency layer, and then reimplements the shell poorly:
- variables (from the environment)
- command tokenization
- escaping rules
- functions
- if statements
- include
- globbing (in the target line)
- various magic $ variables
- process substitution
- eval
... etc.
That is, it's a full fledged programming language with different syntax than shell, but mostly the same features. I guess what might do in some cases is have a very simple "actions.sh" shell script, and then a Makefile which ONLY has simple command lines calling into actions.sh. Any functions would be in bash rather than make.
This is actually nice because there is an "upgrade path". For most simple things, you can just stick with shell. But when you need the power of make, you can upgrade without rewriting anything -- just adding a short/readable makefile.
I wrote my own completion for that :) Here is the pattern I use:
run.sh
build() {
...
}
test() {
...
}
deploy() {
...
}
# This lets you do ./run.sh build foo bar at the command
# line. The autocomplete scans for functions in .sh files
# and fills them in as the first arg.
"$@"
I've been using make myself. The main barrier I keep running into is that it's actually quite challenging to :
1. Use make/bash to work with things like JSON, mustache, images, markdown, less, sass, uglifyjs, etc. etc..
2. Do so in a way that is portable to even other unixish machines.
3. Why doesn't make provide an easy way to input a BIG LIST of files into a command? The choices (I'm aware of) are to put them all on one line, work out some wildcard (which doesn't work on arbitrary lists of files you need in a particular order), or--- have backslash escaped line endings! yuck!
nodejs isn't available in the debian stable packages repo. The available mustache command line tools are pathetically bad at this task (I had to write my own). I can make it work beautifully on my machine, but as soon as it hits my co-workers machine, the build breaks because they haven't installed pandoc, or ripmime, or whatever other utility I had to use to get things done.
So, I don't know, maybe I'm doing things wrong. But I haven't got this to work particularly well yet.
Well, to be fair, make and browserify do completely different jobs. You can't substitute browserify for make, nor vice versa.
But to be honest, if you see learning new things as wasting your attention on new fads, I don't think this stuff is for you. I really like trying new things that people have made and seeing what they can do. If that feels like a chore/hardship to you, you absolutely should just keep using make.
Believe it or not there are people in the world who aren't technical enough to use stuff like Make, and are perfectly fine with using tools like Grunt or Gulp to get them through their days. Mindblowing, I know.
Believe it or not there are people in the world who aren't technical enough to use Grunt or Gulp, because they are much more complicated than Make... Mindblowing, I know.
The makefile syntax is obscure and hard to maintain.
We've been there. We don't need to go there again.
The stories of 'recursive makefile dependency hell' deserve to stay back in the dark ages of the 90s where they belong.
There's a reason lots of people are inventing new systems for doing these sorts of tasks (for example, spawning a local webserver to work with after compiling less and coffee files and parsing the output for errors and displaying them nicely, then watching the filesystem for changes and recompiling on demand).
It's not because make is evil, it's because make does a poor job of some of these sorts of tasks.
...if all you're doing is turning .coffee files into .js, it's file, but it's not a solution for complex website builds.
Yes, Makefile syntax gets somewhat obscure after the simplicity and power of target definitions and variables (e.g. http://mrbook.org/tutorials/make/).
Yes, Make does a poorer job at some of the tasks (although spawning a webserver process isn't one of them).
P.S. I am sorry, I searched for "recursive makefile dependency hell", but I didn't find an explanation of what that is. It would be useful if you could provide some stories. I have been using Make only for two years, so maybe I haven't run into the exact problems yet.
He's probably referring to this old article - http://aegis.sourceforge.net/auug97.pdf which suggests that recursive make is bad because it can cause a lot of unnecessary processing even if you only changed one or two files. I think this just comes down to how you're using make - for me recursive make works just fine because I tend to run the specific target I need while I'm working (as it's usually in my cwd anyway) and only run the root `make all` on deployment.
Speed? Check. Simpler syntax? Check. No need to "fix" code that isn't broken? Check. No need to waste my attention on every new fad? Check.