# p4/Jamrules
#
# This Jamrules describes how to build most of Perforce, exclusive of
# windows only products.
#
# This file is organized into sections:
#
#	Section 1.  Global variable settings.
#	Section 2.  Library names.
#	Section 3.  Per-build type variable settings.
#	Section 4.  Per-platform variable settings.
#	Section 5.  Perforce-special rules and actions.
# 	Section 6.  Perforce-special Windows rules.
#	Section 7.  QT build rules and actions.
#	Section 8.  Lua build rules and actions.
#	Section 9.  Per-platform actions.
#	Section 10. Useful miscellanea
#

#################################################
#
# Section 1.  Global variable settings.
#
#################################################

	if $(JAMBASEDATE) < 2002.05.09 {
	    Exit Jamrules requires Jambase 2002.05.09 ($(JAMBASEDATE)) ;
	}

	# Variables you shouldn't set:
	#
	#   OS - operating system ("FreeBSD")
	#   OSPLAT - OS platform ("sparc")
	#
	# Variables you can set:
	#
	#   OSVER - version of OS ("102" for MACOSX)
	#   TYPE - controls compile flags (see below)
	#   BUILD - subdirectory for special named builds ("nightly")

	# For convenience of historical compatibility, the OSPLAT value
	# "AMD64" will be changed to "X86_64", which is the canonical name
	# we are now using for that platform.  Please get into the habit of
	# using it directly, as this may go away someday.
	if $(OSPLAT) = AMD64 { OSPLAT = X86_64 ; }

	# This is jam idiomatic, but the result is that
	# P4BIN is set to ../p4-bin (relative to P4)

	SubDir AllP4 p4 ;	# where we are
	SubDir AllP4 p4-bin ;	# where we want to be
	SubDir P4BIN ;		# name is that
	SubDir AllP4 p4 ;	# back to where we started

	EXEC_LIB_TOKENS =
		P4BIN
		lib.$(OS:L)$(OSVER:EL)$(OSPLAT:EL)
		;
	EXEC_LIB ?= [ FSubDirPath $(EXEC_LIB_TOKENS) ] ;

	EXEC_LIBEXEC_TOKENS =
		P4BIN
		libexec.$(OS:L)$(OSVER:EL)$(OSPLAT:EL)
		;
	EXEC_LIBEXEC ?= [ FSubDirPath $(EXEC_LIBEXEC_TOKENS) ] ;

	# Build dir: p4-bin/bin.xxx[/build][/type]
	EXEC_TOKENS =
		P4BIN
		bin.$(OS:L)$(OSVER:EL)$(OSPLAT:EL)
		$(BUILD)
		$(TYPE:L)
		;

	EXEC ?= [ FSubDirPath $(EXEC_TOKENS) ] ;
	ALL_LOCATE_TARGET = $(EXEC) ;

	# version file
	# Ident'ed executables depend on this

	SEARCH on Version Jamrules = $(P4) ;
	include Version ;

	STRIP = strip ;
	COMPRESS = gzip -9 ;

	# symbolic flags with no user/group/other specifier will default to
	# ANDing with the user's umask.
	# Thus, if the user's umask is 022,
	#  files will be -rw-r--r-- and executables will be -rwxr-xr-x
	# If a user's umask is 002,
	#  files will be -rw-rw-r-- and executables will be -rwxrwxr-x
	# and so on.

	if $(UNIX)
	{
		FILEMODE = "+r,go-w" ;
		EXEMODE  = "+rx,go-w" ;
	}

	# can be overridden on jam cmdline with -sSMARTHEAP=no
	# Smartheap is currently only used on NT and Linux.
	SMARTHEAP ?= yes ;

	DEFINES +=
		OS_$(OS)
		OS_$(OS)$(OSVER)
		OS_$(OS)$(OSPLAT)
		OS_$(OS)$(OSVER)$(OSPLAT) ;

	HDRS +=
		[ FSubDirPath P4 msgs ]
		[ FSubDirPath P4 support ]
		[ FSubDirPath P4 sys ] ;

	# Which Zeroconf implementation to select. Default is
	# Apple's bonjour.

	ZEROCONF = bonjour ;

	# For production builds we customize the names of our Qt shared
	# libaries on some platforms to avoid naming/version conflicts with
	# system libraries on numerous platforms.  The main exception is
	# OSX, where it isn't needed.
	#
	# Developers don't necessarily bother to add this infix to their
	# builds, but these variables allow one to use them if desired even
	# for non-production builds.
	if $(PRODUCTION) && $(OS) != MACOSX
	{
		QT_LIBINFIX ?= P4 ;
	}

	# Point to the root of the boost hierarchy.  c.f. BoostHdrs rule.
	BOOSTDIR ?= [ FDirName $(AllP4) .. import boost 1.37 ] ;

#################################################
#
# Section 2.  Library names.
#
#################################################

	rule SetLibName
	{
		$(1) = $(2:S=$(SUFLIB)) ;
		LOCATE on $($(1)) = $(EXEC) ;
	}

	SetLibName CLIENTLIB        : libclient     ;
	SetLibName DMLIB            : libdm         ;
	SetLibName FTPLIB           : libp4ftp 	    ;
	SetLibName LBRLIB           : liblbr        ;
	SetLibName P4EXPLIB         : libp4exp      ;
	SetLibName P4TD             : libp4thumb    ;
	SetLibName P4LIB            : libp4         ;
	SetLibName P4SCCLIB         : libp4scc      ;
	SetLibName P4WINLIB         : libp4win      ;
	SetLibName P4WINCMNLIB      : libp4wcmn     ;
	SetLibName P4WINDIFFLIB     : libp4wdf      ;
	SetLibName P4WINMRGLIB      : libp4wmrg     ;
	SetLibName PLUGINLIB 	    : libplugin     ;
	SetLibName PROXYLIB         : libproxy      ;
	SetLibName QTADMINAPPLIB    : libqtadminapp ;
	SetLibName QTADMINLIB       : libqtadmin    ;
	SetLibName QTCMDLIB         : libqtcmd      ;
	SetLibName QTCORELIB        : libqtcore     ;
	SetLibName QTP4APILIB       : libqtp4api    ;
	SetLibName QTIMGMAXLIB      : libqtmaxfmt   ;
	SetLibName QTIMGMAYALIB     : libqtmayafmt  ;
	SetLibName QTIMGPHOTOLIB    : libqtphotofmt ;
	SetLibName QTIMGTGALIB      : libqttgafmt   ;
	SetLibName QTMERGELIB       : libqtmerge    ;
	SetLibName QTMERGEAPPLIB    : libqtmergeapp ;
	SetLibName QTPLATLIB        : libqtplat     ;
	SetLibName QTPREFLIB        : libqtpref     ;
	SetLibName QTUTILLIB        : libqtutil     ;
	SetLibName QTREELIB         : libqtree      ;
	SetLibName QTZEROCONFLIB    : libqtzeroconf ;
	SetLibName RPCLIB           : librpc        ;
	SetLibName SANDSTORM        : libstorm      ;
	SetLibName P4ALIB           : libp4a        ;
	SetLibName P4V              : libp4v        ;
	SetLibName P4VTEST          : libp4vtest    ;
	SetLibName SCCDLLLIB        : p4scc2        ;
	SetLibName SERVERLIB        : libserver     ;
	SetLibName SUPPORTLIB       : libsupp       ;
	SetLibName WEBGIZMOLIB	    : libp4web      ;
	SetLibName ZEROCONFLIB	    : libzeroconf   ;

#################################################
#
# Section 3.  Per-build type variable settings.
#
#################################################

	TYPE ?= opt ;

	switch $(TYPE)
	{
	# These are official builds
	#
	#  dyn: windows guis must be dynamic
	#  opt: our standard, optimized built
	#  pic: for special customer requests

	case dyn : OPTIM = -O2 ;
	case opt : OPTIM = -O2 ;
	case pic : OPTIM = -O2 -fPIC ;

	# These are for internal testing/playing
	#
	#  g/dyng/optg: debugging
	#  pg: profiled executable on unix
	#  fast: a fast compile (no optimization)
	#  lower: case insensitive on UNIX
	#  lpg: lower profiled

	case g      : OPTIM = -g ;
	case dyng   : OPTIM = -g ;
	case fast   : OPTIM = ;
	case lower  : OPTIM = -DCASE_INSENSITIVE -O2 ;
	case lpg    : OPTIM = -DCASE_INSENSITIVE -O2 -pg ; LINKFLAGS = -pg ;
	case optg   : OPTIM = -O2 -g ;
	case pg     : OPTIM = -pg -O ; LINKFLAGS = -pg ;
	case sym    : OPTIM = -opt off -sym full ; LINKFLAGS = -sym full ;
	case FSgSSP : OPTIM = -g -D_FORTIFY_SOURCE=2 -fstack-protector-all ;

	case *vsdebug : # special-target builds; see NT section

	case * : 	Echo "Warning -- unknown compilation TYPE" $(TYPE) ;
	}

	# TYPE_DEBUG for all debug builds.
	# TYPE_DYNAMIC for all dynamic builds.

	switch $(TYPE) { case *g   : TYPE_DEBUG   = true ; }
	switch $(TYPE) { case dyn* : TYPE_DYNAMIC = true ; }

	# Some things don't get built dynamically/statically.

	if ! $(TYPE_DYNAMIC) || $(OS) != NT { BUILD_P4D = true ; }

