views:

510

answers:

5

"make" is not only useful for building your programming project, but it seems to be under-used in other areas.

For example, many shell scripts can be rewritten as Makefiles to allow independent parts to run in parallel (with "make -jXX") to keep all your CPU cores busy, with the explicitly declared dependencies as an added benefit in case you'd ever consider reordering some tasks with side effects in your shell script.

Do you have any interesting stories with unusual uses of make / Makefiles to share? Do you use some other utility as a cheap job scheduler?

A: 

My work uses a curious one: the dependencies don't exist so it always rebuilds everything.

Might as well have used a batch file.

Joshua
Norman Ramsey
Err, the rebuild-everything was intentional.
Joshua
+1  A: 

It probably means my imagination is deficient, but it is hard to get sufficient flexibility into a makefile for such use. The 'obvious' way to achieve it is to specify macro values on the 'make' command line.

make -f script.mk MACRO="list of files on which to operate"

That is more verbose than a simple shell script - and you lose the easy ability to use shell file name expansion. The workaround for that is:

make -f script.mk MACRO="$(echo *[io]*)"

I'd offer this SO question about Why not use #!/bin/make at the top of makefiles as an odd use of (executable) makefiles, but the goal there was not to do unusual things (just boring old software builds); just to use an unusual invocation mechanism for make.

Using the technique, you could simplify the invocation to:

script.mk MACRO="$(echo *[io]*)"

That's still more verbose than:

script *[io]*

I suppose script could be written to do the invocation of make. It all depends. I'm not convinced that there's enough mileage to be gained out of it; YMMV.

Jonathan Leffler
GNU Make supports $(MAKECMDGOALS), which I've used in the past to create Makefile-scripts which can accept random junk on the command line directly without going through these hoops.
ephemient
See also jturner's solution using $(shell cat) to read from stdin.
j_random_hacker
+3  A: 

Other than obvious uses in programming, I've seen Makefiles used to perform repetitive tasks on servers to manage system settings such as user/group creation, package upgrades/updates, and copying config files into place. I have also seen (and used) rake to do this in Ruby based environments.

The most complex example of this I have heard of is ISConf, a configuration management tool. I heard about it from Luke Kanies, the author of Puppet, on his blog.

jtimberman
+2  A: 

Depending on the variety of 'make' , you can sail through dependencies of tasks by using executable makefiles vs shell scripts .. i.e. in a scenario where one init script needs to start 10 services ... one after the other (i.e service two needs service one to be up and alive prior to starting), its easily done via a makefile.

A lot of GNU/Linux packagers make use of this, i.e. debian/rules and others. So yeah, if done correctly, make is just as good at starting programs as it is as building them.

The problem is, not everyone has a build tool chain installed .. so shell scripts or batch files remain the portable (hence 'correct') approach.

Tim Post
+9  A: 

Make's parallelism is particularly handy for shell scripting. Say you want to get the 'uptime' of a whole set of hosts (or basically perform any slow operation). You could do it in a loop:

cat hosts | while read host; do echo "$host: $(ssh $host uptime)"; done

This works, but is slow. You can parallelise this by spawning subshells:

cat hosts | while read host; do (echo "$host: $(ssh $host uptime)")&; done

But now you have no control over how many threads you spawn, and ctrl-c won't cleanly interrupt all threads.

Here is the Make solution: save this to a file (eg. "showuptimes") and mark as executable:

#!/usr/bin/make -f

hosts:=$(shell cat)
all: ${hosts}

${hosts} %:
        @echo "$@: `ssh $@ uptime`"

.PHONY: ${hosts} all

Now running 'cat hosts | ./showuptimes' will print the uptimes one by one. 'cat hosts | ./showuptimes -j' will run them all in parallel. The caller has direct control over the degree of parallelisation (-j), or can specify it indirectly by system load (-l).

How cool is that :)

jturner
+1, I like the shebang line.
j_random_hacker
Nitpick: "./showuptimes < hosts" avoids creating an unnecessary cat process.
j_random_hacker