LinuxDevCenter.com

oreilly.comSafari Books Online.Conferences.

We've expanded our Linux news coverage and improved our search! Search for all things Linux across O'Reilly!

Search
Search Tips

advertisement

Print Subscribe to Linux Subscribe to Newsletters
Linux & Unix > Excerpts >

Advanced makefiles

by Jennifer Vesperman
02/14/2002

In this article, we analyze a fairly complicated makefile. This makefile was captured from actual use in the wild, and sections specific to that project have been removed for this article.

This is a companion article to Introduction to make, and it builds on the topics covered there. See Introduction for a simple makefile and a guide on how to use and construct simple makefiles.

Both the introduction and this advanced article focus on make as a tool for developers. Sysadmins, make can be useful to you, too! As we step through the makefile, think about how the techniques here can be applied to rebuilding a configuration script, or an installation script, or as an auto-updating tool.

Thanks to Mitch Davis for allowing me to use his file. The modified version won't run as presented because I've removed lines, but it will allow me to display various techniques. The original is in frequent use.

Header comments

# TODO: Add a section for installation

# Makefile for (the project)
# Version 3.0
# Jennifer Vesperman
# 14 August 2001
#
# Version 4.0
# Mitch Davis
# 10 January 2002

It's always useful to include headers in a makefile and to record the wish list of improvements. My version of the makefile was one of those quick-and-dirty jobs that we find ourselves doing.

Location definitions

# Set up the compiler directories
xmlc_j:=            /usr/local/lib/xmlc2.0.1/xmlc.jar
install_d:=         /usr/local/apps/jakarta-tomcat-3.2.2/webapps/example
servlet_d:=         $(tomcathome)/lib
class_d:=           $(install_d)/WEB-INF/classes
class_example_d=    $(class_d)/example
# (additional directory definitions snipped.)

The paths necessary for compilation are set up as variables. This allows them to be easily changed if the installation is moved--and you can use conditionals and shell functions to change things automatically for different machines. Conditionals and shell functions are discussed in more detail later in this article.

Using a conditional to define a machine-specific variable

ifeq ($(shell uname -n),install)
  # For compiling on install machine
  install_d:= /usr/local/jakarta-tomcat-3.2.2/webapps/example
endif

Recursively expanded variables

There are two forms of variable. Recursively expanded variables use an "=" between the name and the value and are evaluated at the time the variable is needed. They cannot be defined recursively, as this would create an infinite loop. (make checks for this and forbids this usage.) Functions will be calculated each time make needs the value of the variable.

  • OK: class_example_d = $(class_d)/example
    (refers to a different variable within the definition)

  • Not OK: class_d = $(class_d)/example
    (recursive definition--refers to itself within its definition)

Simply expanded variables

Simply expanded variables use a ":=" between the name and the value and are evaluated immediately when make encounters the variable. Recursive definition is fine, and the right-hand-side value will be the former value of the variable. Simply expanded variables are a feature of GNU make that may not exist in other versions of make.

  • OK: class_example_d := $(class_d)/example

  • OK: class := $(class)/example
    (OK if class was defined before this point)

Environment variables

# These exports are for xmlc, which is 
# a java program which calls javac.
export JAVAC:=  $(java_h)/bin/javac
export JAVA:=   $(java_h)/bin/java

Sometimes it's necessary to set environment variables within the makefile, usually when you have a project that must use a specific version of a compiler. Choose your variables carefully--changing the EDITOR variable will annoy your development team!

Make functions

# Set up the classpaths for Javac
classpath:= \
        $(cookie_d)/cookiebuster.jar \
        $(example_j) \
        $(hsqldb_d)/hsqldb.jar \
        $(xmlc_j) \
        $(xml_j) \
        $(jetty_d)/com.mortbay.jetty.jar

# Convert the spaces to colons.  This trick is from 
# the make info file.
empty:=
space:= $(empty) $(empty)
classpath:=     $(subst $(space),:,$(classpath))

The classpath variable is a standard, simply expanded variable, with its definition split over several lines with the new lines escaped. Mitch then uses a make function to replace the spaces separating paths with colons. He considers this to be a much more readable variable definition than a single line, colon-separated classpath. Don't use this if you have spaces inside the classpath.

Running Linux

Related Reading

Running Linux
By Matt Welsh, Matthias Kalle Dalheimer, Lar Kaufman

make has many useful built-in functions. The syntax of a function call is $(function arguments). Functions are evaluated when the surrounding construct is evaluated: functions in simply expanded variables are evaluated when make first encounters the variable; functions in recursively expanded variables are evaluated when make needs the value of the variable; functions in rules are evaluated when make runs that part of the rule.

Conditionals

# If there's already a CLASSPATH, put it on the front
ifneq ($(CLASSPATH),)
        classpath:=     $(CLASSPATH):$(classpath)
endif

# Re-export the CLASSPATH.
export CLASSPATH:=$(classpath)

Make has conditionals, often used when setting variables. Available conditionals are ifeq, ifneq, ifdef, and ifndef. The else clause is optional, and the arguments may be surrounded by brackets, apostrophes, or quote marks.

In the example, we could have used an ifdef rather than the ifneq to determine whether the classpath environment variable is defined.

The syntax used in this makefile is:

ifeq (arg1, arg2) 
	statement/s
else
	statement/s
endif

Pages: 1, 2

Next Pagearrow




Tagged Articles

Be the first to post this article to del.icio.us

Recommended for You

Sponsored Resources

  • Inside Lightroom
Advertisement

Sponsored by:

Sign up today to receive special discounts,
product alerts, and news from O'Reilly.
Privacy Policy >
View Sample Newsletter >
  • Youtube
  • http://www.youtube.com/OreillyMedia
  • Twitter
  • Subscribe
  • View All RSS Feeds >
O'Reilly Media

800-889-8969 or 707-827-7019
Monday-Friday 7:30am-5pm PT
©2011, O'Reilly Media, Inc.
All trademarks and registered trademarks appearing on oreilly.com are the property of their respective owners.
  • About O'Reilly
  • Academic Solutions
  • Contacts
  • Customer Service
  • Careers
  • Press Room
  • Privacy Policy
  • Terms of Service
  • Writing for O'Reilly
  • Community
  • Authors
  • Forums
  • Membership
  • Newsletters
  • RSS Feeds
  • User Groups
  • More O'Reilly Sites
  • igniteshow.com
  • makerfaire.com
  • makezine.com
  • craftzine.com
  • labs.oreilly.com
  • Partner Sites
  • PayPal Developer Zone
  • O'Reilly Insights on Forbes.com