#################################################
#
# Section 4.  Per-platform variable settings.
#
#################################################

	# Flags for Perforce
	#
	#	CASE_INSENSITIVE -- case folding server
	#	ENUM_INT -- force enums to int sized for watcom
	#	USE_CRLF -- ascii opened as binary needs special handling
	#	USE_CR -- special CR <-> LF translation for mac
	#	USE_EBCDIC -- ascii <-> ebcdic translation in rpc

	GENFLAGS = CCFLAGS C++FLAGS ;

	switch $(OS)$(OSVER) $(OS)
	{
	case AIX53 :
		C++  = g++ ;
		CC   = gcc ;
		LINK = gcc ;

		C++FLAGS += -DBSD -Dunix -D_LARGE_FILES=1 ;
		LINKLIBS += -lsupc++ ;

		switch $(OSPLAT)
		{
		case PPC64 :
			$(GENFLAGS) += -maix64 ;
			LINKFLAGS   += -maix64 ;
			AR           = ar -X 64 -ru ;
			STRIP        = strip -X 64 ;
		}

	case AS400 :
		CC           = icc ;
		C++          = icc ;
		LINK         = icc ;
		OPTIM        = -O4 ;
		$(GENFLAGS) += -DUSE_EBCDIC ;
		LINKFLAGS   += -qDUPPROC ;
		AR           = qar -cru ;
		STRIP        = ;
		ZEROCONF     = none ;

		# This QSYS library must be pre-created before building
		QSYSLIB    = p4 ;

	case CYGWIN :
		CC        = gcc ;
		C++       = gcc ;
		LINK      = g++ ;
		C++FLAGS += -DUSE_CRLF ;
		STRIP     = ;

	case DARWIN :
		CC        = cc ;
		C++       = cc ;
		C++FLAGS += -DCASE_INSENSITIVE ;

	case DARWIN60cs : #case-sensitive
		CC   = cc ;
		C++  = cc ;
		LINK = g++ ;

	case DARWIN8* :
		CC   = gcc ;
		C++  = g++ ;
		LINK = g++ ;

		MACOSX_SDK ?= /Developer/SDKs/MacOSX10.4u.sdk ;
		LINKFLAGS += -Wl,-syslibroot,$(MACOSX_SDK) ;

		switch $(OSVER:U)
		{
		case *CS :
		case *   : C++FLAGS += -DCASE_INSENSITIVE ;
		}

		# OSPLAT=U : universal binary
		switch $(OSPLAT)
		{
		case PPC    : _arch = -arch ppc    ;
		case X86    : _arch = -arch i386   ;
		case X86_64 : _arch = -arch x86_64 ;
		case U      : _arch = -arch ppc
		                      -arch i386
		                      -arch x86_64 ;
		              NOARSCAN = true ; # can't scan "fat" archives
		}

		$(GENFLAGS) += $(_arch) -DOS_DARWIN80 ;
		LINKFLAGS   += $(_arch) ;

	case DARWIN9* :
		CC   = gcc ;
		C++  = g++ ;
		LINK = g++ ;

		MACOSX_SDK ?= /Developer/SDKs/MacOSX10.5.sdk ;
		LINKFLAGS += -Wl,-syslibroot,$(MACOSX_SDK) ;
	 	LINKLIBS += -framework CoreServices ;

		switch $(OSVER:U)
		{
		case *CS :
		case *   : C++FLAGS += -DCASE_INSENSITIVE ;
		}

		# OSPLAT=U : universal binary
		switch $(OSPLAT)
		{
		case PPC    : _arch = -arch ppc    ;
		case X86    : _arch = -arch i386   ;
		case X86_64 : _arch = -arch x86_64 ;
		case U      : _arch = -arch ppc
		                      -arch i386
		                      -arch x86_64 ;
		              NOARSCAN = true ; # can't scan "fat" archives
		}

		$(GENFLAGS) += $(_arch) -DOS_DARWIN90 ;
		LINKFLAGS   += $(_arch) ;

	case DARWIN10* :
		CC   = gcc ;
		C++  = g++ ;
		LINK = g++ ;

		MACOSX_SDK ?= /Developer/SDKs/MacOSX10.6.sdk ;
		LINKFLAGS += -Wl,-syslibroot,$(MACOSX_SDK) ;
 	 	LINKLIBS += -framework CoreServices ;

		switch $(OSVER:U)
		{
		case *CS :
		case *   : C++FLAGS += -DCASE_INSENSITIVE ;
		}

		# OSPLAT=U : universal binary
		# There is no ppc support in osx 10.6 / darwin 10
		switch $(OSPLAT)
		{
		case X86    : _arch = -arch i386   ;
		case X86_64 : _arch = -arch x86_64 ;
		case U      : _arch = -arch i386
		                      -arch x86_64 ;
		              NOARSCAN = true ; # can't scan "fat" archives
		}

		$(GENFLAGS) += $(_arch) -DOS_DARWIN10 ;
		LINKFLAGS   += $(_arch) ;

	case FREEBSD :
		Exit Set OSVER to 4, 5, or 6 for FreeBSD ;

	case FREEBSD4 :
		CC   = gcc ;
		C++  = g++ ;
		LINK = gcc ;

		switch $(OSCOMP)
		{
		case GCC3 : LINKLIBS += -lsupc++ ;
		}

		if $(OSPLAT) != AXP { LINKFLAGS += -static ; }
		$(GENFLAGS) += -pipe ;
		ZEROCONF = avahi ;

	case FREEBSD[56789]* :
		CC   = gcc ;
		C++  = g++ ;
		LINK = gcc ;
		# supc++ library on freebsd5.x and later is missing some
		# modules (this is a bug), so we can't use it.
		# Since every major version of the OS requires relinking
		# anyway, there's no harm in linking stdc++ dynamically.
		LINKLIBS += -lstdc++ ;

		_mflags = ;
		switch $(OSPLAT)
		{
		case X86    : _mflags = -m32 ;
		case X86_64 : _mflags = -m64 ;
 		}

		$(GENFLAGS) += $(_mflags) -pipe ;
		LINKFLAGS   += $(_mflags) ;

		QTOPENGL ?= no ;
		ZEROCONF = avahi ;

	case HPUX11 :
		switch $(OSPLAT:E)-$(OSCOMP:E)
		{
		# On IA64, hpux supports both 64-bit and 32-bit executables.
		# We build 64-bit for the benefit of p4d, and client apps are built
		# the same way for the sake of simplicity.
		case IA64-GCC :
			CC           = gcc ;
			C++          = gcc ;
			$(GENFLAGS) += -mlp64 ;

			LINK         = gcc ;
			LINKFLAGS   += -mlp64 ;
			LINKLIBS    += -lsupc++ -lunwind ;

		case IA64-* : # unbundled vendor compiler
			CC           = aCC ;
			C++          = aCC ;
			OPTIM        = +O1 ;
			if $(TYPE) = pic { OPTIM += +Z ; }

			CCFLAGS     += -Ae ; # treat .c files as C89, not C++
			$(GENFLAGS) += +DD64 +noeh -z ;

			# Suppress compiler warnings:
 			# 	2611: overloaded virtual function "x" is only partially overridden in class "y"
 			# 	2997: function "x::fn is hidden by y::fn" -- virtual function override intended?
			$(GENFLAGS) += +W2611,2997 ;

			LINK         = aCC ;
			# The +hideallsymbols linker option will generate a
			# lot of harmless warnings about being unable to hide
			# symbols that are undefined and need resolving
			# from the (dynamically linked) system libraries,
			# but see //depot/main/p4-doc/code/PORTING for rationale.
			LINKFLAGS   += +DD64 +Oprocelim -z -Wl,+hideallsymbols,+stripunwind ;

		case PA11-* : # unbundled vendor compiler
			CC    = aCC ;
			C++   = aCC ;
			LINK  = aCC ;
			OPTIM = +O1 ;
			CCFLAGS     += -Ae ; # treat .c files as C89, not C++
			$(GENFLAGS) += -D_LARGEFILE64_SOURCE +DA1.1 ;

		case *-* : # assumed PA20 (32-bit) with unbundled vendor compiler
			CC           = aCC ;
			C++          = aCC ;
			LINK         = aCC ;
			OPTIM        = +O1 ;
			CCFLAGS     += -Ae ; # treat .c files as C89, not C++
			$(GENFLAGS) += -D_LARGEFILE64_SOURCE ;
		}

	case IPHONE30 :

		# This is distinct from the MACOSX or DARWIN platforms
		# because the SDKs used are not compatible, and because
		# someday the iPhone may target both armv6 and i386.

		PLATFORM_ROOT ?= /Developer/Platforms/iPhoneOS.platform ;
		COMPILER_DIR  ?= $(PLATFORM_ROOT)/Developer/usr/bin ;

		SDK_VERSION   ?= iPhoneOS3.0.sdk ;
		IPHONE_SDK    ?= $(PLATFORM_ROOT)/Developer/SDKs/$(SDK_VERSION) ;

		CC     = $(COMPILER_DIR)/gcc ;
		C++    = $(COMPILER_DIR)/g++ ;
		LINK   = $(COMPILER_DIR)/g++ ;
		RANLIB = $(COMPILER_DIR)/ranlib ;

		$(GENFLAGS) += -DCASE_INSENSITIVE
		               -DOS_DARWIN
		               -fpascal-strings
		               -isysroot$(IPHONE_SDK) ;
		LINKFLAGS   += -Wl,-syslibroot,$(IPHONE_SDK) ;

		# OSPLAT=U : universal binary (don't use this right now)
		switch $(OSPLAT)
		{
		case ARMV6  : _arch = -arch armv6 ;
		case ARMV7  : _arch = -arch armv7 ;
		case U      : _arch = -arch armv6
		                      -arch armv7 ;
		              NOARSCAN = true ; # can't scan "fat" archives
		}

		$(GENFLAGS) += $(_arch) -DCASE_INSENSITIVE ;
		LINKFLAGS   += $(_arch) ;

	case IRIX65 :
		CC   = cc -OPT:Olimit 5000 -64 -mips3 ;
		C++  = CC -woff 3439,1174,1178,1681,1682
		          -OPT:Olimit 5000 -64 -mips3 ;
		LINK = CC -64 ;

		if $(TYPE) = pic
		{
			OPTIM = -O2 -KPIC ;
		}

	case LINUX :
		Exit Set OSVER to 24 or 26 ;

	case LINUX2[46] :
		# If cross compiling on one platform for another, set
		# CROSS_COMPILE to the prefix of the cross tools.  For
		# example, to build for ARM using an X86 host, set
		# CROSS_COMPILE="arm-none-linux-gnueabi-" and OSPLAT="ARM".

		CC        = $(CROSS_COMPILE:E)gcc    ;
		C++       = $(CROSS_COMPILE:E)g++    ;
		LINK      = $(CROSS_COMPILE:E)gcc    ;
		STRIP     = $(CROSS_COMPILE:E)strip  ;
		RANLIB    = $(CROSS_COMPILE:E)ranlib ;
		LINKLIBS += -lsupc++ # Assumes gcc 3.x or later
		            -ldl ;   # for zeroconf

		# be explicit about submodel since we may be compiling x86 code on
		# an x86/x86_64 biarch system, and the default may be uncertain.
		_mflags = ;
		switch $(OSPLAT)
		{
		case X86    : _mflags = -m32 ;
		case X86_64 : _mflags = -m64 ;
		case ARM*   : _mflags = -march=armv4t ;
		}

		if $(SMARTHEAP) = yes { $(GENFLAGS) += -DUSE_SMARTHEAP ; }

		$(GENFLAGS) += $(_mflags) -D_GNU_SOURCE ;
		LINKFLAGS   += $(_mflags) ;

		QTOPENGL ?= no ;
		ZEROCONF  = avahi ;

	case MACOSX :
		CC = cc ;
		C++ = cc ;
		$(GENFLAGS) += -DCASE_INSENSITIVE ;
		$(GENFLAGS) += -fpascal-strings ;
		# This looks like a flag but it is really a library macro
		# kind of thing and causes link problems if it at the front
		# of the link command so we make it a LIB
		LINKLIBS += -framework ApplicationServices ;
		LINKLIBS += -framework Foundation ;
 	 	LINKLIBS += -framework CoreServices ;

	case MACOSX104 :  # assumes using gcc 4.0.1 or newer
		CC   = gcc ;
		C++  = g++ ;
		LINK = g++ ;

		MACOSX_SDK ?= /Developer/SDKs/MacOSX10.4u.sdk ;

		# The -fvisibility-inlines-hidden option is a C++-only
		# option, needed because Qt4 is built with it and all
		# statically-compiled objects need to use it consistently.
		C++FLAGS    += -fvisibility-inlines-hidden ;
		$(GENFLAGS) += -DCASE_INSENSITIVE
		               -fpascal-strings
		               -isysroot$(MACOSX_SDK) ;
		LINKFLAGS   += -Wl,-syslibroot,$(MACOSX_SDK) ;
		# This looks like a flag but it is really a library macro
		# and causes link problems if it's at the front of the link
		# command, so we make it a LIB.
		LINKLIBS    += -framework ApplicationServices ;
		LINKLIBS    += -framework Foundation ;
 	 	LINKLIBS += -framework CoreServices ;

		# OSPLAT=U : universal binary
		#
		# Unlike the OS=DARWIN case we don't build x86_64 into the
		# universal binaries because Qt still uses the Carbon API,
		# which has no 64-bit implementation.
		switch $(OSPLAT)
		{
		case PPC    : _arch = -arch ppc    ;
		case X86    : _arch = -arch i386   ;
		case X86_64 : _arch = -arch x86_64 ;
		case U      : _arch = -arch ppc
		                      -arch i386   ;
		              NOARSCAN = true ; # can't scan "fat" archives
		}

		$(GENFLAGS) += $(_arch) -DCASE_INSENSITIVE ;
		LINKFLAGS   += $(_arch) ;

		# This adds $(QTDIR)/lib as a frameworks directory, in case
		# Qt is built as frameworks.  On the mac, it can be built
		# either as frameworks, regular unix-style shared
		# libraries, or unix-style static libaries.
		$(GENFLAGS)  += -F$(QTDIR)/lib ;

	case MACOSX105 :  # assumes using gcc 4.0.1 or newer
		CC   = gcc ;
		C++  = g++ ;
		LINK = g++ ;

		MACOSX_SDK ?= /Developer/SDKs/MacOSX10.5.sdk ;

		# The -fvisibility-inlines-hidden option is a C++-only
		# option, needed because Qt4 is built with it and all
		# statically-compiled objects need to use it consistently.
		C++FLAGS    += -fvisibility-inlines-hidden ;
		$(GENFLAGS) += -DCASE_INSENSITIVE
		               -fpascal-strings
		               -isysroot$(MACOSX_SDK) ;
		LINKFLAGS   += -Wl,-syslibroot,$(MACOSX_SDK)
		               -mmacosx-version-min=10.5 ;
		# This looks like a flag but it is really a library macro
		# and causes link problems if it's at the front of the link
		# command, so we make it a LIB.
		LINKLIBS    += -framework ApplicationServices ;
		LINKLIBS    += -framework Foundation ;
 	 	LINKLIBS    += -framework CoreServices ;

		# OSPLAT=U : universal binary
		#
		# Unlike the OS=DARWIN case we don't build x86_64 into the
		# universal binaries because Qt still uses the Carbon API,
		# which has no 64-bit implementation.
		switch $(OSPLAT)
		{
		case PPC    : _arch = -arch ppc    ;
		case X86    : _arch = -arch i386   ;
		case X86_64 : _arch = -arch x86_64 ;
		case U      : _arch = -arch ppc
		                      -arch i386   ;
		              NOARSCAN = true ; # can't scan "fat" archives
		}

		$(GENFLAGS) += $(_arch) -DCASE_INSENSITIVE ;
		LINKFLAGS   += $(_arch) ;

		# This adds $(QTDIR)/lib as a frameworks directory, in case
		# Qt is built as frameworks.  On the mac, it can be built
		# either as frameworks, regular unix-style shared
		# libraries, or unix-style static libaries.
		$(GENFLAGS)  += -F$(QTDIR)/lib ;

	case MACOSX106 :  # assumes using gcc 4.0.1 or newer
		CC   = gcc ;
		C++  = g++ ;
		LINK = g++ ;

		MACOSX_SDK ?= /Developer/SDKs/MacOSX10.6.sdk ;

		# The -fvisibility-inlines-hidden option is a C++-only
		# option, needed because Qt4 is built with it and all
		# statically-compiled objects need to use it consistently.
		C++FLAGS    += -fvisibility-inlines-hidden ;
		$(GENFLAGS) += -DCASE_INSENSITIVE
		               -fpascal-strings
		               -isysroot$(MACOSX_SDK) ;
		LINKFLAGS   += -Wl,-syslibroot,$(MACOSX_SDK) ;
		# This looks like a flag but it is really a library macro
		# and causes link problems if it's at the front of the link
		# command, so we make it a LIB.
		LINKLIBS    += -framework ApplicationServices ;
		LINKLIBS    += -framework Foundation ;
 	 	LINKLIBS    += -framework CoreServices ;

		# OSPLAT=U : universal binary
		#
		# Unlike the OS=DARWIN case we don't build x86_64 into the
		# universal binaries because Qt still uses the Carbon API,
		# which has no 64-bit implementation.
		#
		# No PPC support in OSX 10.6.
		switch $(OSPLAT)
		{
		case X86    : _arch = -arch i386   ;
		case X86_64 : _arch = -arch x86_64 ;
		case U      : _arch = -arch i386   ;
		}

		$(GENFLAGS) += $(_arch) -DCASE_INSENSITIVE ;
		LINKFLAGS   += $(_arch) ;

		# This adds $(QTDIR)/lib as a frameworks directory, in case
		# Qt is built as frameworks.  On the mac, it can be built
		# either as frameworks, regular unix-style shared
		# libraries, or unix-style static libaries.
		$(GENFLAGS)  += -F$(QTDIR)/lib ;

	case MVS :
		# Set the following variables in your shell before
		# invoking jam
		#
		# _C89_CLIB_PREFIX="SYS1.CBC"
		# _C89_PLIB_PREFIX="SYS1.CEE"
		# _C89_SLIB_PREFIX="SYS1"
		#
		# _CC_CLIB_PREFIX="SYS1.CBC"
		# _CC_PLIB_PREFIX="SYS1.CEE"
		# _CC_SLIB_PREFIX="SYS1"
		#
		# _CXX_CLIB_PREFIX="SYS1.CBC"
		# _CXX_PLIB_PREFIX="SYS1.CEE"
		# _CXX_SLIB_PREFIX="SYS1"
		#
		# Note: some might not be required if all the aliases have
		# been set correctly
		#
		EBCDIC ?= yes ;
		CC = cc ;
		C++ = c++ -+ ;
		$(GENFLAGS) += -D_OE_SOCKETS -DNO_LONG_LONG ;
		if $(EBCDIC) != no { $(GENFLAGS) += -DUSE_EBCDIC ; }
		if $(ASCII) = yes  { $(GENFLAGS) += -DNO_EBCDIC_FILES ; }
		LINK = c++ ;
		OPTIM = -O ;
		ZEROCONF = none ;


	case NETBSD* :
		OSCOMPDIR ?= /usr/pkg/gcc34/bin/ ;

		CC           = $(OSCOMPDIR:E)gcc ;
		C++          = $(OSCOMPDIR:E)g++ ;
		LINK         = $(OSCOMPDIR:E)gcc ;
		LINKLIBS    += -lsupc++ ;
		$(GENFLAGS) += -pipe -Dunix ;

		# NetBSD gcc choked on -O2 -fPIC
		if $(TYPE) = pic { OPTIM = -O1 -fPIC ; }

	case VMS* :
		# use C++ compiler: we're cheap
		CC       = cxx ;
		C++      = cxx ;
		DEFINES += NO_MEMCPY ;
		STRIP    = ;
		OPTIM    = ;

	case NT* :
		local _Z = /Zi ; # flag to put debug syms in .pdb file

		# Visual Studio 8 and earlier choke when writing .pdb files
		# to a networked drive; this variable provides a way to
		# override the pdb file directory.  Visual Studio 9
		# (VS2008) and later apparently are ok.
		PDBDIR ?= $(EXEC) ;

		if $(JAMFAST)
		{
			if $(PRODUCTION)
			{
				Exit Do not use JAMFAST with PRODUCTION, since JAMFAST embeds
				     debug symbols directly in object files. ;
			}

			# Put debug syms directly in object files.
			# If running jam with -j2 or greater, using a .pdb database
			# for the debug symbols may cause locking failures from
			# parallel compilation processes trying to access it.
			_Z = /Z7 ;
		}

		switch $(BUILD)
		{
		# When we do API builds, we set BUILD=vs2003, vs2005, etc.
		# These builds should have neither /Zi nor /Z7 symbol
		# instrumentation, because we don't want to ship debug
		# symbols to our customers, either embedded in the
		# .obj/.lib files or in the .pdb database which the linker
		# would want provided.
		case vs2* : _Z = ;
		}

		BINDIR    = e:\\perforce ;
		JAMSHELL ?= $(P4)\\Jamsh.bat $(OSPLAT) % "!" ;

		C++FLAGS += /DCASE_INSENSITIVE /DUSE_CRLF /wd4996 ;
		if $(SMARTHEAP) = yes { $(GENFLAGS) += /DUSE_SMARTHEAP ; }

		# Use setargv.obj to get wildcard expansion.
		# This is coupled with our own modified wildcard expander used by
		# setargv.obj in VS8 or later, per job030753.
		LINKLIBS  = setargv.obj advapi32.lib oldnames.lib
		            kernel32.lib ws2_32.lib ;


		if $(MSVSVER) >= 8
		   && ! $(TYPE_DYNAMIC) # 2008-10-17: static only for now
		{
			local _dyn ;
			if $(TYPE_DYNAMIC) = true { _dyn = -dyn ; }

			LINKLIBS += $(EXEC_LIB)/wild-vs$(MSVSVER)$(_dyn:E).obj ;
		}

		if $(OSPLAT) = IA64
		{
			# When using the windows 2003 SDK on IA64, the /GS flag is
			# enabled by default but even if you disable it for our own
			# builds, the libraries provided with the SDK itself were build
			# with /GS, so there's no way to avoid having to link against
			# this library.
			#
			# See http://support.microsoft.com/?id=894573
			LINKLIBS += bufferoverflowU.lib ;
		}

		# The "rc" tool needs MS headers:

		RCSTDHDRS = $(MSVCNT:J=" ")\\include
		            $(MSVCNT:J=" ")\\atlmfc\\include ;
		STRIP  = ;

		# Now, unset STDHDRS so Jam doesn't scan system headers (takes
		# too long when using compiler on networked machine):
		STDHDRS = ;

		if $(BCCROOT)
		{
			# Jeff Anton compiles with borland.

			OPTIM        = -O2 ;
			RCFLAGS      = /d NDEBUG /r ;
			AR           = tlib /C /P128 ;
			LINKLIBS     = $(BCCROOT)/lib/wildargs.obj ;
		}
		else if $(TYPE) = g
		{
			# Debugging build

			OPTIM = $(_Z) /Gm ;
			RCFLAGS      = /d DEBUG /r ;
			LINKFLAGS   += /DEBUG ;
			if $(CRT) = dyn
			{
				$(GENFLAGS) += /MDd ;
			}
			else
			{
				$(GENFLAGS) += /MTd ;
			}
		}
		else if $(TYPE) = dyn
		{
			# Dynamic link version, for qt products

			OPTIM = $(_Z) /O2 ;
			RCFLAGS      = /d NDEBUG /r ;
			$(GENFLAGS) += /MD ;

			LINKFLAGS += /MAP /DEBUG /OPT:REF /OPT:ICF ;
		}
		else if $(TYPE) = dyng
		{
			# Dynamic Debugging build
			if $(JAMFAST)
			{
				OPTIM = $(_Z) ;
			}
			else
			{
				OPTIM = $(_Z) /Gm ;
			}

			RCFLAGS      = /d DEBUG /r ;
			$(GENFLAGS) += /MDd ;
			LINKFLAGS   += /DEBUG /NODEFAULTLIB:msvcrt.lib  /fixed:no ;
		}
		else if $(TYPE) = vsdebug
		{
			# Static link with Visual Studio debug libraries.
			# This does not enable debugging our own code, just sets
			# linker dependencies for VS libraries.
			# This is intended for customer use.

			OPTIM        = /O2 ;
			RCFLAGS      = /d NDEBUG /r ;
			$(GENFLAGS) += /MTd ;
		}
		else if $(TYPE) = dyn_vsdebug
		{
			# Dynamic link with Visual Studio debug libraries.
			# This does not enable debugging our own code, just sets
			# linker dependencies for VS libraries.
			# This is intended for customer use.

			OPTIM        = /O2 ;
			RCFLAGS      = /d NDEBUG /r ;
			$(GENFLAGS) += /MDd ;
		}
		else if $(OSVER) = 98
		{
			# Dynamic link version for win98 version of p4win
			# Goes into bin.win98 -- oddity.

			EXEC = [ FSubDirPath P4BIN bin.win98 ] ;
			ALL_LOCATE_TARGET = $(EXEC) ;

			OPTIM        = /O2 ;
			if $(TYPE_DEBUG) = true { OPTIM += $(_Z) ; }

			RCFLAGS      = /d NDEBUG /r ;
			$(GENFLAGS) += /MD ;
			LINKFLAGS    = /MAP ;
		}
		else
		{
			# Static link version, for command line products

			OPTIM        = /O2 $(_Z) ;
			RCFLAGS      = /d NDEBUG /r ;
			if $(CRT) = dyn
			{
				$(GENFLAGS) += /MD ;
			}
			else
			{
				$(GENFLAGS) += /MT ;
			}
			LINKFLAGS   += /MAP /DEBUG /OPT:REF /OPT:ICF ;
		}

	    if $(OSPLAT) = X64
	    {
		# 64 bit windows needs increased stack size, so
		# we're doubling the stack from 2mb to 4mb.
		# See job31737.

		LINKFLAGS on p4d.exe = $(LINKFLAGS) /STACK:4194304 ;
	    }

	case QNXNTO* :
		CC = cc ;
		C++ = cc ;
		LINKLIBS += -lsocket ;

	case SCO* :
		C++ = gcc ;
		CC = gcc ;
		LINK = gcc ;
		LINKLIBS += -lsocket ;

	case SOLARIS* :
		switch $(OSCOMP)
		{
		case SUNC11 : # Sun Studio 11
			# Recommended jam flags: -sOSCOMP=SUNC11 -sBUILD=suncc
			# Add -sTYPE=pic for api.
			CC   = CC ;
			C++ = CC ;
			LINK = CC ;
			OPTIM = -xO3 ;

			if $(TYPE) = pic { OPTIM += -KPIC ; }

			switch $(OSPLAT)
			{
			case *64 :
				$(GENFLAGS) += -xarch=generic64 ;
				LINKFLAGS   += -xarch=generic64 ;
			}

		case SUNC12 : # Sun Studio 12
			# Recommended jam flags: -sOSCOMP=SUNC12 -sBUILD=suncc
			# Add -sTYPE=pic for api.
			CC   = CC ;
			C++ = CC ;
			LINK = CC ;
			OPTIM = -xO3 ;

			if $(TYPE) = pic { OPTIM += -KPIC ; }

			switch $(OSPLAT)
			{
			case *64 :
				$(GENFLAGS) += -m64 ;
				LINKFLAGS     += -m64 ;
			}

		case * : # GCC
			CC   = gcc ;
			C++  = g++ ;
			LINK = gcc ;

			switch $(OSPLAT)
			{
			case *64 : # X86_64 or SPARC64
				LINKFLAGS   += -m64 ;
				$(GENFLAGS) += -m64 ;
			}

			# supc++ needed for all apps since we use gcc >= 3.2.
			LINKLIBS += -lsupc++ ;
		}

		$(GENFLAGS) += -Dsolaris
		               -D_LARGEFILE64_SOURCE
		               -I/opt/lude/include ;

		LINKLIBS += -lsocket -lnsl ;
		AR    = /usr/ccs/bin/ar ru ;
		STRIP = /usr/ccs/bin/strip ;

		QTOPENGL ?= no ;

	case * :
		Exit Don't know "$(OS)$(OSVER) or " $(OS) ;
	}

	# Set build flags for chosen Zeroconf implementation
	if $(ZEROCONF) = bonjour
	{
	    DEFINES += USE_BONJOUR ;
	}
	if $(ZEROCONF) = avahi
	{
	    DEFINES += USE_AVAHI ;
	}

	if $(UNIX)
	{
		# Don't fail if directory already exists.
		MKDIR = mkdir -p ;
	}

