Web Development

Use Makefiles for more than handling source code

The make command is not just for programmers. Vincent Danen shows you other handy tasks that you can perform with this versatile command.

The make command is generally given little thought by anyone other than programmers. Traditionally, this command and its associated Makefile are found in source code bundles to ease the compilation and linking of source code into executable files. It can, however, be used for much more than just handling source code.

A Makefile is nothing more than a series of commands to execute, working on the idea of dependencies for file targets. For instance, you can execute "make install" and it will check to see that any required targets are up to date first, such as a "compile" target and any dependencies it may have. This makes "make" a very versatile command. This also means you can use it with files other than just source code files; you can make it do things like copy files (locally or remotely), do version control, delete files, or any other command you like that is useful when dealing with files.

For instance, you can have a Makefile written to copy local Web files to a remote server, taking them from a version control repository. Such a Makefile might look like this:

SVNURL = https://svn.repository.com/svn/website/trunk
REMOTEHOST = user@host:~/public_html/
ifdef REV
REVISION = -r$(REV)
endif
all: dist
clean:
       rm -rf website
       rm -f website.tar.gz
checkout:
       svn co $(SVNURL) $(REVISION) website
dist: clean checkout
       tar czf website.tar.gz website
       rsync -avP -e ssh website/* $(REMOTEHOST)

Note that a proper Makefile must use tab characters to indent command structures that belong to targets. Using spaces will cause "make" to complain. The above Makefile will, in one step (using "make", which uses the default target "all"), clean the current directory (removing the website/ directory, as well as an archived copy of the Web site); check out the code from subversion, the URI of which is defined in the $(SVNURL) variable; and then make a tarball of the Web site and synchronize it to the remote server via rsync.

With the ifdef definition, you can use make REV=600 to check out the subversion repository as it was at revision 600 (passing -r600 to the subversion command); this allows you to quickly and easily revert changes or use specific point-in-time snapshots. One thing to note is that "make" will trap on non-zero exit codes, meaning it exits and returns the return code of the command in question. If you want "make" to proceed despite non-zero return codes, you can easily do so by using something like:

       ps xyz || echo ""
       cat foo

In the above, ps xyz will always exit non-zero because xyz is not a valid command. We trap it with the "||" construct (which indicates to the shell to execute the command following if the preceding command fails). The output of the failed command will still be echoed to the screen, but the error will not cause "make" to abort, and the next command will proceed.

The "make" command and Makefiles are useful for much more than just compiling source code. While it may have been designed for it, it can be used for so much more. Is it better than writing a shell script? That largely depends on your needs, but the fact that "make" does strict exit code checking, when a shell script does not (unless you do it yourself), can make it very compelling in certain situations.

Here is the PDF version of this tip.

Delivered each Tuesday, TechRepublic's free Linux and Open Source newsletter provides tips, articles, and other resources to help you hone your Linux skills. Automatically sign up today!

About

Vincent Danen works on the Red Hat Security Response Team and lives in Canada. He has been writing about and developing on Linux for over 10 years and is a veteran Mac user.

6 comments
varun.blaze
varun.blaze

make files are similiar to ANT for compiling java sources

Jaqui
Jaqui

very good dependency checking, which can cause a problem if you don't "clean" first. Newer files would NOT get overwritten or replaced without the clean target.

jprigot
jprigot

I once read an article by an IBM researcher who uses Makefiles to make sure that processes start in the correct sequence and dependent processes are running during system startup.

Tony K
Tony K

I remember coming across an article a few years back in which the author had used make as a replacement for init since make can run its tasks in parallel. I now use make (on Unix and Windows) to perform tasks similar to what's in the article. It's good to see a more "mainstream" discussion.

pointzerotwo
pointzerotwo

Several years ago I needed to resize dozens of hi-res image files into "normal", "thumbnail", and "detail" sizes for a website. It seemed like the perfect job for 'make', since the process was somewhat similar to compiling source code. It would only re-convert images if their source image changed. After hours and hours I finally figured out the syntax to make it work, and it worked out ok. For most scripting jobs, though, I tend to use ruby over shell scripts, batch files, or other specialized tools (like make). It's very flexible, has nice syntax, and the same version works on Windows (w/o cygwin), Mac, and Linux.

ogozhan
ogozhan

I was asking to the question in subject before I read this and the next reply. Yes I cannot use bash scripting in Windows (possible with cygwin indeed). Also pearl is another cross-platform scripting alternative but it is another headache. I guess it is quite easier to use make "scripts" on both platforms. And it seems make is designed considering dependency a lot. So you can perceive the dependencies at first glance once you get familiar with make. I may be convinced to learn make.