#################################################
#
# Section 5.  Perforce-special rules and actions.
#
#################################################

	#
	# Special Rules
	#
	# FRemoveAny x : y ;        - return new array of x minus any values in y
	# FRegexpQuote list ;       - quote regexp metacharacters into literals
	# FDirEntries path : pat ;  - return a list of files matching pat in path
	# DefineVar src : var ;     - define a var for src compilation
	# Ident exe ;               - define bits for program ident string
	# ListAC ??? ;
	# P4ClientHdrs ;            - add all p4 client headers for building Web, ftp
	# P4Library lib : src ;     - Library of P4 client libs
	# P4DLibrary lib : src ;    - Library of P4D server libs
	# Strip exe ;               - strip executable of symbols after building
	# CopyRec target : dstdir : srcdir : excludes ; - recursively copy srcdir into dstdir
	#
	# And build packaging rules
	#
	# P4APIMakeDir apiname : files ; build api dist structure
	# P4Api apiname : files ; make archive files of api dist structure
	# MkDistArchive file : directory ; calls appropriate action based on file extension
	# MakeP4ObjCdist file ; Create Objective C API package
	# MakeP4DTGdist file ; Create p4dtg package
	# MakeP4ThumbDist file ; Create p4thumb package
	# MakeP4Vdist ; create p4v.tgz on unix systems or P4V.dmg on macosx

	rule FRemoveAny
	{
		# Usage: y = [ FRemoveAny $(x) : v1 v2 ... ] ;
		# returns new array with any occurence of v1, v2, etc from $(x) elided
		local _new ;
		local _elt ;
		for _elt in $(1)
		{
			if ! ( $(_elt) in $(2) ) { _new += $(_elt) ; }
		}
		return $(_new) ;
	}

	rule FRegexpQuote
	{
		# FRegexpQuote list ;
		# Quote any egrep(1) regexp metacharacters in elements of
		# list such that they will only match a literal expression.
		# Returns the quoted list.
		local result ;
		local p ;

		for p in $(<)
		{
			local q ;

			while (1)
			{
				local r = [ Match ^([^][()*+.?\\]*)([][()*+.?\\])(.*) : $(p) ] ;
				q += $(r[1]) ;
				if $(r[2]) = ""
				{
					q += $(p) ;
					break ;
				}
				q += \\$(r[2]) ;
				p = $(r[3]) ;
			}

			result += $(q:J=) ;
		}

		return $(result) ;
	}

	rule FDirEntries
	{
		# Usage: files = [ FDirEntries path to directory : pat ] ;
		# Returns list of entries in directory which match pat (default '*')

		local dir = [ FDirName $(<) ] ;
		local pat = $(>) ;
		if ! $(pat) { pat = "*" ; }

		local ents = [ Glob $(dir) : $(pat) ] ;             # => d/. d/.. d/a d/b
		# We need to quote windows directories because they use
		# backslashes, and those are regexp metacharacters.
		# Safer on unix too.
		local re   = [ FRegexpQuote $(dir)$(SLASH) ] ;
		ents = [ Match $(re)(.*) : $(ents) ] ;              # => . .. a b
		return [ FRemoveAny $(ents) : $(DOT) $(DOTDOT) ] ;  # return minus . and ..
	}

	rule DefineVar
	{
		# Usage: DefineVar foo.cc : VARNAME
		# Defines it if set

		if $($(>))
		{
		    ObjectDefines $(<) :
			[ Fconcat $(>)= [ FQuote \"$($(>))\" ] ] ;
		}
	}

	rule Ident
	{
		# Set up special defines

		local osid = $(OS)$(OSVER:E)$(OSPLAT:E) ;

		rule Fconcat { return $(<:J) ; }

		ObjectDefines $(<) :
		    [ Fconcat ID_OS= 	[ FQuote $(osid[1]:U) ] ]
		    [ Fconcat ID_REL= 	[ FQuote $(RELEASE:J=.) ] ]
		    [ Fconcat ID_PATCH= [ FQuote $(PATCHLEVEL)$(SPECIAL:E) ] ]
		    [ Fconcat ID_Y= 	[ FQuote $(SUPPDATE[1]) ] ]
		    [ Fconcat ID_M= 	[ FQuote $(SUPPDATE[2]) ] ]
		    [ Fconcat ID_D= 	[ FQuote $(SUPPDATE[3]) ] ] ;

		# Source file includes Version

		Includes [ FGristSourceFiles $(<) ] : Version ;
	}

	rule ListAC
	{
		# Special jam trickery to display AC numbers with "jam AC"

		NOTFILE $(<) ;
		ALWAYS $(<) ;
		SEARCH on $(>) = $(SEARCH_SOURCE) ;
		Depends $(<) : $(>) ;
	}

	actions ListAC
	{
		$(AWK) 'BEGIN {L=0; FS=","} /AC_/ {print L, $1; L++}' $(>)
	}

	rule MacRes
	{
		local _t = [ FAppendSuffix $(<) : $(SUFEXE) ] ;
		Depends $(_t) : $(>) ;
		SEARCH on $(>) = $(SEARCH_SOURCE) ;
	}

	rule MacCreatorCode
	{
		switch $(<)
		{
		    case p4v :
		    	return P4VC ;

		    case p4merge :
		    	return P4MG ;

		    case * :
		    	return ttxt ;
		}
	}

	rule P4ClientHdrs
	{
		# P4ClientHdrs ; - add p4 client headers for building Web, ftp

		SubDirHdrs $(P4) client ;
		SubDirHdrs $(P4) diff ;
		SubDirHdrs $(P4) i18n ;
		SubDirHdrs $(P4) middle ;
		SubDirHdrs $(P4) net ;
		SubDirHdrs $(P4) web ;
	}

	rule BoostHdrs
	{
		# Include boost without jam-crawling its maze of headers.
		# Don't use SubDirHdrs: Jam locks up if it tries to crawl boost.
		SubDirC++Flags -I$(BOOSTDIR)
		               -I$(BOOSTDIR)/tr1
		               -I$(BOOSTDIR)/boost/tr1 ;
	}

	rule P4Library
	{
		Library $(<) : $(>) ;
	}

	rule P4DLibrary
	{
		if $(BUILD_P4D) { Library $(<) : $(>) ; }
	}

	rule P4Main
	{
		Main $(<) : $(>) ;
		Strip $(<) ;
		if $(BINDIR) { InstallBin $(BINDIR) : $(<) ; }
	}

	rule P4DMain
	{
		if $(BUILD_P4D)
		{
		    P4Main $(<) : $(>) ;
		}
		else
		{
		    P4NoBuild $(<) : BUILD_P4D ;
		}
	}

	rule P4NoBuild
	{
		NotFile $(>) ;
	}

	actions quietly P4NoBuild
	{
		echo Set $(>) to force build of $(<).
	}

	rule LinkLibraries
	{
		# NB this is superfluous in jam 2.6

		# make library dependencies of target
		# set NEEDLIBS variable used by 'actions Main'

		local _t = [ FAppendSuffix $(<) : $(SUFEXE) ] ;
		local _s = [ FAppendSuffix $(>) : $(SUFLIB) ] ;

		Depends $(_t) : $(_s) ;
		NEEDLIBS on $(_t) += $(_s) ;
	}

	rule Strip
	{
		local _striptypes = opt pic dyn ;  # don't strip g variants
		if $(STRIP) && ( $(TYPE:E=opt) in $(_striptypes) )
		{
		    Strip1 $(<:S=$(SUFEXE)) ;
		}
	}

	actions Strip1
	{
		$(STRIP) $(<)
	}

	# CopyRec target : dstdir : srcdir : excludes ;
	# Recursively copies the contents of srcdir into dstdir
	# target is a non-file token to use for dependency generation
	# excludes are directory or file names not to copy.
	rule CopyRec
	{
		local target = $(1) ;
		local dst = [ FDirName $(2) ] ;
		local src = [ FDirName $(3) ] ;
		local excludes = $(4) ;
		local filepat = $(5) ;

		# Avoid duplicate recursion/dependencies if we've seen this
		# target already.
		if $($(dst)-CopyRec-seen) { return ; }
		$(dst)-CopyRec-seen = 1 ;

		NotFile $(target) ;

		# ents will be empty if src is not a directory
		local ents = [ Glob $(src) : * ] ; # => src/. src/.. src/a src/b
		if $(ents)
		{
			Depends $(target) : $(dst:G=dir) ;
			MkDir $(dst:G=dir) ;

			ents = [ FDirEntries $(src) ] ;

			local sub ;
			for sub in $(ents)
			{
				if $(sub) in $(excludes) { continue ; }
				CopyRec $(target) : $(dst) $(sub) : $(src) $(sub) : $(excludes) : $(filepat) ;
			}
		}
		else
		{
			if $(filepat)
			{
				local dir = $(src:P) ;
				local matches = [ Glob $(dir) : $(filepat) ] ;
				if ! $(src) in $(matches) { return ; }
			}

			local pdst = $(dst:PG=dir) ;

			Depends $(target) : $(dst) ;
			Depends $(dst) : $(pdst) ;
			MkDir $(pdst) ;

			if $(UNIX)
			{
				# For a recursive copy on unix we want to try to preserve
				# file timestamps and permissions (e.g. they might be
				# executables plain files).
				local CHMOD = ;
				CP on $(dst) = $(CP) -p ;
				File $(dst) : $(src) ;
 			}
			else
			{
				File $(dst) : $(src) ;
			}
		}
	}

	rule P4APIDirName
	{
		# P4APIDirName apiname ;
		#
		# The API should be copied into a temp subdirectory by P4APIMakeDir
		# and the API files copied into it.
		#
		# This rule computes the name of that directory, and the name of
		# the tar/zip file that it should be packed into, and returns a
		# list of those two names.
		#
		# This is a subroutine for clarity purposes, and is use both by
		# P4APIMakeDir and the DTG sdk builds to compute P4DIR.

		local _sep = "." ;       # directory name field separator
		if $(VMS)
		{
			_sep = "_" ;
		}

		# _dirname - apiname-releaseinfo
		# on nt: apiname-releaseinfo-build_type
		local _dirname = $(RELEASE[1-2]) $(PATCHLEVEL) $(RELEASE[3-]) ;
		_dirname = $(<)-$(_dirname:J=$(_sep)) ;
		local _arcname = $(<) ;
		if $(NT)
		{
			local _ntsuffix ;

			switch $(TYPE)
			{
			case dyn* : _ntsuffix = $(BUILD) $(TYPE) ;
			case opt  : _ntsuffix = $(BUILD) static ;
			case *    : _ntsuffix = $(BUILD) static $(TYPE) ;
			}

			_dirname = $(_dirname)-$(_ntsuffix:J=_) ;
			_arcname = $(<)_$(_ntsuffix:J=_) ;
		}

		return $(_dirname) $(_arcname) ;
	}

	rule P4APIMakeDir
	{
		# P4APIMakeDir apiname : files ;
		#
		# Builds a temp subdirectory $(EXEC)/apiname-releaseinfo
		# and copies the API files into it.
		#
		# Returns a list consisting of the api directory name
		# (usually api-releaseinfo, but possibly
		# api-releasinfo_build_type on NT), and the archive file
		# name (minus final suffix) into which the directory should
		# be stored.
		#
		# This is a subroutine for clarity purposes and probably
		# shouldn't be used directly except by the P4API rule.

		local _dirname_data = [ P4APIDirName $(<) ] ;
		local _dirname = $(_dirname_data[1]) ;
		local _arcname = $(_dirname_data[2]) ;

		local _cpflags ;
		if $(UNIX)
		{
			_cpflags = -p ; # to preserve times with cp -p
		}

		NotFile api ;
		Depends all : api ;

		MakeLocate $(_dirname) : $(EXEC) ;
		Depends api : $(_dirname) ;

		# SEARCH_SOURCE -- where api files are found (all over)

		local SEARCH_SOURCE =
		    $(HDRS) $(SUBDIRHDRS) $(SUBDIR) $(P4) ;

		# for each target file, copy to named temp directory
		# create mini structure (include/p4, lib, sample directories)

		local _f ;
		for _f in $(>)
		{
		    local _d _t ;

		    # Note that for .h and .cc files we use different
		    # grist $(x:G=alt), to distinguish these targets from
		    # the ones used in compiles.  We don't want #include
		    # processing on these.

		    switch $(_f)
		    {
		    case *.h   : _d = include p4 ; _f = $(_f:G=alt) ;
		    case *.a   : _d = lib        ;
		    case *.lib : _d = lib        ;
		    case *.olb : _d = lib        ;  # VMS library archive
		    case *.cc  : _d = sample     ; _f = $(_f:G=alt) ;
		    case *     : _d = sample     ;
		    }

		    _t = $(_f:G=$(<)) ;			                # target
		    _d = [ FDirName $(EXEC) $(_dirname) $(_d) ] ;	# directory

		    CP on $(_t) = $(CP) $(_cpflags) ;
		    MakeLocate $(_t) : $(_d) ;
		    File $(_t) : $(_f) ;
		    Depends api : $(_t) ;
		    Clean clean : $(_t) ;
		}

		return $(_dirname) $(_arcname) ;
	}

	rule P4Api
	{
		# P4Api apiname : files ;
		#
		# Builds a temporary subdirectory $(EXEC)/apiname-releaseinfo
		# and makes a tarball apiname.tar of that stuff.

		# _dirname - apiname-releaseinfo
		# on nt: apiname-releaseinfo-build_type
		local _apidata = [ P4APIMakeDir $(<) : $(>) ] ;
		local _dirname = $(_apidata[1]) ;
		local _arcname = $(_apidata[2]) ;

		local _tar     = $(_arcname:S=.tar) ;
		local _tgz     = $(_arcname:S=.tgz) ;
		local _zip     = $(_arcname:S=.zip) ;
		local _bck     = $(_arcname:S=.bck) ;
		local _targets = $(_tar) $(_tgz) $(_zip) ;

		if $(NT)
		{
			# This allows one to still be able to run the
			# command "jam p4api.tar" and have it work, even
			# though the actual file name will vary.
			Depends $(<:S=.tar) : $(_tar) ;
			Depends $(<:S=.tgz) : $(_tgz) ;
			Depends $(<:S=.zip) : $(_zip) ;
		}
		else if $(VMS)
		{
			_targets += $(_bck) ;
		}

		LOCATE on $(_targets) = $(EXEC) ;
		Depends $(_targets) : api ;

		MkTarArchive $(_tar) : $(_dirname) ;
		MkComressedTarArchive $(_tgz) : $(_dirname) ;
		MkZipArchive $(_zip) : $(_dirname) ;
		if $(VMS) { MkBckArchive $(_bck) : $(_dirname) ; }
	}

	rule MkDistArchive
	{
		local _trg ;

		for _trg in $(<)
		{
			switch $(_trg:S)
			{
			case .tar    : MkTarArchive          $(_trg) : $(>) ;
			case .tgz    : MkComressedTarArchive $(_trg) : $(>) ;
			case .tar.gz : MkComressedTarArchive $(_trg) : $(>) ;
			case .zip    : MkZipArchive          $(_trg) : $(>) ;
			case .bck    : MkBckArchive          $(_trg) : $(>) ;
			case *       : exit "Don't know how to make $(_trg)" ;
			}
		}
	}

	rule MakeBrowseDist
	{
		local release_info = $(RELEASE[1-2]) $(PATCHLEVEL) $(RELEASE[3-]) ;
		local dirname      = browse-$(release_info:J=.) ;
		local exec_dir     = [ FSubDirPath P4BIN bin.tools $(BUILD) ] ;
		local _f ;

		if ! $(browse-dist-dir-DONE)
		{
			browse-dist-dir-DONE = true ;

			MakeLocate $(dirname) : $(exec_dir) ;
			Depends browse-dist : $(dirname) ;

			local topdir = $(exec_dir) $(dirname) ;

			# Copy browse benchmarks scripts, documentation, etc.,
			# excluding all Jamfile and Jamrules files.
			CopyRec browse-dist : $(topdir) : $(AllP4) p4-tools benchmarks browse : Jamfile Jamrules ;

			# Change permissions on the browse private key so that
			# it can be successfully used with the user's SSH daemon.
			_f = [ FDirName $(topdir) browse ] ;
			MODE on $(_f) = 400 ;
			Chmod $(_f) ;

			# Change permissions on the browse JavaScript so that the configuration
			# defined within can be edited by the user, and change the line-endings
			# so that it can be easily edited using most Windows utilities.
			_f = [ FDirName $(topdir) browse.js ] ;
			MODE on $(_f) = 644 ;
			Chmod $(_f) ;
			Unix2Dos $(_f) ;

			# Change permissions on the browse Bourne shell script so that
			# the configuration defined within can be edited by the user.
			_f = [ FDirName $(topdir) browse.sh ] ;
			MODE on $(_f) = 755 ;
			Chmod $(_f) ;

			# Copy browsechild binaries for all platforms on which it was built.
			for _f in [ FDirEntries $(P4BIN) : bin.* ]
			{
				local bindir = [ FDirName $(P4BIN) $(_f) ] ;
				local prog = [ FDirEntries $(bindir) : browsechild browsechild.exe ] ;
				local _g ;

				for _g in $(prog)
				{
					CopyRec browse-dist : $(topdir) $(_f) $(_g) : $(bindir) $(_g) ;
				}
			}
		}

		LOCATE on $(<) = $(exec_dir) ;
		Depends $(<) : browse-dist ;
		Depends all : $(<) ;
		MkDistArchive $(<) : $(dirname) ;
	}

	rule MakeP4ConvertDist
	{
		local release_info = $(RELEASE[1-2]) $(PATCHLEVEL) $(RELEASE[3-]) ;
		local dirname      = p4convert-$(release_info:J=.) ;
		local topdir       = $(EXEC) $(dirname) ;

		local srcfiles     = $(2) ;

		MakeLocate $(dirname) : $(EXEC) ;
		Depends p4convert-dist : $(dirname) ;

		local _ent ;
		for _ent in $(srcfiles)
		{
			CopyRec p4convert-dist : $(topdir) $(_ent) : $(AllP4) p4-convert svn $(_ent) ;
		}
		CopyRec p4convert-dist : $(topdir) p4convert-svn : p4convert-svn ;

		LOCATE on $(<) = $(EXEC) ;
		Depends $(<) : p4convert-dist ;
		Depends all : $(<) ;
		MkDistArchive $(<) : $(dirname) ;
	}

	rule MakeP4ObjCdist
	{
		local release_info = $(RELEASE[1-2]) $(PATCHLEVEL) $(RELEASE[3-]) ;
		local dirname      = p4objc-$(release_info:J=.) ;
		local exec_dir     = [ FSubDirPath P4BIN bin.tools $(BUILD) ] ;

		MakeLocate $(dirname) : $(exec_dir) ;
		Depends p4objc-dist : $(dirname) ;

		local topdir = $(exec_dir) $(dirname) ;
		CopyRec p4objc-dist : $(topdir) LICENSE.txt : $(AllP4) p4-objc LICENSE.txt ;
		CopyRec p4objc-dist : $(topdir) api         : $(AllP4) p4-objc api ;
		CopyRec p4objc-dist : $(topdir) doc         : $(AllP4) p4-objc doc ;

		# When we copy images from the sample, we want to exclude
		# the ones that we override from the watermarked images
		# directory.  So exclude those (and the watermark images
		# directory itself), then copy the watermarked ones in.
		local watermark_dir = $(AllP4) p4-objc sample resources images_watermarked ;
		local watermark_excludes = [ FDirEntries $(watermark_dir) ] ;
		local all_excludes = build ._build images_watermarked $(watermark_excludes) ;
		CopyRec p4objc-dist : $(topdir) sample : $(AllP4) p4-objc sample : $(all_excludes) ;

		# Now copy in the watermarked images
		local _ent ;
		for _ent in $(watermark_excludes)
		{
			CopyRec p4objc-dist : $(topdir) sample resources images $(_ent) : $(watermark_dir) $(_ent) ;
		}

		LOCATE on $(<) = $(exec_dir) ;
		Depends $(<) : p4objc-dist ;
		Depends all : $(<) ;
		MkDistArchive $(<) : $(dirname) ;
	}

	rule MakeP4ScoutDist
	{
		local kind = $(<) ;
		local appdir = <$(kind)>P4Scout.app ;
		local zipfiles = $(kind)-$(appdir:G=).zip $(kind)-$(appdir:G=).dSYM.zip ;

		local srcdir = $(AllP4) p4-objc sample ;
		SCOUTSRCDIR on $(appdir) = [ FDirName $(srcdir) ] ;

		Depends p4scout-dist : p4scout-dist-$(kind) ;
		Depends p4scout-dist-$(kind) : $(appdir) ;
		Depends $(appdir) : p4api.tgz ;

		LOCATE on $(zipfiles) = $(EXEC) ;
		Depends $(zipfiles) : $(appdir) ;

		on $(appdir) NOTFILE $(kind) ;
		P4Scout_xcodebuild $(appdir) : $(kind) ;
	}

	rule MakeP4PHPdist
	{
		local release_info = $(RELEASE[1-2]) $(PATCHLEVEL) $(RELEASE[3-]) ;
		local dirname      = p4php-$(release_info:J=.) ;
		local exec_dir     = [ FSubDirPath P4BIN bin.tools $(BUILD) ] ;
		local topdir       = $(exec_dir) $(dirname) ;

		MakeLocate $(dirname) : $(exec_dir) ;
		Depends p4php-dist : $(dirname) ;

		local excludes = docs [ FDirEntries $(AllP4) p4-php : Jam* *~ ] ;
		CopyRec p4php-dist : $(topdir)              : $(AllP4) p4-php : $(excludes) ;
		CopyRec p4php-dist : $(topdir) RELNOTES.txt : $(AllP4) p4-doc user p4phpnotes.txt ;
		CopyRec p4php-dist : $(topdir) Version      : $(AllP4) p4 Version ;

		LOCATE on $(<) = $(exec_dir) ;
		Depends $(<) : p4php-dist ;
		Depends all : $(<) ;
		MkDistArchive $(<) : $(dirname) ;
	}

	rule MakeP4DTGdist
	{
		local release_info = $(RELEASE[1-2]) $(PATCHLEVEL) $(RELEASE[3-]) ;
		local dirname = p4dtg-$(release_info:J=.) ;

		local topdir    = $(EXEC) $(dirname) ;
		local bugzdir   = $(EXEC) $(dirname) doc bugz3mysql5 ;
		local mysqldir  = $(EXEC) $(dirname) doc mysql5 ;

		MakeLocate $(dirname) : $(EXEC) ;
		Depends p4dtg-dist : $(dirname) ;

		CopyRec p4dtg-dist : $(topdir) p4dtg-config           : p4dtg-config ;
		CopyRec p4dtg-dist : $(topdir) p4dtg-test             : p4dtg-test ;
		CopyRec p4dtg-dist : $(topdir) p4dtg-repl             : p4dtg-repl ;

		CopyRec p4dtg-dist : $(topdir) plugins p4jobdt.so     : p4jobdt.so ;
		CopyRec p4dtg-dist : $(topdir) plugins bugz3mysql5.so : bugz3mysql5.so ;
		CopyRec p4dtg-dist : $(topdir) plugins mysql5.so      : mysql5.so ;

		CopyRec p4dtg-dist : $(topdir) p4dtg-config.png       : $(P4DTG) src p4dtg-config p4dtg-config.png ;
		CopyRec p4dtg-dist : $(topdir) p4dtgnotes.txt         : $(AllP4) p4-doc user p4dtgnotes.txt ;
		CopyRec p4dtg-dist : $(topdir) p4dtg.pdf              : $(AllP4) p4-doc manuals p4dtg p4dtg.pdf ;

		CopyRec p4dtg-dist : $(topdir) help                   : $(AllP4) p4-doc help p4dtg ;

		CopyRec p4dtg-dist : $(bugzdir) patch.bugzilla-3      : $(P4DTG) sdk bugz patch.bugzilla-3 ;
		CopyRec p4dtg-dist : $(bugzdir) patch.bugzilla-3.4    : $(P4DTG) sdk bugz patch.bugzilla-3.4 ;
		CopyRec p4dtg-dist : $(bugzdir) README.txt            : $(P4DTG) sdk bugz README.txt ;
		CopyRec p4dtg-dist : $(bugzdir) README.p4dti.txt      : $(P4DTG) sdk bugz README.p4dti.txt ;
		CopyRec p4dtg-dist : $(bugzdir) mk_dtgdtissue.pl      : $(P4DTG) sdk bugz mk_dtgdtissue.pl ;
		CopyRec p4dtg-dist : $(bugzdir) dti_to_dtg.pl         : $(P4DTG) sdk bugz dti_to_dtg.pl ;
		CopyRec p4dtg-dist : $(bugzdir) changeid.pl           : $(P4DTG) sdk bugz changeid.pl ;
		CopyRec p4dtg-dist : $(bugzdir) jobspec.txt           : $(P4DTG) sdk bugz jobspec.txt ;

		CopyRec p4dtg-dist : $(mysqldir) README.txt           : $(P4DTG) sdk mysql README.txt ;
		CopyRec p4dtg-dist : $(mysqldir) import.pl            : $(P4DTG) sdk mysql import.pl ;

		local empty_dirs = config repl ;
		local _d ;
		for _d in $(empty_dirs)
		{
			_d = [ FDirName $(topdir) $(_d) ] ;
			MkDir $(_d:G=dir) ;
			Depends p4dtg-dist : $(_d:G=dir) ;
		}

		local _strip_bin = p4dtg-config p4dtg-repl p4dtg-test ;
		local _strip_lib = plugins/bugz3mysql5.so plugins/p4jobdt.so plugins/mysql5.so ;
		local _f ;
		for _f in $(_strip_bin)
		{
			_f = [ FDirName $(topdir) $(_f) ] ;
			Strip $(_f) ;
		}
		for _f in $(_strip_lib)
		{
			_f = [ FDirName $(topdir) $(_f) ] ;
			STRIP on $(_f) = $(STRIP) -x ;
			Strip1 $(_f) ;
		}

		LOCATE on $(<) = $(EXEC) ;
		Depends $(<) : p4dtg-dist ;
		Depends all : $(<) ;
		MkDistArchive $(<) : $(dirname) ;
	}

	rule MakeP4ThumbDist
	{
		local topdir ;

		if $(OS) = NT
		{
			# Hopefully this is temporary, to be replaced with a proper installer.
			topdir = p4thumb ;

			local bindir = $(EXEC) $(topdir) ;
			local libdir = $(EXEC) $(topdir) ;
			local rscdir = $(EXEC) $(topdir) ;

			MakeLocate $(topdir) : $(EXEC) ;
			Depends p4thumb-dist : $(topdir) ;

			CopyRec p4thumb-dist : $(bindir) p4thumb.exe      : p4thumb.exe ;
			CopyRec p4thumb-dist : $(bindir) vcredist_x86.exe : $(EXEC_LIB) vcredist_x86.exe ;
			CopyRec p4thumb-dist : $(bindir) assistant.exe    : $(EXEC_LIB) assistant.exe ;
			CopyRec p4thumb-dist : $(libdir) plugins          : $(EXEC_LIB) qt4 plugins : : *.dll ;
			CopyRec p4thumb-dist : $(rscdir) p4thumbnotes.txt : $(AllP4) p4-doc user p4thumbnotes.txt ;

			CopyRec p4thumb-dist : $(rscdir) translations     : $(EXEC_LIB) qt4 translations ;
			for _f in p4thumb_$(QtLanguages).qm
			{
				CopyRec p4thumb-dist : $(rscdir) translations $(_f) : $(_f) ;
			}

			local Qtdlls = [ FDirEntries $(EXEC_LIB) : *4.dll ] ;
			local _dll ;
			for _dll in $(Qtdlls)
			{
				CopyRec p4thumb-dist : $(libdir) $(_dll) : $(EXEC_LIB) $(_dll) ;
			}

			MakeQtConf p4thumb-dist : $(bindir) ;
		}
		else
		{
			local release_info = $(RELEASE[1-2]) $(PATCHLEVEL) $(RELEASE[3-]) ;
			topdir = p4thumb-$(release_info:J=.) ;

			local bindir = $(EXEC) $(topdir) bin ;
			local libdir = $(EXEC) $(topdir) lib p4v ;
			local rscdir = $(EXEC) $(topdir) lib p4v P4VResources ;

			MakeLocate $(topdir) : $(EXEC) ;
			Depends p4thumb-dist : $(topdir) ;

			CopyRec p4thumb-dist : $(bindir) p4thumb.bin : p4thumb ;
			CopyRec p4thumb-dist : $(bindir) p4thumb     : $(AllP4) p4-qt apps p4v p4vwrapper.sh ;
			CopyRec p4thumb-dist : $(libdir) qt4         : $(EXEC_LIB) qt4 ;

			CopyRec p4thumb-dist : $(rscdir) translations     : $(EXEC_LIB) qt4 translations ;
			for _f in p4thumb_$(QtLanguages).qm
			{
				CopyRec p4thumb-dist : $(rscdir) translations $(_f) : $(_f) ;
			}

			MakeQtConf p4thumb-dist : $(bindir) ;

			STRIP on [ FDirName $(bindir) p4thumb.bin ] = $(STRIP) -x ;
			Strip1 [ FDirName $(bindir) p4thumb.bin ] ;
		}

		LOCATE on $(<) = $(EXEC) ;
		Depends $(<) : p4thumb-dist ;
		Depends all : $(<) ;
		MkDistArchive $(<) : $(topdir) ;
	}

	rule MakeP4Vdist
	{
		if $(OS) = MACOSX
		{
			MakeP4Vdist_macosx $(<) ;
		}
		else if $(UNIX)
		{
			MakeP4Vdist_unix $(<) ;
		}
		# TODO: Add switch for NT to build installer
	}

	rule MakeP4Vdist_unix
	{
		local release_info = $(RELEASE[1-2]) $(PATCHLEVEL) $(RELEASE[3-]) ;
		local topdir  = p4v-$(release_info:J=.) ;
		local bindir  = $(EXEC) $(topdir) bin ;
		local libdir  = $(EXEC) $(topdir) lib p4v ;
		local rscdir  = $(EXEC) $(topdir) lib p4v P4VResources ;
		local helpsrc = $(AllP4) p4-doc help ;
		local _f ;

		MakeLocate $(topdir) : $(EXEC) ;
		Depends p4v-dist : $(topdir) ;

		## Copy in the qt-based commands with shell wrapper
		local qtcmd = p4v p4merge p4admin ;
		for _f in $(qtcmd)
		{
			CopyRec p4v-dist : $(bindir) $(_f).bin : $(_f) ;
			CopyRec p4v-dist : $(bindir) $(_f)     : $(AllP4) p4-qt apps p4v p4vwrapper.sh ;

			# Make sure they're all at least stripped of local symbols
			_f = [ FDirName $(bindir) $(_f).bin ] ;
			STRIP on $(_f) = $(STRIP) -x ;
			Strip1 $(_f) ;

		}

		## Offline broker and server components.
		local p4ddir = $(EXEC) ;
		if $(TYPE_DYNAMIC) { p4ddir += .. ; }
		CopyRec p4v-dist : $(rscdir) p4d  : $(p4ddir) p4d ;
		CopyRec p4v-dist : $(rscdir) p4ob : p4ob ;

		_f = [ FDirName $(rscdir) p4ob ] ;
		STRIP on $(_f) = $(STRIP) -x ;
		Strip1 $(_f) ;

		## Assistant executable
		CopyRec p4v-dist : $(bindir) assistant    : $(EXEC_LIB) assistant_dyn ;

		# Libraries, plugins, qt standard translation catalogs
		CopyRec p4v-dist : $(libdir) qt4 lib      : $(EXEC_LIB) qt4 lib ;
		CopyRec p4v-dist : $(libdir) qt4 plugins  : $(EXEC_LIB) qt4 plugins ;
		CopyRec p4v-dist : $(rscdir) translations : $(EXEC_LIB) qt4 translations ;

		## Image resources
		CopyRec p4v-dist : $(rscdir) images.rcc          : images.rcc ;
		# job034811 - people use these for shortcut icons
		CopyRec p4v-dist : $(rscdir) icons               : $(helpsrc) icons ;

		## Documentation
		for _f in $(QtLanguages)
		{
			# FIXME (noahf): This is almost ready but needs some runtime (nfs locking) debugging
			# For now we are just copying pre-built collections below.
			#QtHelpGen           : $(helpsrc) p4v-html-pure $(_f) p4vhelp_$(_f).qhp  ;
			#QtHelpCollectionGen : $(helpsrc) p4v-html-pure $(_f) p4vhelp_$(_f).qhcp ;
			#
			#QtHelpGen           : $(helpsrc) p4merge $(_f) p4mergehelp_$(_f).qhp  ;
			#QtHelpCollectionGen : $(helpsrc) p4merge $(_f) p4mergehelp_$(_f).qhcp ;
			#
			#QtHelpGen           : $(helpsrc) p4admin-html-pure $(_f) p4adminhelp_$(_f).qhp ;
			#QtHelpCollectionGen : $(helpsrc) p4admin-html-pure $(_f) p4adminhelp_$(_f).qhcp ;


			CopyRec p4v-dist : $(rscdir) p4vhelp p4vhelp_$(_f).qhc : $(helpsrc) p4v-html-pure $(_f) p4vhelp_$(_f).qhc ;
			CopyRec p4v-dist : $(rscdir) p4vhelp p4vhelp_$(_f).qch : $(helpsrc) p4v-html-pure $(_f) p4vhelp_$(_f).qch ;

			CopyRec p4v-dist : $(rscdir) p4mergehelp p4mergehelp_$(_f).qhc : $(helpsrc) p4merge $(_f) p4mergehelp_$(_f).qhc ;
			CopyRec p4v-dist : $(rscdir) p4mergehelp p4mergehelp_$(_f).qch : $(helpsrc) p4merge $(_f) p4mergehelp_$(_f).qch ;

			CopyRec p4v-dist : $(rscdir) p4adminhelp p4adminhelp_$(_f).qhc : $(helpsrc) p4admin-html-pure $(_f) p4adminhelp_$(_f).qhc ;
			CopyRec p4v-dist : $(rscdir) p4adminhelp p4adminhelp_$(_f).qch : $(helpsrc) p4admin-html-pure $(_f) p4adminhelp_$(_f).qch ;

		}
		CopyRec p4v-dist : $(rscdir) p4vhelp p4v-gs.pdf    : $(AllP4) p4-doc manuals p4v-gs p4v-gs.pdf ;
		CopyRec p4v-dist : $(rscdir) p4vhelp p4v-gs_ja.pdf : $(AllP4) p4-doc manuals p4v-gs p4v-gs_ja.pdf ;


		## Translation files

		for _f in $(qtcmd)_$(QtLanguages).qm
		{
			CopyRec p4v-dist : $(rscdir) translations $(_f) : $(_f) ;
		}
		CopyRec p4v-dist : $(rscdir) translations msg_ja.txt : $(AllP4) p4-offline translations msg_ja.txt ;

		## Example files

		local examples = basic_p4vdefaults.xml
		                 basic_p4vfeatures.xml
		                 p4vdefaults.xml
		                 p4vfeatures.xml ;
		for _f in $(examples)
		{
			CopyRec p4v-dist : $(rscdir) examples $(_f) : $(AllP4) p4-qt doc $(_f) ;
		}

		MakeQtConf p4v-dist : $(bindir) ;

		LOCATE on $(<) = $(EXEC) ;
		Depends $(<) : p4v-dist ;
		Depends all : $(<) ;
		MkDistArchive $(<) : $(topdir) ;
	}

	rule MakeP4Vdist_macosx
	{
		local apps = p4v p4merge p4admin ;
		local Contents Resources ;
		local _f ;

		LOCATE on $(<) = $(EXEC) ;
		Depends $(<) : p4v-dist ;
		Depends p4v-dist : $(apps) ;

		# For each app, do the following:
		#   * Copy in frameworks and plugins
		#   * Copy in common image resources.
		#   * Generate qt.conf
		#   * Fix dylib references in exe and install VersionCheck wrapper
		local app ;
		for app in $(apps)
		{
			Contents  = $(EXEC) $(app).app Contents ;
			Resources = $(Contents) Resources ;

			CopyRec p4v-dist : $(Contents)  Frameworks   : $(EXEC_LIB) Frameworks ;
			CopyRec p4v-dist : $(Contents)  PlugIns      : $(EXEC_LIB) PlugIns ;
			CopyRec p4v-dist : $(Resources) translations : $(EXEC_LIB) translations ;
			CopyRec p4v-dist : $(Resources) images.rcc   : images.rcc ;
			CopyRec p4v-dist : $(Resources) empty.lproj  : /dev/null ;

			# Translation files
			for _f in $(app)_$(QtLanguages).qm
			{
				CopyRec p4v-dist : $(Resources) translations $(_f) : $(_f) ;
			}

			MakeQtConf p4v-dist : $(Resources) ;

			local _real = [ FDirName $(Contents) MacOS $(app) ] ;
			# Must use the same grist here as in QtMacPackage.
			_real = $(_real:G=$(app)) ;
			_real = $(_real).real ;

			Depends p4v-dist : $(_real) ;
			Depends $(_real) : $(app) ;
			MacP4VdyldFixup $(_real) : $(app) ;
		}

		#
		# app-specific prep for p4v.app
		#
		Resources = $(EXEC) p4v.app Contents Resources ;

		MacP4Vassistant p4v-dist : $(Resources) : $(AllP4) p4-qt apps p4v img p4v_help.icns ;
		for _f in $(QtLanguages)
		{
			CopyRec p4v-dist : $(Resources) Help p4vhelp_$(_f).qhc : $(AllP4) p4-doc help p4v-html-pure $(_f) p4vhelp_$(_f).qhc ;
			CopyRec p4v-dist : $(Resources) Help p4vhelp_$(_f).qch : $(AllP4) p4-doc help p4v-html-pure $(_f) p4vhelp_$(_f).qch ;
		}
		CopyRec p4v-dist : $(Resources) Help p4v-gs.pdf    : $(AllP4) p4-doc manuals p4v-gs p4v-gs.pdf ;
		CopyRec p4v-dist : $(Resources) Help p4v-gs_ja.pdf : $(AllP4) p4-doc manuals p4v-gs p4v-gs_ja.pdf ;

		# Offline broker and p4d components
		CopyRec p4v-dist : $(Resources) p4d  : [ MakeP4Vdist_macosx_compute_p4d_directory ] p4d ;
		CopyRec p4v-dist : $(Resources) p4ob : p4ob ;
		CopyRec p4v-dist : $(Resources) translations msg_ja.txt : $(AllP4) p4-offline translations msg_ja.txt ;


		local examples = basic_p4vdefaults.xml
		                 basic_p4vfeatures.xml
		                 p4vdefaults.xml
		                 p4vfeatures.xml ;
		for _f in $(examples)
		{
			CopyRec p4v-dist : $(Resources) examples $(_f) : $(AllP4) p4-qt doc $(_f) ;
		}

		#
		# app-specific prep for p4merge.app
		#
		Resources = $(EXEC) p4merge.app Contents Resources ;

		MacP4Vassistant p4v-dist : $(Resources) : $(AllP4) p4-qt apps p4merge img p4_merge_help.icns ;
		for _f in $(QtLanguages)
		{
			CopyRec p4v-dist : $(Resources) Help p4mergehelp_$(_f).qhc : $(AllP4) p4-doc help p4merge $(_f) p4mergehelp_$(_f).qhc ;
			CopyRec p4v-dist : $(Resources) Help p4mergehelp_$(_f).qch : $(AllP4) p4-doc help p4merge $(_f) p4mergehelp_$(_f).qch ;
		}
		CopyRec p4v-dist : $(Resources) launchp4merge           : p4merge_mac_shim ;

		#
		# app-specific prep for p4admin.app
		#
		Resources = $(EXEC) p4admin.app Contents Resources ;

		# TODO: p4admin assistant may need its own icon; check with dev
		MacP4Vassistant p4v-dist : $(Resources) : $(AllP4) p4-qt apps p4v img p4v_help.icns ;
		for _f in $(QtLanguages)
		{
			CopyRec p4v-dist : $(Resources) Help p4adminhelp_$(_f).qhc : $(AllP4) p4-doc help p4admin-html-pure $(_f) p4adminhelp_$(_f).qhc ;
			CopyRec p4v-dist : $(Resources) Help p4adminhelp_$(_f).qch : $(AllP4) p4-doc help p4admin-html-pure $(_f) p4adminhelp_$(_f).qch ;
		}

		buildDMG $(<) : $(EXEC:G=dir)/$(apps:S=.app) ;
 	}

	rule MakeP4Vdist_macosx_compute_p4d_directory
	{
		# Finding the server executable for the offline component of p4v on
		# the mac is slightly nasty because we build with OS=MACOSX for the
		# Qt components, and OS=DARWIN for the server component.
		#
		# Furthermore, we have to keep a map of the corresponding OSVER
		# numbers between OSX and Darwin.  And, we want to use the nightly
		# builds of the server if we are making a nightly build.

		local _darwin_osver ;
		switch $(OSVER)
		{
		case 104 : _darwin_osver = 80 ;
		case 105 : _darwin_osver = 90 ;
		}

		local _platform = darwin $(_darwin_osver) $(OSPLAT:L) ;
		local _path = $(AllP4) p4-bin bin.$(_platform:J="") $(BUILD) ;
		return $(_path) ;
	}

	rule MacP4Vassistant
	{
		# Install the assistant into app's resources directory.
		# The assistant comes straight from the TrollTech distribution for
		# now, though someday we may make our own branded version.

		local target    = $(1) ;
		local Resources = [ FDirName $(2) ] ;
		local icons     = [ FDirName $(3) ] ;

		local assistant_tar = assistant_dyn.tar ;
		LOCATE on $(assistant_tar) = $(EXEC_LIB) ;

		local dst = <$(Resources)>Assistant.app ;
		MakeLocate $(dst) : $(Resources) ;
		Depends $(target) : $(dst) ;

		ASSISTANT_ICONS on $(dst) = $(icons) ;
		MacP4Vassistant_install $(dst) : $(assistant_tar) ;

		local asst_Resources = $(Resources) Assistant.app Contents Resources ;

		MakeQtConf $(dst) : $(asst_Resources) ;
		CopyRec $(target) : $(asst_Resources)  translations : $(EXEC_LIB) translations ;
	}

	# Untar the assistant tar file and copy our custom icon into the assistant.
	actions MacP4Vassistant_install
	{
		tar -xpvf $(>) -C $(<:P)
		cp $(ASSISTANT_ICONS) $(<)/Contents/Resources/assistant.icns
	}

	# The copying of SystemVersionCheck ideally should be a separate
	# rule/action, but it's difficult to get Jam to replace one file
	# with another except incidentally, and here we are kind of moving
	# (and modifying) the original target, so here is as good a place
	# as any to do it.
	actions MacP4VdyldFixup
	{
		$(CP) -p "$(>)" "$(<)" || exit 1
		otool -X -L "$(<)" \
		  | sed -n \
		        -e '/@executable_path/d' \
		        -e 's/ *(compat.*//' \
		        -e 's/^[ 	]*//' \
		        -e '/^\//!p' \
		  | while read dep ; do
		      toprel=`echo "$dep" \
		               | sed -e 's=.*/\([^/]*.framework/\)=\1=' \
		                     -e 's=^/.*/=='`
		      new=@executable_path/../Frameworks/$toprel
		      install_name_tool -change "$dep" "$new" "$(<)"
		    done
		$(CP) $(EXEC_LIBEXEC)/SystemVersionCheck "$(>)"
	}

	actions buildDMG
	{
		$(AllP4)/tools/scripts/buildDMG.pl \
			-debug \
			-compressionLevel 9 \
			-buildDir $(EXEC) \
			-dmgName $(<:B) \
			-volName $(<:B) \
			$(>)
	}

	rule MakeQtConf
	{
		local target = $(1) ;
		local dir    = [ FDirName $(2:G=) ] ;

		local qtconf = <$(dir)>qt.conf ;
		MakeLocate $(qtconf) : $(dir) ;
		Depends $(target) : $(qtconf) ;
		MakeQtConf1 $(qtconf) ;
		MODE on $(qtconf) = $(FILEMODE) ;
		Chmod $(qtconf) ;
	}

	actions MkTarArchive
	{
		tar -cf $(<) -C $(>:P) $(>:BE)$(>:SE)
	}

	actions MkZipArchive
	{
		cd $(<:P)
		zip -9 -r -q $(<:BE)$(<:SE) $(>:BE)$(>:SE)
	}

	actions MkComressedTarArchive
	{
		tar -cf - -C $(>:P) $(>:BE)$(>:SE) | $(COMPRESS) > $(<)
	}

	actions Unix2Dos
	{
		unix2dos -q $(<) ;
	}

	rule LinkSmartHeap
	{
		if $(SMARTHEAP) = yes
		{
			local _64 = "" ;
			local   d = "" ;

			if $(OSPLAT) = X86_64 || $(OSPLAT) = X64 { _64 = 64 ; }
			if $(TYPE) = g { d = d ; }

			switch $(OS)-$(OSVER:E)-$(OSPLAT:E)-$(OSCOMP:E)
			{
			case NT-*-X*-* :
				SMARTHPLIB ?= $(EXEC_LIB)\\shlSMP$(_64)Mt$(d).lib ;

				local e = [ FAppendSuffix $(<) : $(SUFEXE) ] ;
				LINKLIBS on $(e) = $(SMARTHPLIB) $(LINKLIBS) ;

			case LINUX-*-X86*-* :
				SMARTHPLIB ?= $(EXEC_LIB)/libsmartheapC$(d)$(_64).a
			                      $(EXEC_LIB)/libsmartheap$(d)$(_64).a ;

				# Per-target LINKLIBS need to incorporate global libs
				# too (e.g. libsupc++), but they should come after the
				# smartheap libs.
				LINKLIBS on $(<) = $(SMARTHPLIB) $(LINKLIBS) ;

				# Ignore a couple of duplicate symbol definitions in
				# exception handler code between some of the smartheap 9.01
				# objects and libsupc++ (or static libstdc++).
				#
				# We aren't using exception handlers anyway, but there is
				# no other way to work around this problem at link time
				# without upgrading to gcc 4.1 for our builds; we're still
				# using gcc 3.4.5.
				LINKFLAGS on $(<) = $(LINKFLAGS) -Wl,-z,muldefs ;
			}
		}
	}

#################################################
#
# Section 5.  Perforce-special Windows rules.
#
#################################################

	#
	# Special p4-win/scc/p4-exp rules:
	#
	# P4EXPDefines - set C++ flags for P4-EXP
	# P4EXPDOTH file : file ; - wrapper for p4exp.h dependencies
	# P4EXPDOTHDEPENDS files : file ; - wrapper for files dependant on p4exp.h
	# P4EXPMIDL file : file ; - set up files for MIDL compiling
	# EXPMIDL file : file ; - compile .idl file
	# EXP64MIDL file : file ; - compile .idl file for 64 bit Windows
	# P4EXPLinkage exe : libs ; - set up link flags windows exe
	#
	# P4SccDefines - set C++ flags for (old) p4scc.dll
	#
	# P4WinDefines - set C++ flags for p4-win/gui
	# P4WinDiffDefines - set C++ flags for p4-win/diff, merge
	#
	# WinDefines opts : defines ; - set C++ flags for p4-win
	# WinDllDeffile exe : file ; - set /def: file for link
	# WinDllLinkage exe : libs ; - set up link flags windows DLL
	# WinDllNoMain exe ; - setup exe with no main
	# WinLinkage exe : libs ; - set up link flags windows exe
	# WinRes exe : *.rc : flags ; - compile .rc->.res, link against exe
	# WinResIdent *.rc ; - set special defines for build identification
	#

	rule P4RPTCLILinkage
	{
	    local _lf = /subsystem:console ;

	    switch $(TYPE_DEBUG)
	    {
	    case true : _lf += /DEBUG ;
	    case *    : _lf += /MAP ;
	    }

	    _lf += /INCREMENTAL:NO ;
	    _lf += /NODEFAULTLIB:"libcmt" ;
	    _lf += /NODEFAULTLIB:"libc" ;

	    switch $(OSPLAT)
	    {
	    case X86 : _lf += /MACHINE:x86 ;
	    }

	    LINKFLAGS on $(<) = $(LINKFLAGS) $(_lf) ;

	    LINKLIBS on $(<) =
	    gdi32.lib comctl32.lib shlwapi.lib user32.lib
	    version.lib shell32.lib advapi32.lib oldnames.lib
	    kernel32.lib ws2_32.lib winmm.lib odbc32.lib
	    odbccp32.lib $(2) ;
	}

	rule P4GTLinkage
	{
	    local _lf = /subsystem:windows ;

	    switch $(TYPE_DEBUG)
	    {
	    case true : _lf += /DEBUG ;
	    case *    : _lf += /MAP ;
	    }

	    _lf += /DLL ;
	    _lf += /INCREMENTAL:NO ;
	    _lf += /NODEFAULTLIB:"libcmt" ;
	    _lf += /NODEFAULTLIB:"libc" ;

	    switch $(OSPLAT)
	    {
	    case X86 : _lf += /MACHINE:x86 ;
	    case X64 : _lf += /MACHINE:x64 ;
	    }

	    LINKFLAGS on $(<) = $(LINKFLAGS) $(_lf) ;

	    if $(OSPLAT) != X64 {
	    LINKLIBS on $(<) =
	    $(P4GT)/htmlhelp/htmlhelp.lib
	    gdi32.lib comctl32.lib shlwapi.lib user32.lib
	    version.lib shell32.lib advapi32.lib oldnames.lib
	        kernel32.lib ws2_32.lib winmm.lib odbc32.lib
	        odbccp32.lib $(2) ;
	    }
	    else {
	        LINKLIBS on $(<) =
	        $(P4GT)/htmlhelp/htmlhelp_x64.lib
	        gdi32.lib comctl32.lib shlwapi.lib user32.lib
	        version.lib shell32.lib advapi32.lib oldnames.lib
	        kernel32.lib ws2_32.lib winmm.lib odbc32.lib
	    odbccp32.lib $(2) ;
	}
	}

	rule P4GTDefines
	{
	    if $(MSVSVER) >= 8 {
		C++FLAGS += /Zc:wchar_t- ;
		WinDefines /GR : _USRDLL _WINDLL NT_PLUGIN ;
	    }
	    else
	    {
	        WinDefines /GR /GX : _USRDLL _WINDLL NT_PLUGIN ;
	    }

	    #
	    # Setting environment variable "LANG=ja" triggers Japanese
	    # localized P4GT builds only.
	    #
	    switch $(LANG)
	    {
		case ja : C++FLAGS += /DLANG_ja ;
	    }
	}

	rule P4EXPDefines
	{
		local u = ;

  		if $(OSVER) != 98 && ! $(NOUNICODE)
		{
   			u += [ FDefines UNICODE _UNICODE ] ;
  		}

		WinDefines /Ob1 /EHa $(u) : _UNICODE _ATL_STATIC_REGISTRY _USRDLL _WINDLL ;
	}

	rule P4EXPDOTH
	{
		DEPENDS $(<) : $(>) ;
		Clean clean : $(<) ;
	}

	rule P4EXPDOTHDEPENDS
	{
		DEPENDS $(<) : $(>) ;
	}

	rule P4EXPMIDL
	{
		DEPENDS $(<) : $(>) ;

		switch $(OSPLAT)
		{
		case X64 : EXP64MIDL $(<) : $(>) ;
		case *   : EXPMIDL $(<) : $(>) ;
		}

		Clean clean : $(<) p4exp.tlb dlldata.c p4exp_p.c ;
	}

	actions EXPMIDL
	{
		midl /env win32 /Oicf /tlb ".\p4exp.tlb" /h "p4exp.h" /iid $(<) $(>)
	}

	actions EXP64MIDL
	{
		midl /env x64   /Oicf /tlb ".\p4exp.tlb" /h "p4exp.h" /iid $(<) $(>)
	}

	rule P4EXPLinkage
	{
		# P4EXPLinkage exe : libs ; - set up link flags windows exe

		local _lf = /subsystem:windows ;

		switch $(TYPE_DEBUG)
		{
		case true : _lf += /DEBUG ;
		case *    : _lf += /MAP ;
		}

		_lf += /DLL ;
		_lf += /def:p4exp.def ;

		switch $(OSPLAT)
		{
		case X86 : _lf += /MACHINE:X86 ;
		case X64 : _lf += /MACHINE:X64 ;
		}

		LINKFLAGS on $(<) = $(LINKFLAGS) $(_lf) ;

		LINKLIBS on $(<) =
			gdi32.lib comctl32.lib shlwapi.lib
			user32.lib version.lib shell32.lib
			advapi32.lib oldnames.lib kernel32.lib ws2_32.lib
			winmm.lib $(2) ;

	}

	rule P4SccDefines
	{
		WinDefines /GX : _USRDLL _WINDLL ;
	}

	rule P4WinDefines
	{
		local u = ;

		# Unicode builds except on Win98.

		if $(OSVER) != 98 && ! $(NOUNICODE)
		{
			u += [ FDefines UNICODE _UNICODE ] ;
		}
		else
		{
			u += [ FDefines _MBCS ] ;
		}

		u += /GR /EHsc /GS ;
		if $(TYPE_DEBUG) = true { u += /Zi ; }

		WinDefines $(u) : STRICT ;
	}

	rule P4WinDiffDefines
	{
		WinDefines /GR /GX : P4DIFF ;
	}

	rule WinDefines
	{
		SubDirC++Flags
		    /W3 $(1)
		    [ FDefines NDEBUG _WINDOWS $(2) ] ;

		switch $(OSPLAT)
		{
		case X64 : SubDirC++Flags [ FDefines WIN64 ] ;
		case *   : SubDirC++Flags [ FDefines WIN32 ] ;
		}

		if $(TYPE_DYNAMIC)
		{
		    SubDirC++Flags [ FDefines _AFXDLL ] ;
		}
	}

	rule WinDllDeffile
	{
		# WinDllDeffile exe : file ; - set /def: file for link

		SEARCH on $(>) = $(SEARCH_SOURCE) ;
		DEFFILE on $(<) = $(>) ;
		DEPENDS $(<) : $(>) ;
	}

	rule WinDllLinkage
	{
		# WinDllLinkage exe : libs ; - set up link flags windows DLL

		WinLinkage $(<) : $(>) ;

		LINKFLAGS on $(<) += /dll ;
	}

	rule WinDllNoMainLinkage
	{
		# WinDllNoMain exe ;

		LINKFLAGS on $(<) += /NOENTRY /SUBSYSTEM:WINDOWS /DLL ;

		switch $(OSPLAT)
		{
		case X64 : LINKFLAGS on $(<) += /MACHINE:X64 ;
		case *   : LINKFLAGS on $(<) += /MACHINE:I386 ;
		}

		LINKLIBS on $(<) = $(2) ;
	}

	rule WinLinkage
	{
		# WinLinkage exe : libs ; - set up link flags windows exe

		local _lf = /subsystem:windows ;

		switch $(TYPE_DEBUG)
		{
		case true : _lf += /DEBUG ;
		case *    : _lf += /MAP /DEBUG ;
		}

		if $(OSVER) != 98 && ! $(NOUNICODE)
		{
			_lf += /ENTRY:"wWinMainCRTStartup" ;
		}

		switch $(OSPLAT)
		{
		case X86 : _lf += /MACHINE:X86 ;
		}

		LINKFLAGS on $(<) = $(LINKFLAGS) $(_lf) ;

		LINKLIBS on $(<) =
		    $(2) ;
	}

	rule WinRes
	{
		# WinRes exe : *.rc : flags ; - compile .rc->.res, link

		# Compile .rc into .res for linking into executable.
		# (Strictly MSVCNT, I presume.)

		local s r e ;

		e = [ FAppendSuffix $(<) : $(SUFEXE) ] ;
		s = [ FGristSourceFiles $(>) ] ;
		r = $(s:S=.res:G=) ;

		DEPENDS $(e) : $(r) ;
		DEPENDS $(r) : $(s) ;

		LinkLibraries $(e) : $(r) ;

		LOCATE on $(r) = $(LOCATE_TARGET) ;
		SEARCH on $(s) = $(SEARCH_SOURCE) ;

		# .rc files have #includes, but we're pretty sure
		# they include only files local to the .rc's directory

		HDRRULE on $(>) = HdrRule ;
		HDRSCAN on $(>) = $(HDRPATTERN) ;
		HRDSEARCH on $(>) = $(SEARCH_SOURCE) ;
		HDRGRIST on $(>) = $(HDRGRIST) ;

		# Bind headers

		RCFLAGS on $(r) = $(RCFLAGS) $(3) ;
		RCHDRS on $(r) = [ on $(r) FIncludes
			$(SUBDIRHDRS) $(HDRS) $(RCSTDHDRS) ] ;

		switch $(OSPLAT)
		{
		case X86 : RCFLAGS on $(r) += /d _WIN32 ;
		case X64 : RCFLAGS on $(r) += /d _WIN64 ;
		}

		WinRc $(r) : $(s) ;

		Clean clean : $(r) ;
	}

	rule WinResIdent
	{
		# WinResIdent *.rc ;

		local s r p v ;

		s = [ FGristSourceFiles $(<) ] ;
		r = $(s:S=.res:G=) ;

		# If RELEASE=2005.1 and PATCHLEVEL=69929 then
		#	P4_FILE_VERSION = 2005.1.6.9929
		#	P4_PRODUCT_VERSION = 2005.1

		p = [ Match (.*)(....) : $(PATCHLEVEL) ] ;
		v = $(RELEASE[1]).$(RELEASE[2]).$(p:J=.) $(RELEASE[3]) ;

		rule Fconcat { return $(<:J) ; }

		RCFLAGS on $(r) += [ FDefines
		    [ Fconcat P4_INT_MAJOR= $(RELEASE[1]) ]
		    [ Fconcat P4_INT_MINOR= $(RELEASE[2]) ]
		    [ Fconcat P4_INT_HBUILD= $(p[1]) ]
		    [ Fconcat P4_INT_LBUILD= $(p[2]) ]
		    [ Fconcat P4_FILE_VERSION= [ FQuote $(v[1]) ] ]
		    [ Fconcat P4_PRODUCT_VERSION= [ FQuote $(v:J=.) ] ]
		    [ Fconcat P4_COPYRIGHT= [ FQuote $(RELEASE[1]) ] ]
		    ] ;

		# Source file includes Version

		Includes $(s) : Version ;
	}

	actions WinRc {
		rc /fo $(<) $(RCFLAGS) "$(RCHDRS)" $(>)
	}


#################################################
#
# Section 7.  QT build rules and actions.
#
#################################################

	#
	# QtDefines ; - Add defines/headers for building with QT
	# QtFormLibrary lib : *.ui ; make .h's and archive .obj's
	# QtHeaders ts : headers ; - list headers for i18n xlation
	# QtLibrary lib : ts : files ; - Library call with lupdate
	# QtLinkage exe : opt ; - linkflags/libs for building with QT
	# QtConsoleLinkage exe ; - QtLinkage for a console app on NT
	# QtLrelease qm : ts ; - build qm from ts files with lrelease
	# QtMoc x.cpp : x.h ; - preprocess with moc
	# QtMocLibrary lib : *.h ; - moc, compile, & archive
	# QtResource qrc : mod : pngs ; - name pngs to make resource
	# QtResourceCpp cpp : qrc ; - build .cpp from resource file
	# QtUicCpp x.cpp : x.ui x.h ; - preprocess with uic to make .cpp
	# QtUicHdr x.h : x.ui ; - preprocess with uic to make .h
	#

	QtLanguages = ja en ;

	rule QtHeaders
	{
		# QtHeaders ts : headers ; - list headers for lupdate

		# This just stashes the named headers in the QTLUPHDRS
		# variable, used by QtLupdate1 to generate the translation
		# files.

		# We give the headers a separate grist, so that we don't
		# confuse their other uses (just in case we mess up here).

		QtLupdate $(<) : h : $(>:G=QTLHDR) ;
	}

	rule QtLibrary
	{
		# QtLibrary lib : ts : files ; - Library call with lupdate

		Library $(1) : $(3) ;
		QtLupdate $(2) : s : [ FGristSourceFiles $(3) ] ;
	}

	rule QtLrelease
	{
		# QtLrelease qm : ts ;
		for _i in $(QtLanguages)
		{
		    QtLreleaseRun $(1)_$(_i).qm : $(2)_$(_i).ts ;
		}

		LOCATE on $(_qm) = $(LOCATE_TARGET) ;

	}

	rule QtLreleaseRun
	{
		# QtLreleaseRun qm : ts ;

		NotFile lrelease ;
		Depends lrelease : $(1) ;
		Depends $(1) : $(2) ;
		Clean clean : $(1) ;

		LOCATE on $(1) = $(LOCATE_TARGET) ;
	}

	actions QtLreleaseRun
	{

		$(QTLREL) $(>) -qm $(<)
	}

	rule QtLupdate
	{
		# QtLupdate ts : h/s : files ; - Add sources/hdrs to lupdate

		# This rule is deeply complicated, and here's why.
		#
		# TrollTech's lupdate command uses a .pro file to declare the name
		# and location of the .ts, source, and header files to be
		# processed.  Unfortunately, rather than computing the location of
		# these files relative to the current working directory, they are
		# determined relative to the location of the .pro file!
		#
		# The naive solution would be to write the .pro files out to the
		# current working directory, but that means parallel builds on
		# different platforms using a shared workspace can clobber each other.
		#
		# Writing the .pro files out to the build output directory is
		# pretty much impossible to do right, because Jam offers no way to
		# compute the relative path to a source file from any other
		# arbitrary location; you can only compute it from the current
		# working directory.  Thus, you might be able to finagle "jam
		# lupdate" to work from p4-bin, but then it would blow up if you
		# tried to run it from p4-qt.
		#
		# To avoid the platform-clobbering race, we create a temporary
		# directory in the current working directory, wherever that is,
		# write the .pro files there, and fix up the file paths using a
		# now-known relative prefix ("..") from cwd.  The .pro files are
		# then deleted and you wind up with an empty temporary directory.
		# There might be some clever way to remove that that I don't know
		# about, but it's a harmless artifact.
		#
		# If LUPDATE_MERGE is set, the .ts files are written to the
		# directory "lupdate.merged_ts" instead of the bin.<platform>
		# directory, and obsolete entries are retained.  These are the
		# versions of the files that should be checked back into
		# p4-qt/translations when they are to be permanently updated.

		local tmpdir = tmp_lupdate.$(OS:L)$(OSVER:EL)$(OSPLAT:EL) ;
		if $(LUPDATE_MERGE) { tmpdir = lupdate.merged_ts ; }

		local cwdrel = ..$(SLASH) ;
		NotFile $(cwdrel) ;

		for lang in $(QtLanguages)
		{
			# add grist to distinguish source .ts file from the copy of it
			# in target dir
			local _ts  = $(1)_$(lang).ts ;
			local _tss = $(_ts:G=SRC) ;
			SEARCH on $(_tss) = [ FSubDirPath P4QT translations ] ;

			local _pro  = $(1)_$(lang).pro ;
			local _proh = $(1)_h_$(lang).pro ;
			local _pros = $(1)_s_$(lang).pro ;
			local _prox = $(1)_$(2)_$(lang).pro ;

			on $(_ts) if ! $(Done)
			{
				Done on $(_ts) = true ;

				# .ts -> .pro -> s.pro (QtLupTmp)-> sources
				#             -> h.pro (QtLupTmp)-> headers
				#     -> .ts from source tree, aka _tss

				NotFile lupdate ;
				Depends lupdate           : $(_ts) ;
				Depends $(_ts)            : $(_pro) ;
				Depends $(_pro)           : $(_proh) $(_pros) ;
				Depends $(_proh) $(_pros) : $(_tss) ;
				Clean clean : $(_ts) ;

				if $(LUPDATE_MERGE)
				{
					LOCATE on $(_ts) = $(tmpdir) ;
				}
				else
				{
					LOCATE on $(_ts) = $(LOCATE_TARGET) ;
				}
				MakeLocate $(_proh) $(_pros) $(_pro) : $(tmpdir) ;
				QTLTRANS on $(_pro) = $(_ts) ;

				# Copy translated ts files from source tree
				# Update ts files using pro file, headers/sources
				# Build pro file from list of headers/sources

				# lupdate reads and writes the same .ts file
				# we keep any translations in .ts files in the source tree
				# but need to copy them into the target dir for lupdate to
				# be able to update them

				# it is a manual step not involving jam to copy them back
				# to the source tree

				# source .ts file may not be present; that's ok because
				# lupdate will create one
				NOCARE $(_tss) ;

				# Zero h.pro/s.pro files to begin with
				QtLupTmp0 $(_proh) ;
				QtLupTmp0 $(_pros) ;

				QtLupdatePro $(_pro) $(cwdrel) : $(_proh) $(_pros) ;
				QtLupdateRun $(_ts)            : $(_tss) $(_pro) ;

				# Zonk pro files when done
				RmTemps $(_ts)  : $(_pro) ;
				RmTemps $(_pro) : $(_proh) $(_pros) ;
			}

			SEARCH on $(3) = $(SEARCH_SOURCE) ;
			Depends $(_prox) : $(3) ;
			QtLupTmp1 $(_prox) $(cwdrel) : $(3) ;
		}
	}

	# QtLupdatePro pro cwdrel : hpro spro ;
	# If set, cwdrel is extra path from cwd needed to instruct lupdate
	# where the sources really are relative to the pro file, because
	# lupdate searches for files relative to the location of the pro file,
	# not cwd.

	if $(NT)
	{
	    actions quietly together piecemeal QtLupTmp1
	    {
		    echo $(<[2]:E)$(>) \ >> $(<[1])
	    }

	    actions quietly QtLupTmp0
	    {
		    copy nul: $(<)
	    }

	    actions quietly QtLupdatePro bind QTLTRANS
	    {
		    echo TRANSLATIONS = $(<[2]:E)$(QTLTRANS) > $(<[1])
		    echo HEADERS = \ >> $(<[1])
		    type $(>[1]) >> $(<[1])
		    echo. >> $(<[1])
		    echo SOURCES = \ >> $(<[1])
		    type $(>[2]) >> $(<[1])
		    echo. >> $(<[1])
	    }
	}
	else
	{
	    actions quietly together piecemeal QtLupTmp1
	    {
			echo $(<[2]:E)$(>) \\ >> $(<[1])
	    }

		# Zero out the file if it already exists, or create it.  This way
		# the commands in QtLupdatePro will not print errors for files that
		# don't exist because there are e.g. no h files to write to it.
	    actions quietly QtLupTmp0
	    {
			: > $(<)
	    }

	    actions quietly QtLupdatePro bind QTLTRANS
	    {
			echo TRANSLATIONS = $(<[2]:E)$(QTLTRANS) > $(<[1])
			echo HEADERS = \\ >> $(<[1])
			cat $(>[1]) >> $(<[1])
			echo "" >> $(<[1])
			echo SOURCES = \\ >> $(<[1])
			cat $(>[2]) >> $(<[1])
			echo "" >> $(<[1])
	    }
	}

	# QtLupdateRun ts : tss pro ;
	#	copy the source .ts file (tss) into the output directory (ts)
	#	and make sure it's writable, then run lupdate on the pro file (pro)
	#	to extracted strings from the .cpp/.h files and update the ts
	#	file (ts) with newly found strings

	if $(CHMOD)
	{
		actions QtLupdateRun
		{
			$(CP) $(>[1]) $(<[1])
			$(CHMOD) +w $(<[1])
			$(QTLUP) $(>[2])
		}
	}
	else
	{
		actions QtLupdateRun
		{
			$(CP) $(>[1]) $(<[1])
			$(QTLUP) $(>[2])
		}
	}

	rule QtBaseDefines
	{
		# QtDefines ; - Add defines/headers for building with QT
		BoostHdrs ;

		if ! $(QTDIR)
		{
		    Exit Can't build in QT directories without QTDIR set. ;
		}

		if $(JAMVERSION) < 2.4.1 {
		    Exit QT builds require 2.4.1 ;
		}

		if $(JAMBASEDATE) < 2005.05.05 && ! $(QT25WARN) {
		    Echo QT builds work poorly without Jambase 2005.05.05 ;
		    QT25WARN = true ;
		}

		QTLUP    = [ FDirName $(QTDIR) bin lupdate ] ;
		QTLREL   = [ FDirName $(QTDIR) bin lrelease ] ;
		QTMOC    = [ FDirName $(QTDIR) bin moc ] ;
		QTUIC    = [ FDirName $(QTDIR) bin uic ] ;
		QEMBED   = [ FDirName $(QTDIR) bin qembed ] ;

		if ! $(LUPDATE_MERGE) && ( $(LUPDATE_NO_OBSOLETE) || $(PRODUCTION) )
		{
			# lrelease has a "bug" whereby if entries in one ts file are
			# marked obsolete but are active in another ts file (because
			# keys were moved, say) then lrelease may drop duplicates
			# *favoring the obsolete entries*, which it then doesn't
			# include in the .qm file.  (The order of preference depends on
			# the order of files on the command line.)  So for production
			# builds, we strip the obsolete entries for the tmp ts files.
			#
			# The default is to keep the obsolete entries because we don't
			# always want to throw them away; they are useful for the
			# linquist tool and when we check in merged ts files we should
			# usually save them.

			QTLUP += -no-obsolete ;
		}

		local _d _f ;

		_d += QT_NO_STL ;
		_d += QT_THREAD_SUPPORT ;
		_d += QT_NO_CAST_TO_ASCII ;
		_d += QT_NO_CAST_FROM_ASCII ;
		_d += QT_STATICPLUGIN ;

		if $(QTOPENGL) = no
		{
			_d += NO_OPENGL ;
		}

		if $(TEST) { _d += TEST ; }

		# Source code debugging
		# DEBUG is in our code -- conditional compilations
		# QT_NO_* is in QT code

		switch $(TYPE_DEBUG)
		{
		case true : _d += DEBUG ;
		case *    : _d += QT_NO_DEBUG QT_NO_CHECK ;
		}

		switch $(OS)
		{
		case NT :
			_f += /EHsc /GR /W4 ;
			_f += /wd4127 ; # conditional expression is constant
			_f += /wd4512 ; # assignment operator could not be generated

			# from Qt's Makefile
			# but we want stricter warnings and don't use precompiled headers
			# _f += /Zm200 /W3 ;

			if $(MSVSVER) >= 8
			{
				# VS8 treats wchar_t as a builtin type by default
				# while prior version use a typedef
				_f += /Zc:wchar_t- ;
			}
			if $(TYPE_DEBUG)
			{
				# enable runtime checks for debug builds only
				# this isn't compatible with optimizations
				_f += /RTCcsu ;

				if $(VLD)
				{
					_d += VLD ;
				}
			}
		}

		SubDirC++Flags [ FDefines $(_d) ] $(_f) ;
	}

	rule QtCoreHeaders
	{
		QtAllHeaders : Qt QtCore ;
	}

	# If a list of ": modules ..." is specified, just add those directories
	# into the search list.  Otherwise, a default list is generated.
	rule QtAllHeaders
	{
		local QtModules = $(2) ;
 		if ! $(QtModules)
		{
			QtModules =
				Qt
				QtCore
				QtGui
				QtAssistant
				QtNetwork
				QtWebKit
				QtXml
				QtXmlPatterns ;
		}

		if $(OS) = NT || $(OS) = MACOSX
		{
			QtModules += phonon ;
		}

		if $(QTOPENGL) != no
		{
			QtModules += QtOpenGL ;
		}

		for module in $(QtModules)
		{
			SubDirHdrs [ FDirName $(QTDIR) include $(module) ] ;

			# Also search the framework directories so that
			# non-module-qualified #include <QFoo> directives
			# work even when headers are not installed in
			# QTDIR/include/qtmodule.
			if $(OS) = MACOSX && ! $(QT_NO_FRAMEWORK_INCLUDES)
			{
				SubDirHdrs [ FDirName $(QTDIR) lib $(module).framework Headers ] ;
			}

		}
		SubDirHdrs [ FDirName $(QTDIR) include ] ;
		SubDirHdrs $(LOCATE_SOURCE[1]) ;

		if $(OS) = FREEBSD
		{
			SubDirHdrs /usr/X11R6/include ;
		}
		if $(OS) = NT && $(TYPE_DEBUG) && $(VLD)
		{
			SubDirHdrs $(VLD)/include ;
		}
	}

	rule QtDefines
	{
		# QtDefines ; - Add defines/headers for building with QT
		# Adds headers for all Qt modules

		if $(MSVSVER) = 8 && $(WindowsSdkDir)
		{
			# Include vista SDK directory for vs2005
			# This should only be done for Qt products.
			# Prior to adding the SDK dir, make sure the API
			# includes defined at the top of this Jamrules are
			# inserted.  Otherwise we may pick up the wrong
			# error.h.
			local _h ; for _h in $(HDRS) { SubDirHdrs $(_h) ; }
			SubDirHdrs $(WindowsSdkDir:J=" ")/include ;
		}

		QtBaseDefines $(1) ;
		QtAllHeaders $(1) ;
	}

	rule QtCoreDefines
	{
		# QtCoreDefines ; - Add defines/headers for building with QT
		# Adds headers for QtCore only; no QtGui or other rot

		if $(MSVSVER) = 8 && $(WindowsSdkDir)
		{
			# Include vista SDK directory for vs2005
			# This should only be done for Qt products.

			# Prior to adding the SDK dir, make sure the API
			# includes defined at the top of this Jamrules are
			# inserted.  Otherwise we may pick up the wrong
			# error.h.
			local _h ; for _h in $(HDRS) { SubDirHdrs $(_h) ; }
			SubDirHdrs $(WindowsSdkDir:J=" ")/include ;
		}

		QtBaseDefines ;
		QtCoreHeaders ;
	}

	rule QtLinkage
	{
		# QtLinkage exe : opt : qtlibs : rpath ; - linkflags/libs for building with QT

		local _t = [ FAppendSuffix $(<) : $(SUFEXE) ] ;
		local _opt = $(2) ;

		# Executable-local rpaths are only supported by the dynamic
		# linker/loader on solaris and linux so far.  MacOSX also supports
		# them but the syntax and mechanism is different; see MacP4VdyldFixup.
		#
		# Please don't use this parameter for absolute paths; it should be
		# for paths relative to the executable, wherever it is run, a la
		# the linux/solaris $ORIGIN token.
		#
		# Use the literal token "NULL" for rpath arg if you want to supress
		# any dynamic rpath.
		local _rpath = $(4) ;
		if $(_rpath) = "" { _rpath = $ORIGIN/../lib/p4v/qt4/lib ; }

		# The order here is significant when linking statically.
		#
		# The STATIC variable is a list of additional library dependencies
		# which the static Qt libraries have.  They don't need to be
		# enumerated when doing shared builds because the shared libraries
		# already have their library dependencies enumerated in the shared
		# object files and the linker picks these up automatically.  For
		# static libraries there is no such facility.
		local QT4LIBLIST ;
		local QT4LIBLIST_STATIC ;

		if $(3)
		{
			# If a Qt library list is specified in the 3rd
			# parameter to this rule, we use those and only
			# those libraries.
			QT4LIBLIST = $(3) ;
		}
		else
		{
			# otherwise, we use a library list customized for p4v.

			if $(TESTS) # unit testing
			{
				QT4LIBLIST += QtTest ;
			}

			if $(QTOPENGL) != no
			{
				QT4LIBLIST += QtOpenGL ;
				# $(UNIX) is set even for osx, but we must exclude macs here.
				if $(UNIX) && $(OS) != MACOSX && ! $(TYPE_DYNAMIC)
				{
					QT4LIBLIST_STATIC += GL ;
				}
			}

			QT4LIBLIST +=
				QtXml
				QtXmlPatterns
				QtNetwork
				QtGui
				QtWebKit
				QtCore ;
		}

		switch $(OS)
		{
			# We don't want to embed rpath entries for QTDIR/lib in
			# production builds because they are not located in a
			# standard system directory (unlike e.g. /usr/X11R6/lib).
			# Doing so results in unnecessary stat calls on customer
			# filesystems that may even cause network timeouts.  We
			# link Qt statically in unix production builds.
			#
			# Please don't add X libraries here in order to satisfy
			# dependencies in development builds of Qt.  The libraries
			# listed here are the dependencies required for production
			# builds; adding more dynamic linker dependencies
			# decreases portability.
			#
			# If you are working with QT shared libraries in a
			# development environment, there are 3 alternatives:
			#   1. set LD_LIBRARY_PATH
			#   2. edit your system ld.so.conf
			#   3. use the dev_LINKFLAGS and dev_LINKLIBS hooks:
			#         jam -sdev_LINKFLAGS="..." -sdev_LINKLIBS="..."

		case FREEBSD :
			LINKFLAGS on $(_t) +=
				# -Wl,-rpath,$(QTDIR)/lib
				-L$(QTDIR)/lib
				-L/usr/X11R6/lib
				$(LINKFLAGS) $(dev_LINKFLAGS) ;

			if ! $(TYPE_DYNAMIC)
			{
				QT4LIBLIST_STATIC +=
					Xrender
					Xrandr
					Xcursor
					fontconfig
					SM
					Xfixes
					X11
					m ;
			}

			LINKLIBS on $(_t) +=
				-l$(QT4LIBLIST)$(QT_LIBINFIX:E)
				-l$(QT4LIBLIST_STATIC)
				-pthread
				/usr/local/lib/libiconv.a
				$(LINKLIBS) $(dev_LINKLIBS) ;

		case SOLARIS :
			LINKFLAGS on $(_t) +=
				-L$(QTDIR)/lib
				-L/usr/X11R6/lib
				-L/usr/openwin/lib
				-L/usr/sfw/lib
				-L/opt/lude/lib
				$(LINKFLAGS) $(dev_LINKFLAGS) ;

			if $(TYPE_DYNAMIC)
			{
				if $(_rpath) != "NULL"
				{
					LINKFLAGS on $(_t) += -Wl,-R,'$(_rpath)' ;
				}
				LINKFLAGS on $(_t) += -Wl,-R,/usr/sfw/lib ;
			}
			else # ! $(TYPE_DYNAMIC)
			{
				# These libraries must be enumerated explicitly because our
				# static production Qt libs depend on them.
				QT4LIBLIST_STATIC +=
					ICE
					SM
					Xrender
					Xfixes
					Xext
					fontconfig
					freetype
					X11
					rt	;
			}

			LINKLIBS on $(_t) +=
				-l$(QT4LIBLIST)$(QT_LIBINFIX:E)
				-l$(QT4LIBLIST_STATIC)
				-lm -lpthread -lrt
				$(LINKLIBS) $(dev_LINKLIBS) ;

		case LINUX :
			if $(TYPE_DYNAMIC) && $(_rpath) != "NULL"
			{
				LINKFLAGS on $(_t) += -Wl,-rpath,'$(_rpath)' ;
			}

			switch $(OSPLAT)
			{
			case X86 :
				LINKFLAGS on $(_t) +=
					-L$(QTDIR)/lib
					-L/usr/X11R6/lib
					$(LINKFLAGS) $(dev_LINKFLAGS) ;

			case X86_64 :
				LINKFLAGS on $(_t) +=
				-L$(QTDIR)/lib
				-L/usr/X11R6/lib64
				$(LINKFLAGS) $(dev_LINKFLAGS) ;
			}

			if ! $(TYPE_DYNAMIC)
			{
				# These libraries must be enumerated explicitly because our
				# static production Qt libs depend on them.
				QT4LIBLIST_STATIC +=
					Xrender
					Xrandr
					Xcursor
					fontconfig
					ICE
					SM
					X11
					Xext
					m
					rt
					dl ;
			}

			LINKLIBS on $(_t) +=
				-l$(QT4LIBLIST)$(QT_LIBINFIX:E)
				-l$(QT4LIBLIST_STATIC)
				-pthread
				$(LINKLIBS) $(dev_LINKLIBS) ;

		case MACOSX :
			# QtWebKit 4.5.0 and later depend on this framework.
			QT4LIBLIST += phonon ;

			LINKFLAGS on $(_t) += $(LINKFLAGS)
				# comment out -prebind flag, because Qt is
				# not built prebound
				#-prebind
				-L$(QTDIR)/lib   # look here for normal libs
				-F$(QTDIR)/lib   # ...for structured frameworks too
				# This (dynamic) library is listed here so that it appears
				# before any other objects and specifically before
				# libsupp.a, to avoid symbol name collisions.  libz is
				# needed for the QuickTime framework.
				-lz
				$(dev_LINKFLAGS) ;

			LINKLIBS on $(_t) += $(LINKLIBS)
				# This is already on the global LINKLIBS
				#-framework ApplicationServices ;
				#-framework Foundation ;
				-framework QuickTime
				-framework OpenGL
				-framework AGL
				-framework AppKit ;

			# If you want to link with Qt4 as frameworks on mac,
			# use -sTYPE=dyn or dyng.  Otherwise you get a static
			# (or unix-style dynamic but non-frameworks) link.
			if $(TYPE_DYNAMIC)
			{
				# This pads the executable header so that
				# we can later change dynamic shared
				# library paths recorded in the output file.
				# (See MacP4VdyldFixup action.)
				LINKFLAGS on $(_t) += -Wl,-headerpad_max_install_names ;

				for _frmwk in $(QT4LIBLIST)$(QT_LIBINFIX:E)
				{
					LINKLIBS on $(_t) += -framework $(_frmwk) ;
				}
			}
			else
			{
				# These libraries must be enumerated explicitly because our
				# static production Qt libs depend on them.
				QT4LIBLIST_STATIC +=
					iconv
					ssl
					crypto ;

				LINKLIBS on $(_t) += -l$(QT4LIBLIST)$(QT_LIBINFIX:E)
				                     -l$(QT4LIBLIST_STATIC) ;
			}
			LINKLIBS on $(_t) += $(dev_LINKLIBS) ;

			if $(_opt) != "console"
			{
				QtMacPackage $(<) ;
			}

		case NT :

			QT4LIBLIST += phonon ;

			# warn about non-dynamic builds on NT
			if ! $(TYPE_DYNAMIC) && ! $(QTWARNED)
			{
				echo Warning: you really want jam -sTYPE=dyn for QT on NT. ;
				QTWARNED = 1 ;
			}

			# no dos box unless debug
			if $(_opt) = "console"
			{
				LINKFLAGS on $(_t) += $(LINKFLAGS) /subsystem:console ;
			}
			else if ! $(TYPE_DEBUG)
			{
				LINKFLAGS on $(_t) += $(LINKFLAGS) /subsystem:windows ;
			}

			local d = "" ;
			if $(TYPE_DEBUG) { d = d ; }

			# We use QT_LIBINFIX=P4 for our production builds, but in Qt
			# 4.5 and earlier, qtmain doesn't get the infix string.  In Qt
			# 4.6 and later, it does.  Since we don't want to have to
			# "know" this (or parse the value of QTDIR to figure it out),
			# we just check the filesystem to see which one is there.
			#
			# Currently (as of p10.1) we are building DTG with a 4.5.x
			# version of Qt and the P4V family with Qt 4.6.x, so this
			# infix variability comes into play.
			local qtmain = [ FDirEntries $(QTDIR) lib : qtmain$(QT_LIBINFIX:E)$(d).lib qtmain$(d).lib ] ;

			LINKLIBS on $(_t) = [ FDirName $(QTDIR) lib $(qtmain[1]) ] ;
			for _lib in $(QT4LIBLIST)$(QT_LIBINFIX:E)
			{
				LINKLIBS on $(_t) += [ FDirName $(QTDIR) lib $(_lib)$(d)4.lib ] ;
			}

			LINKLIBS on $(_t) +=
				advapi32.lib	# for qtree
				user32.lib
				gdi32.lib
				comdlg32.lib
				ole32.lib
				oleaut32.lib
				shell32.lib
				uuid.lib
				imm32.lib
				winmm.lib
				ws2_32.lib
				winspool.lib
				version.lib	;

			if $(TYPE_DEBUG) && $(VLD)
			{
				LINKLIBS on $(_t) += $(VLD)/lib/vld.lib ;
			}
		case * :
			Exit Don't know how to link QT executables on $(OS). ;
		}
	}

	rule QtConsoleLinkage
	{
		# QtConsoleLinkage exe ; - QtLinkage for a console app on NT

		QtLinkage $(<) : console ;
	}

	rule QtDllLinkage
	{
		# QtLinkage exe ; - linkflags/libs for building with QT

		local QT4LIBLIST ;
		QT4LIBLIST +=
			QtXml
			QtOpenGL
			QtNetwork
			QtGui
			QtCore
			phonon ;

		# WebKit not built for static DLL on Windows
		if $(TYPE_DYNAMIC) && $(OS) = NT
		{
			QT4LIBLIST +=
				QtWebKit ;
		}

		switch $(OS)
		{
		case NT :

			# warn about non-dynamic builds on NT
			if ! $(TYPE_DYNAMIC) && ! $(QTWARNED)
			{
				echo Warning: you really want jam -sTYPE=dyn for QT on NT. ;
				QTWARNED = 1 ;
			}

			LINKFLAGS on $(<) += $(LINKFLAGS) /DLL ;
			echo Warning: you are building a dll  $(LINKFLAGS) ;

			# no dos box unless debug
			if ! $(TYPE_DEBUG)
			{
				LINKFLAGS on $(<) += $(LINKFLAGS) /subsystem:windows ;
			}

			# advertise symbols available
			if $(TYPE_DEBUG) && $(MSVSVER) >= 9
			{
				LINKFLAGS on $(<) += /ASSEMBLYDEBUG ;
			}

			local d = "" ;
			if $(TYPE_DEBUG) { d = d ; }
			local n = "" ;
			if $(TYPE_DYNAMIC) { n = 4 ; }

			# We use QT_LIBINFIX=P4 for our production builds, but in Qt
			# 4.5 and earlier, qtmain doesn't get the infix string.  In Qt
			# 4.6 and later, it does.  Since we don't want to have to
			# "know" this (or parse the value of QTDIR to figure it out),
			# we just check the filesystem to see which one is there.
			#
			# Currently (as of p10.1) we are building SCC with a 4.5.x
			# version of Qt and the P4V family with Qt 4.6.x, so this
			# infix variability comes into play.
			local qtmain = [ FDirEntries $(QTDIR) lib : qtmain$(QT_LIBINFIX:E)$(d).lib qtmain$(d).lib ] ;
			LINKLIBS on $(<) = [ FDirName $(QTDIR) lib $(qtmain[1]) ] ;

			for _lib in $(QT4LIBLIST)$(QT_LIBINFIX:E)
			{
				LINKLIBS on $(<) += [ FDirName $(QTDIR) lib $(_lib)$(d)$(n).lib ] ;
			}

			LINKLIBS on $(<) +=
				advapi32.lib	# for qtree
				user32.lib
				gdi32.lib
				comdlg32.lib
				ole32.lib
				oleaut32.lib
				shell32.lib
				uuid.lib
				imm32.lib
				winmm.lib
				ws2_32.lib
				winspool.lib
				shlwapi.lib
				version.lib	;

			if ! $(TYPE_DYNAMIC)
			{
				LINKLIBS on $(<) += opengl32.lib ;	# for static QtOpenGL.lib
			}

			if $(TYPE_DEBUG) && $(VLD)
			{
				echo addding vld ;
				LINKLIBS on $(<) += $(VLD)/lib/vld.lib ;
			}

		case * :
			Exit Don't know how to link QT executables on $(OS). ;
		}
	}

	# Mac special package - make a raw executable into a .app folder
	# This does x things:

	# 1. locates the actual exe in exe.app/Contents/MacOS/exe
	# 2. Creates exe.app/Contents/PkgInfo
	# 3. Creates exe.app/Contents/Info.plist
	# 4. Creates exe.app/Contents/Resources/application.icns

	rule QtMacPackage
	{
		# QtMacPackage exe ;

		Depends $(<) : <$(<)>PkgInfo ;
		Depends $(<) : <$(<)>Info.plist ;
		Depends $(<) : <$(<)>application.icns ;

		MakeLocate  $(<)                  : [ FSubDirPath $(EXEC_TOKENS) $(<:S=.app) Contents MacOS ] ;
		MakeLocate <$(<)>PkgInfo          : [ FSubDirPath $(EXEC_TOKENS) $(<:S=.app) Contents ] ;
		MakeLocate <$(<)>Info.plist       : [ FSubDirPath $(EXEC_TOKENS) $(<:S=.app) Contents ] ;
		MakeLocate <$(<)>application.icns : [ FSubDirPath $(EXEC_TOKENS) $(<:S=.app) Contents Resources ] ;

		MacCreatorCode <$(<)>Info.plist : $(<) ;

		QtMacPackageInfo <$(<)>PkgInfo ;
		QMS on <$(<)>PkgInfo = [ MacCreatorCode $(<) ] ;

		QtMacPlist <$(<)>Info.plist : $(<) ;
	}

	actions QtMacPackageInfo
	{
	    echo "APPL$(QMS)" > $(<)
	}

	rule QtMacIcons
	{
	    File <$(<)>application.icns : $(>) ;
	}

	rule QtMacPlist
	{
	    local osid = $(OS)$(OSVER:E)$(OSPLAT:E) ;

	    Depends files : $(<) ;

	    # Add the standard items to the Info.plist file
	    #
	    QtMacAddPListItem $(>) : CFBundleExecutable         : $(>) ;
	    QtMacAddPListItem $(>) : CFBundlePackageType        : "APPL" ;
	    QtMacAddPListItem $(>) : CFBundleShortVersionString : $(RELEASE:J=.) ;
	    QtMacAddPListItem $(>) : CFBundleVersion            : $(RELEASE:J=.)/$(PATCHLEVEL)$(SPECIAL:E) ;
	    QtMacAddPListItem $(>) : CFBundleGetInfoString      : "$(RELEASE:J=.), Copyright $(SUPPDATE[1]) Perforce Software, Inc." ;
	    QtMacAddPListItem $(>) : CFBundleIconFile           : application.icns ;
	    QtMacAddPListItem $(>) : P4RevString                : "$(>:U)/$(osid[1]:U)/$(RELEASE:J=.)/$(PATCHLEVEL)$(SPECIAL:E) ($(SUPPDATE[1])/$(SUPPDATE[2])/$(SUPPDATE[3]))" ;

	    MODE on $(<) = $(FILEMODE) ;
	    Chmod $(<) ;

	    # This is just for the output hack in the action QtMacPList
	    JOINER_VARIABLE on $(<) = " >> " ;
	}

	# Adds a string item to Info.plist
	# concatenates the XML description to a string which contains the contents
	#
	rule QtMacAddPListItem
	{
	    MAC_PLIST_CONTENTS on <$(<)>Info.plist  += " \"    <key>$(2)</key>\"" ;
	    MAC_PLIST_CONTENTS on <$(<)>Info.plist  += " \"    <string>$(3)</string>\"" ;
	}

	# Writes out an XML file that conforms to the Info.pllist format
	#
	# look at the central line very carefully
	# the whole thing gets expanded into multiple lines because
	# there are no spaces in this line. They are made into multiple
	# permutations of every value in MAC_PLIST_CONTENTS.
	# each value begins with a space (so there is a space after "echo"
	# and each one uses the one value in JOINER_VARIABLE so it can
	# put spaces between current the MAC_PLIST_CONTENTS value, and
	# the value of the file which it will be appended to
	#
	actions QtMacPlist
	{
		echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" > $(<)
		echo "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"  >> $(<)
		echo "<plist version=\"1.0\">"  >> $(<)
		echo "<dict>"                   >> $(<)


		echo$(MAC_PLIST_CONTENTS)$(JOINER_VARIABLE)$(<);


		echo "</dict>"                  >> $(<)
		echo "</plist>"                 >> $(<)
	}

	# Library rules

	rule QtHdrRule
	{
		# Our own HdrRule that knows a .ui doesn't itself include
		# a .h, but instead causes the resulting .cpp to do so.
		# What .cpp?  TCPP is set on the .ui by QtFormLibrary,
		# and that's how we know it's this rigged dependency.

		HdrRule $(TCPP:E=$(<)) : $(>) ;
	}

	rule QtFormLibrary
	{
		# QtFormLibrary lib : *.ui ; make .h's and archive .obj's

		# For each x.ui file we generate _3_ files:
		#
		#	x.h (uic x.ui)
		#	tx.cpp (uic x.ui x.h) (temp)
		#	mx.cpp (moc x.h) (temp)
		#
		# The tx.cpp and mx.cpp get compiled into tx.o and mx.o
		# and archived into the library.

		Library $(<) : m$(>:S=.cpp) ;
		Library $(<) : t$(>:S=.cpp) ;

		local i ;

		for i in $(>)
		{
		    local h = $(i:S=.h) ;
		    local ui = [ FGristSourceFiles $(i) ] ;
		    local mcpp = [ FGristSourceFiles m$(i:S=.cpp) ] ;
		    local tcpp = [ FGristSourceFiles t$(i:S=.cpp) ] ;
		    local mobj = $(mcpp:S=$(SUFOBJ)) ;
		    local tobj = $(tcpp:S=$(SUFOBJ)) ;

		    # .ui's can include .h files, though what it actually
		    # means is that the generated tx.cpp includes the .h's,
		    # so we pass the tx.cpp name down to our own QtHdrRule.

		    TCPP on $(ui) = $(tcpp) ;
		    HDRRULE on $(ui) = QtHdrRule ;
		    HDRSCAN on $(ui) = "<include .*>(.*)</include>" ;
		    HDRSEARCH on $(ui) =
			$(SEARCH_SOURCE:E) $(SUBDIRHDRS) $(HDRS) $(STDHDRS) ;

		    QtUicHdr $(h) : $(ui) ;
		    QtUicCpp $(tcpp) : $(ui) $(h) ;
		    QtMoc $(mcpp) : $(h) ;

		    if ! $(TYPE_DEBUG) { RmTemps $(mobj) : $(mcpp) ; }
		    if ! $(TYPE_DEBUG) { RmTemps $(tobj) : $(tcpp) ; }

		    Includes $(mcpp) : $(h) ;
		    Includes $(tcpp) : $(h) ;
		}
	}

	rule QtForms
	{
		# QtForms *.ui ; make .h's

		# For each x.ui file we generate a single header file:
		#
		#	ui_x.h (uic x.ui)

		local i ;

		for i in $(>)
		{

		    local h = ui_$(i:S=.h) ;
		    local ui = [ FGristSourceFiles $(i) ] ;
		    Depends $(<) : $(h) ;

		    QtUicHdr $(h) : $(ui) ;

		}
	}

	rule QtMocLibrary
	{
		# QtMocLibrary lib : *.h ; - moc, compile, & archive

		# X.h -> temp mX.cpp -> temp mX.obj -> lib
		# Normal library rule on the generated m*.cpp files

		Library $(<) : m$(>:S=.cpp) ;

		# Make mX.cpp from X.h using moc
		# mX.cpp is a temp

		local h ;

		for h in $(>)
		{
		    local cpp = [ FGristSourceFiles m$(h:S=.cpp) ] ;
		    local obj = $(cpp:S=$(SUFOBJ)) ;
		    local gh = [ FGristFiles $(h) ] ;
		    QtMoc $(cpp) : $(gh) ;
		    if ! $(TYPE_DEBUG) { RmTemps $(obj) : $(cpp) ; }
		}
	}

	# Source file rules

	rule FSplit
	{
		# string : delim (default /)

		local s = $(>:E=/) ;
		local x = [ MATCH ([^$(s)]*)$(s)(.*) : $(<) ] ;
		if ! $(x) { return $(<) ; }
		return $(x[1]) [ FSplit $(x[2]) : $(>) ] ;
	}

	rule FLocalPath
	{
		# path1 path2 ... -- turns / into / or \ as needed

		local r ;
		for i in $(<) { r = $(r) [ FDirName [ FSplit $(i) ] ] ; }
		return $(r) ;
	}

	rule QrcHdrRule
	{
		# Echo $(<) is $(>) ;

		local t = [ FLocalPath $(>) ] ;

		Includes $(<) : $(t) ;
		SEARCH on $(t) = $(HDRSEARCH) ;
	}

	actions Qrc
	{
		$(QTRCC) -binary -o $(<) $(>)
	}

	rule Qrc
	{
		# Qrc file.rcc : file.qrc ;

		MakeLocate $(<) : $(EXEC) ;
		SEARCH on $(>) = $(SEARCH_SOURCE) ;
		QTRCC    = [ FDirName $(QTDIR) bin rcc ] ;
		HDRRULE on $(>) = QrcHdrRule ;
		HDRSCAN on $(>) = "<file.*>(.*)</file>" ;
		HDRSEARCH on $(>) = $(SEARCH_SOURCE:E) ;

		Depends all : $(<) ;
		Depends $(<) : $(>) ;
	}

	rule QtMoc
	{
		# QtMoc x.cpp : x.h ; - preprocess with moc

		# Derive a .cpp from .h using Qt's moc

		NotFile src ;
		Depends src : $(<) ;

		Depends all : $(<) ;
		Depends $(<) : $(>) ;
		Clean clean : $(<) ;

		SEARCH on $(>) = $(SEARCH_SOURCE) ;
		MakeLocate $(<) : $(LOCATE_SOURCE) ;
	}

	actions QtMoc
	{
		$(QTMOC) -DOS_$(OS) $(>) -o $(<)
	}

	rule QtHelpGenBuild
	{
		# QtHelpGenBuild target.qhc : source.qhp : command : default_target_suffix ;
		local dst            = $(1) ;
		local src            = [ FDirName $(2) ] ;
		local cmd            = $(3) ;
		local default_suffix = $(4) ;

		if ! $(dst)
		{
			dst = $(src:B) $(default_suffix) ;
			dst = $(dst:J=".") ;
		}

		MakeLocate $(dst) : $(ALL_LOCATE_TARGET) ;

		Depends all : $(dst) ;
		Depends $(dst) : $(src) ;
		Clean clean : $(dst) ;

		QTHELPBIN on $(dst) = [ FDirName $(QTDIR) bin $(cmd) ] ;
		QTHELPSRC on $(dst) = $(src) ;

		QtHelpGenRun $(dst) : $(src) ;
	}

	rule QtHelpGen
	{
		QtHelpGenBuild $(1) : $(2) : qhelpgenerator : qhc ;
	}

	rule QtHelpCollectionGen
	{
		QtHelpGenBuild $(1) : $(2) : qcollectiongenerator : qch ;
	}

	# LD_LIBRARY_PATH is for unix.
	# DYLD_LIBRARY_PATH and DYLD_FRAMEWORK_PATH are for OSX.
	# The trolltech build process does not hardcode these so they need
	# to go into the environment.
	#
	# These help generation programs, at least as of version 4.4.2,
	# also seem to have a bunch of problems on several platforms
	# writing over NFS whether or not locking is enabled.  So write to
	# /tmp and then copy back into place.
	actions QtHelpGenRun
	{
		LD_LIBRARY_PATH=$(QTDIR)/lib
		DYLD_LIBRARY_PATH=$(QTDIR)/lib
		DYLD_FRAMEWORK_PATH=$(QTDIR)/lib
		export LD_LIBRARY_PATH DYLD_LIBRARY_PATH DYLD_FRAMEWORK_PATH
		$(QTHELPBIN) -o ${TMPDIR-/tmp}/$(<:B)$$ $(QTHELPSRC) && $(CP) ${TMPDIR-/tmp}/$(<:B)$$ $(<)
	}

	rule QtUicCpp
	{
		# QtUicCpp x.cpp : x.ui x.h ; - preprocess with uic to make .cpp

		NotFile src ;
		Depends src : $(<) ;

		Depends all : $(<) ;
		Depends $(<) : $(>) ;
		Clean clean : $(<) ;

		SEARCH on $(>) = $(SEARCH_SOURCE) ;
		MakeLocate $(<) : $(LOCATE_SOURCE) ;
	}

	# don't include dir name in x.h

	actions QtUicCpp
	{
		$(QTUIC) $(>[1]) -i $(>[2]:D=) -o $(<)
	}

	rule QtUicHdr
	{
		# QtUicHdr x.h : x.ui ; - preprocess with uic to make .h

		NotFile src ;
		Depends src : $(<) ;

		Depends all : $(<) ;
		Depends $(<) : $(>) ;
		Clean clean : $(<) ;

		SEARCH on $(>) = $(SEARCH_SOURCE) ;
		MakeLocate $(<) : $(LOCATE_SOURCE) ;
	}

	actions QtUicHdr
	{
		$(QTUIC) $(>) -o $(<)
	}

	rule QtUnitTest
	{
		# $(1) = component to build unit test for
		#	the component is defined in $(1).h and $(1).cpp
		#   the unit test is defined in t_$(1).h and t_$(1).cpp
		# $(2) = list of other components this test depends on
		# $(3) = list of libraries this test depends on

		local lib = t_$(1) ;

		# Need to build component into differently named object file
		# because Library rule will delete normal object file.
		# Create unique names that don't conflict with the unit test
		# files by adding .ut suffix before extension.

		Object <$(SOURCE_GRIST)>$(1).ut$(SUFOBJ) : <$(SOURCE_GRIST)>$(1).cpp ;
		QtMoc <$(SOURCE_GRIST)>m$(1).ut.cpp : <$(SOURCE_GRIST)>$(1).h ;
		Object <$(SOURCE_GRIST)>m$(1).ut$(SUFOBJ) : <$(SOURCE_GRIST)>m$(1).ut.cpp ;
		LibraryFromObjects t_$(1) :
			<$(SOURCE_GRIST)>$(1).ut$(SUFOBJ)
			<$(SOURCE_GRIST)>m$(1).ut$(SUFOBJ) ;

		# Rebuild any dependencies for same reason.
		for dep in $(2)
		{
			Object <$(SOURCE_GRIST)>$(dep).$(1).ut$(SUFOBJ) :
				<$(SOURCE_GRIST)>$(dep).cpp ;
			QtMoc <$(SOURCE_GRIST)>m$(dep).$(1).ut.cpp : <$(SOURCE_GRIST)>$(dep).h ;
			Object <$(SOURCE_GRIST)>m$(dep).$(1).ut$(SUFOBJ) :
				<$(SOURCE_GRIST)>m$(dep).$(1).ut.cpp ;
			LibraryFromObjects t_$(1) :
				<$(SOURCE_GRIST)>$(dep).$(1).ut$(SUFOBJ)
				<$(SOURCE_GRIST)>m$(dep).$(1).ut$(SUFOBJ) ;
		}

		# Need to compile unit test too since we're forced to use MainFromObjects.
		# Moc'ed cpp files, and their obj files, end up with mt_ prefix.
		Object <$(SOURCE_GRIST)>t_$(1)$(SUFOBJ) : <$(SOURCE_GRIST)>t_$(1).cpp ;
		QtMoc <$(SOURCE_GRIST)>mt_$(1).cpp : <$(SOURCE_GRIST)>t_$(1).h ;
		Object <$(SOURCE_GRIST)>mt_$(1)$(SUFOBJ) : <$(SOURCE_GRIST)>mt_$(1).cpp ;

		MainFromObjects $(1) :
			<$(SOURCE_GRIST)>mt_$(1)$(SUFOBJ)
			<$(SOURCE_GRIST)>t_$(1)$(SUFOBJ) ;
		LinkLibraries $(1) : $(lib) $(3) ;
		QtConsoleLinkage $(1) ;
	}

	rule QtUnitTestSuite
	{
		for dep in $(2)
		{
			local exe = $(dep)$(SUFEXE) ;
			MakeLocate $(exe) : $(LOCATE_TARGET) ;
			Depends $(1) : $(exe) ;
			if $(RUNTESTS)
			{
				QtUnitTestCase $(1) : $(exe) ;
			}
		}
	}

	actions QtUnitTestCase
	{
		$(2)
	}

	rule P4QtCoreHdrs
	{
		SubDirHdrs $(P4QT) p4api include ;
		SubDirHdrs $(P4QT) core include ;
	}

#################################################
#
# Section 8.  Lua build rules and actions.
#
#################################################

	# Rule to deal with Lua generated files and tool dependencies for
	# P4-Report.  Note that there are cases where parallel builds will
	# fail.  For example, if you make a clean build, edit scripts/file.lua,
	# then re-build, you'll still have old p4-bin/file.lb results, so
	# bin2c and luac might finish after or during the C++ compile.
	#
	# This problem only applies to incremental builds.  If production
	# builds are from-scratch, then they should be safe.

	rule P4ReportDEPENDS
	{
		# Make sure we first build the Lua compiler and bin2c utility
		# before we try and make the header files.

		DEPENDS luacode.h    : luac$(SUFEXE) bin2c$(SUFEXE) ;
		DEPENDS luaclicode.h : luac$(SUFEXE) bin2c$(SUFEXE) ;

		# Make sure we create the header files before compiling p4sql
		# and p4odbc.dll.

		DEPENDS p4sql$(SUFEXE) : luacode.h luaclicode.h ;
		DEPENDS p4odbc.dll     : luacode.h luaclicode.h ;
	}

	rule Lua2c
	{
		local _t ;
		_t = [ FGristFiles $(>:S=.lb) ] ;

		LuaCompile $(>) ;
		LOCATE on $(<) = $(SEARCH_SOURCE) ;
		DEPENDS lib : $(<) ;
		DEPENDS $(<) : $(_t) ;
		LuaBin2c $(<) : $(_t) ;
		Clean clean : $(<) ;
		Clean clean : $(_t) ;
	}

	rule LuaCompile
	{
		local _t _i ;

		for _i in [ FGristFiles $(<:S=.lua) ]
		{
			_t = $(_i:S=.lb) ;
			SEARCH on $(_i) = $(SEARCH_SOURCE) ;
			LOCATE on $(_t) = $(LOCATE_TARGET) ;
			DEPENDS obj : $(_t) ;
			DEPENDS $(_t) : $(_i) ;
			Luac $(_t) : $(_i) ;
			Clean clean : $(_t) ;
		}
	}

	actions LuaBin2c {
		$(ALL_LOCATE_TARGET)$(SLASH)bin2c $(>) > $(<)
	}

	actions Luac {
		$(ALL_LOCATE_TARGET)$(SLASH)luac -s -o $(<) $(>)
	}

#################################################
#
# Section 9.  Per-platform actions.
#
#################################################

if $(OS) = IPHONE
{
	# The "security unlock-keychain" command here should have no effect
	# if the keychain is already unlocked, even if the supplied
	# password is incorrect.  But it will unlock keychains with blank
	# passwords, which should avoid some accidental production failures.
	actions P4Scout_xcodebuild
	{
		security unlock-keychain -p '' login.keychain

		pwd=`pwd`
		cd $(SCOUTSRCDIR) &&
		xcodebuild -configuration $(>) P4APIDIR=$pwd/$(P4APIDIR) &&
		cd build/$(>)-iphoneos &&
		zip -9 -r -y -q $(>)-$(<).zip $(<) &&
		zip -9 -r -y -q $(>)-$(<).dSYM.zip $(<).dSYM &&
		mv $(>)-$(<).zip $(>)-$(<).dSYM.zip $pwd/$(EXEC)
	}
}

if $(UNIX) || $(NT)
{
	# Provide proper quoting for file names with spaces in them.
	actions File
	{
		$(CP) "$(>)" "$(<)"
	}
}

if $(NT) && $(MSVCNT)
{
	actions updated together piecemeal Archive {
	    pushd $(<:D)
	    if exist $(<:BS) set _$(<:B)_=$(<:BS)
	    $(AR) /nologo /out:$(<:BS) %_$(<:B)_% $(>:BS)
	    popd
	}

	# When embedding a manifest, the resource id should be 1 for exe files,
	# 2 for dlls.  P4-GT plugins are sensitive to change here - see
	# job036615 and job040269.
	actions Link bind NEEDLIBS DEFFILE
	{
		$(LINK) $(LINKFLAGS) /out:$(<) /def:$(DEFFILE) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)
		set _target=$(<)
		set _file=%_target:$(ALL_LOCATE_TARGET)$(SLASH)=%
		set _rsrc=1
		if /i %_target:~-3,3% neq exe set _rsrc=2
		if exist $(<).manifest mt -manifest $(<).manifest -outputresource:$(<);%_rsrc%
	}
}

if $(NT)
{
	actions Cc
	{
		$(CC) /c /Fo$(<) /Fd$(PDBDIR)\ $(CCFLAGS) $(CCDEFS) "$(CCHDRS)" "/I$(STDHDRS)" $(>)
	}

	actions C++
	{
		$(C++) /c /Fo$(<) /Fd$(PDBDIR)\ $(C++FLAGS) $(CCDEFS) "$(CCHDRS)" "/I$(STDHDRS)" /Tp$(>)
	}

	actions MkTarArchive
	{
		tar cf $(<) -C $(>:P) $(>:BE)$(>:SE)
	}

	# If someone beat us to creating the directory, don't bomb.
	actions MkDir1
	{
		$(MKDIR) $(<)
		if exist $(<) set ERRORLEVEL=0
	}
}

if $(VMS)
{
	actions MkTarArchive
	{
		set default $(<:D)
		vmstar cvdzf $(<:B)$(<:S) [.$(>:B)...]
		set file/prot=(o:rwed) $(<:B)$(<:S)
	}

	actions MkZipArchive
	{
		set default $(<:D)
		zip "-9wrV" $(<:B)$(<:S) $(>:BS=.dir)
	}

	actions MkBckArchive
	{
		set default $(<:D)
		backup [.$(>:B)...] $(<:B)$(<:S)/save
		set file/prot=(o:rwed) $(<:B)$(<:S)
	}
}

#
# MakeQtConf
#
if $(OS) = MACOSX
{
	actions MakeQtConf1
	{
		echo "[paths]" > $(<)
		echo "plugins      = PlugIns" >> $(<)
		echo "translations = Resources/translations" >> $(<)
	}
}
else if $(UNIX)
{
	actions MakeQtConf1
	{
		echo "[paths]" > $(<)
		echo "plugins      = ../lib/p4v/qt4/plugins" >> $(<)
		echo "translations = ../lib/p4v/P4VResources/translations" >> $(<)
	}
}
else if $(NT)
{
	actions MakeQtConf1
	{
		echo "[paths]" > $(<)
		echo "plugins      = plugins" >> $(<)
		echo "translations = translations" >> $(<)
	}
}


#################################################
#
# Section 10.  Useful miscellanea
#
#################################################

	# Numerous client packages use this variable: p4-dtg, p4-convert,
	# the scripted APIs, etc.
	#  We can't set this in Section 1 because the rule isn't defined yet.
	if ! $(P4APIDIR)
	{
		local _apidir = [ P4APIDirName p4api ] ;
		P4APIDIR = [ FDirName $(EXEC) $(_apidir[1]) ] ;
	}

	# Tell the user where the top of the code tree is.
	#
	# For example if you were in say, some arbitrary working directory
	# deeply under p4-qt/..., how could you easily get back to the
	# p4-bin directory?
	#
	# 	$ alias topdir='jam locate-topdir 2>&1 | sed -ne "/^TOPDIR=/s///p"'
	# 	$ cd `topdir`/p4-bin
	#
	# This is probably more useful for scripts, however.

	rule LocateTopDir
	{
		local loc = [ FSubDirPath AllP4 ] ;
		NOTFILE $(loc:G=locate) ;
		EchoLocate $(<) : $(loc:G=locate) ;
	}

	actions EchoLocate
	{
		echo "TOPDIR=$(>:G=:E=.)" ;
	}

	LocateTopDir locate-topdir ;

# end of Jamrules