# BhbJambase
# Copyright (c) 2001 MBruce, all rights reserved
# $Id: $

# This is the basic Jambase for use in your projects.

################################################################################
# Note:  This is an architectural difference between "jam" from perforce and   #
# this highly modified version of "jam".  This version of "jam" will only      #
# know how to do very few things in it's Jambase.  Everything else in included #
# at runtime from this file.                                                   #
#                                                                              #
################################################################################


# -----------
# Local stuff.
# -----------

include $(TOP)$(SLASH)Jamvars ;

# ----------------
# Basic Common variables
# ----------------

# Customize for your project
BHBVERSION = "10" ;

# TOP refers to the top of the source tree - in our case this is the
# branch directory (e.g. ~/dev/bhb10).
HDRS = $(TOP)$(SLASH)inc ;  # Where our standard headers are.
LIBPATH = $(TOP)$(SLASH)lib ;  # Where our libraries go.
BINPATH = $(TOP)$(SLASH)bin ;   # Where our executables go.

# we keep 3rdparty libs elsewhere
CFLIBDIR = $(CF) ;
if $(CF) = rbug
{
  CFLIBDIR = release ;
}
3RDPARTYLIB = 
  $(TOP)$(SLASH)3rdparty$(SLASH)lib 
  $(TOP)$(SLASH)3rdparty$(SLASH)lib$(SLASH)$(CFLIBDIR) 
  ;

# Where the base of the java tree is, in grist and dirs:
JAVAGRIST = <java> ;
JAVAROOT = $(TOP:R=$(PWD))$(SLASH)java ;
JAVA3RDPARTYROOT = $(TOP:R=$(PWD))$(SLASH)3rdparty$(SLASH)java ;

# Java classpath
CLASSPATH = $(JAVA3RDPARTYROOT) ;

# Variable    Meaning
# --------    -------
# ARCH        Letters to append to lib/exe names to indicate configuration.
# ARCHDIR     Subdirectory where intermediate files go.
# DEBUGGING   Are we debugging at all?

ARCHDIR = $(CF) ;


# ------------------------------------------
# Environmental configuration settings
# These must come before the "if $(NT)" and "if $(UNIX)" sections.
# ------------------------------------------

if ! $(TOP)
{
  ECHO We depend on TOP being the name of the top directory ;
  EXIT As in SubDir TOP foo bar ";" ;
}

if ! $(CF) || ( $(CF) != debug && $(CF) != release && $(CF) != rbug )
{
  ECHO Please define a configuration (ie: if you are building debug or release) ;
  ECHO The possible configurations are debug and release. ;
  EXIT The configuration needs to be set in the environment variable 'CF'. ;
}

if ! $(TEMP)
{
  ECHO Please set the environment variable "TEMP" to somewhere safe. ;
  ECHO DO NOT set it to /tmp unless you are the only one who uses this machine. ;
  EXIT TYPE:     export TEMP=$(HOME)/tmp; mkdir $(HOME)/tmp ;
}

# uncomment this if you need object store persistable classes
# if ! $(OSJI_HOME)
# {
#   ECHO Please set OSJI_HOME to the root path of ObjectStore. ;
#   EXIT You can probably do this by running /opt/release/bhb/bin ;
# }

if $(FAST)
{
  ECHO Fast build specified; skipping header dependency analysis. ;
  ECHO C and C++ only ;
}

if $(PROFILE)
{
  LINKPROFILE = $(PROFILE) ;
}

if $(LINKPROFILE)
{
  ECHO Profiling is enabled. ;
  ECHO Windows NT only at the moment. ;
}

if $(CF) = rbug
{
  ECHO Generating debug info in release mode! ;
  # more crappy trunkated debug info in this mode...
  ALLOWWARN = true ;
  ECHO Windows NT only.  This stuff works on UNIX.  ;
}

if $(MAPFILE)
{
  ECHO Generating Mapfile. ;
  ECHO Windows NT only at the moment. ;
}

# Unit testing is enabled by default...
if $(NOUNITTEST)
{
  ECHO Unit testing disabled. ;
}

if $(VERBOSELINK)
{
  ECHO Verbose link. ;
}

if $(ALLOWWARN)
{
  ECHO Allowing warnings... beware ;
}

if $(UPDATEINSTALLEXE) && ! $(DEBUGGING)
{
  if $(INSTALL_DIR)
  {
    ECHO Updating the executables in the bhbInstall directory. ;
    DEPENDS all : install ;
  }
  else
  {
    ECHO Update your $(INSTALL_DIR) ;
  }
}

if $(NOLINK)
{
  ECHO Not linking... ;
}

if ! $(BHBJAM)
{
  EXIT This Bhbrules needs to be run with bhbjam ;
}

if $(BROWSE)
{
  ECHO Building file-by-file browse info. ;
  ECHO To build the .bsc file run \"jam browse\". ;
}


# ------------------------------------------
# Start decision making.
# ------------------------------------------

switch $(CF)
{
case debug :
  DEBUGGING = true ;
  ARCH = g ;
case release :
  DEBUGGING = ;
  ARCH = r ;
case rbug :
  DEBUGGING = true ;
  ARCH = ag ;
}

if $(DEBUGGING)
{
  JAVAFLAGS = -g ;
}
else
{
  JAVAFLAGS = -O ;
}

LCURLY = "{" ;
RCURLY = "}" ;

if $(UNIX)
{
  LINKEXECUTABLE += -lstdc++ ;

  LINKDLL = $(LINKEXECUTABLE) ;
  LINKMAIN = $(LINKEXECUTABLE) ;
  LINKAPPLICATION = $(LINKEXECUTABLE) ;
  LINKLIBRARY = ;
  SPLITPATH = ":" ;

  JAMSHELL = "/bin/ksh" ;
}

if $(NT)
{
  SPLITPATH = ";" ;

  # /Zi = Generate debug info in a pdb file (used for exes).
  # /Od = Disable optimizations.
  # /GZ = Enable runtime stack checks.
  OPTIMDEBUG = -D"_DEBUG" /Zi /Od /GZ ;

  # Inlining:
  # /Ob0 = Disabled.
  # /Ob1 = Only when specified with 'inline'.  (/Ob1 also enables the Force.)
  # /Ob2 = Any suitable function.

  # Optimization:
  # /O2 = optimize for speed
  OPTIMRELEASE = -D"NDEBUG" -D"BHB_RELEASE_ASSERT" /Ob1 /O2 ;

  switch $(CF)
  {
    case debug :
      OBJECTPDBFILE = $(LIBPATH)$(SLASH)objects$(ARCH).pdb ;
      DEBUGLINKFLAGS = /debug /incremental:yes ;

      OPTIM = $(OPTIMDEBUG) ;
    case release :
      DEBUGLINKFLAGS = ;

      OPTIM = $(OPTIMRELEASE) ;
    case rbug :
      OPTIMRELEASE += /Zi ;
      OPTIMDEBUG = $(OPTIMRELEASE) ;

      OBJECTPDBFILE = $(LIBPATH)$(SLASH)objects$(ARCH).pdb ;
      DEBUGLINKFLAGS = /debug ;

      OPTIM = $(OPTIMDEBUG) ;
  }

  # Unit testing is on unless explicitly turned off.
  if $(NOUNITTEST)
  {
    UNITTESTFLAGS = ;
  }
  else
  {
    UNITTESTFLAGS = /D"_UNITTEST" ;
  }

  switch $(CF)
  {
  case debug :
    # Link with MSVCRTD.LIB (meaning AFXDLL),
    # Link with stingray as dlls
    CFCFLAGS default =
      /MDd /D"_AFXDLL"
      /D_CMNDLL /D_SECDLL /D_GXDLL
      /D_BHB_CF_DEBUG
      ;
  case release :
    # Link with MSVCRT.LIB (meaning AFXDLL),
    # Link with stingray as dlls
    CFCFLAGS default =
      /MD /D"_AFXDLL"
      /D_CMNDLL /D_SECDLL /D_GXDLL
      /D_BHB_CF_RELEASE
      ;
  case rbug :
    # Link with MSVCRT.LIB (meaning AFXDLL),
    # Link with stingray as dlls
    CFCFLAGS default =
      /MD /D"_AFXDLL"
      /D_CMNDLL /D_SECDLL /D_GXDLL
      /D_BHB_CF_RELEASE
      ;
  }

  # Standard Link flags
  # flags for any EXE (dll, main, app)
  LINKEXECUTABLE =
    /nologo
    $(DEBUGLINKFLAGS)
    /machine:I386
    ;
  if $(LINKPROFILE)
  {
    LINKEXECUTABLE += /profile ;
  }
  if $(MAPFILE)
  {
    LINKEXECUTABLE += /map /mapinfo:lines ;
  }
  if $(VERBOSELINK)
  {
    LINKEXECUTABLE += /verbose ;
  }
  LINKDLL = /dll $(LINKEXECUTABLE) ;
  LINKMAIN = /subsystem:console $(LINKEXECUTABLE) ;
  LINKAPPLICATION = /subsystem:windows $(LINKEXECUTABLE) ;
  LINKLIBRARY = /lib /nologo ;

  if $(ALLOWWARN)
  {
    NOWARNINGS = ;
  }
  else
  {
    NOWARNINGS = /WX ; # Warnings are errors
  }

  STANDARDCFLAGS =
    /nologo
    /Zp8           # 8-byte struct alignment.
    /W3            # Warning level 3.
    /GX            # Enable C++ exception handling.
    /GR            # Enable RTTI
    $(NOWARNINGS)
    /D"NOMINMAX"
    /D"WIN32"
    /D"_WINDOWS"
    /D"_MBCS"
    /D_SECNOMSG
    $(UNITTESTFLAGS)
    "/I$(TOP:R=$(PWD))/3rdparty/inc"
    "/I$(TOP:R=$(PWD))/3rdparty/inc/stingray"
    "/I$(TOP:R=$(PWD))/3rdparty/inc/versant"
    /D"_WIN32_IE=0x0400" # Ensures compatibility with comctl32.dll & shell32.dll v4.71 and later
    /c             # Compile only (no link).
    /D"_GXNOMSG" # No MSG please!  (Objective Grid pragma messages, that is)
    /DODBCXXX_DLL # We're using odbc++.dll
    $(CFCFLAGS)
    ;
}

# ----------------------------
# End Basic Configuration
# ----------------------------
# You probably don't need to mess with anything below this point.


# ----------------
# Base dependencies
# ----------------

DEPENDS all : shell lib exe obj java jar ;
DEPENDS all shell files lib exe obj java : first ;
DEPENDS veryclean : clean ;
NOTFILE all first shell files lib exe obj dirs clean uninstall java veryclean ;
NOTFILE 
  all first shell files lib exe obj dirs clean uninstall java veryclean jar ;
ALWAYS veryclean clean uninstall ;

# Not yet installed grist (to distinguish from  the installed file
PREINSTALL = <preinstall> ;

# Allow a space or tab befor the '#include' when searching
# for headers.
HDRPATTERN = "^[ 	]*#[	 ]*include[	 ]*[<\"](.*)[\">].*$" ;

# Names of standard Jam files
JAMFILE  default = Jamfile ;
JAMRULES default = Bhbrules ;

# since we're using sh for NT, these are general
AWK		  default = awk ;
CHMOD		default = chmod ;
CP		  default = cp ;
DOT		  default	= . ;
DOTDOT	default	= .. ;
EXEMODE	default = 711 ;
FILEMODE	default = 644 ;
MKDIR		default = mkdir -p ;
MV		  default = mv -f ;
RCP		  default = rcp ;
RSH		  default = rsh ;
RM		  default = rm -rf ;
SED		  default = sed ;
SLASH		default = / ;

# ---------------------------
# Platform-specific variables
# ---------------------------

# Variables such as NT were set when we built jam itself.

# Variable    Meaning
# --------    -------
# CFCFLAGS    Configuration-specific compiler flags (NT only).
# PRELIB      Prefix for library names.
# PREDLL      Prefix for dll names.
# SUFDLL      Suffix for dll names.
# SUFRES      Suffix for compiled resources.

if $(UNIX)
{
  PRELIB    default = lib ;
  PREDLL    default = lib ;
  SUFDLL    default = .so ;
  SUFLIB		default = .a ;
  SUFOBJ		default = .o ;
  SUFEXE		default = "" ;
  SUFRES    default = .res ;

  AR		    default = ar ru ;
  AS		    default = as ;
  CC		    default = gcc ;
  C++		    default = $(CC) ;
  LINK		    default = $(CC) ;

  if $(OS) = SOLARIS
  {
    # Solaris build are currently working.  Allow this.
  }
  else if $(OS) = LINUX
  {
    EXIT Linux build isn't ready yet. ;
  }
  else
  {
    EXIT What unix are you building on? ;
  }
}
else if $(NT)
{
  OS = NT ;		# replace Windows_NT

  PRELIB    default = "" ;
  PREDLL    default = $(PRELIB) ;
  SUFDLL    default = .dll ;
  SUFLIB		default = .lib ;
  SUFOBJ		default = .obj ;
  SUFEXE		default = .exe ;
  SUFRES    default = .res ;

  AR		    default = link /nologo ;
  AS		    default = masm386 ;
  CC		    default = cl /nologo ;
  C++		    default = $(CC) ;
  LINK		  default = link ;

  RC = rc ;  # Resource compiler.
  AR = lib -nologo ;  # Archive command.
}
else
{
  EXIT We don't support this platform. ;
}

# -------------------
# BhbJam' Markup
# -------------------

# Markup an exe, lib or dll with our weird markup scheme.  E.g.
#
# MakeName targ : BhbJam : exe : locate ;
# targ -> "BhbJam84lg.exe" in $(TOP)/bin
#
# MakeName targ : og : dll : nomarkup ;
#
# targ -> "og.dll" wherever it's already supposed to be
#
# etc.
rule MakeName
{
  local _f_result = $(1) ;
  local _f_target = $(2) ;
  local _f_type = $(3) ;
  local _f_flags = $(4) ;

  if ! $($(_f_result))
  {
    local _f_path, _f_cfMark, _f_versionMark, _f_suffix, _f_prefix;

    local _f_locate = ;
    local _f_depend = ;
    local _f_grist = ;
    local _f_search = ;

    _f_suffix = "" ;
    _f_prefix = "" ;
    _f_cfMark = $(ARCH) ;
    _f_versionMark = $(BHBVERSION) ;

    switch $(_f_type)
    {
      case exe :
        _f_path = $(BINPATH) ;
        _f_suffix = $(SUFEXE) ;
        # if $(CF) = release { _f_flags += nomarkup ; }
      case dll :
        _f_path = $(LIBPATH) ;
        _f_suffix = $(SUFDLL) ;
        _f_prefix = $(PREDLL) ;
      case lib :
        _f_path = $(LIBPATH) ;
        _f_suffix = $(SUFLIB) ;
        _f_search = true ;
      case obj :
        _f_grist = true ;
        _f_path = $(LOCATE_TARGET) ;
        _f_suffix = $(SUFOBJ) ;
        _f_flags += nomarkup ;
      case pch :
        _f_grist = true ;
        _f_path = $(LOCATE_TARGET) ;
        _f_suffix = $(SUFPCH) ;
        _f_flags += nomarkup ;
      case res :
        _f_grist = true ;
        _f_path = $(LOCATE_TARGET) ;
        _f_suffix = $(SUFRES) ;
        _f_flags += nomarkup ;
      case jar :
        _f_path = $(JAVAROOT) ;
        _f_suffix = ".jar" ;
        _f_flags += nomarkup ;
      case * :
        _f_suffix = "."$(_f_type) ;
        _f_flags += nomarkup ;
        _f_path = $(LOCATE_TARGET) ;
        _f_grist = true ;
        _f_path = $(SUBDIR) ;
        _f_locate = true ;
    }

    for _f in $(_f_flags)
    {
      switch $(_f)
      {
        case 3rdparty :
          _f_path = $(3RDPARTYLIB) ;
          _f_versionMark = "" ;
          _f_cfMark = "" ;
        case nomarkup :
          _f_versionMark = "" ;
          _f_cfMark = "" ;
        case locate :
          _f_locate = true ;
        case depend :
          _f_depend = true ;
        case declare :
          _f_locate = true ;
          _f_depend = true ;
      }
    }

    local _f_base = $(_f_prefix)$(_f_target)$(_f_versionMark)$(_f_cfMark) ;
    local _f_name ;

    if $(_f_grist)
    {
      makeGristedName _f_name : $(_f_base:S=$(_f_suffix)) ;
    }
    else
    {
      _f_name = $(_f_base:S=$(_f_suffix)) ;
    }

    if $(_f_locate)
    {
      MakeLocate $(_f_name) : $(_f_path) ;
    }
    else if $(_f_search)
    {
      SEARCH on $(_f_name) = $(_f_path) ;
    }

    if $(_f_depend)
    {
      NOTFILE $(_f_target) ;
      DEPENDS $(_f_target) : $(_f_name) ;
    }

    $(_f_result) = $(_f_name) ;
  }
}

# Append to a flag for some stage of the compilation process.  e.g.:
#
# SetFlag foo.c : obj : CCFLAGS : -Dfoo ;
#
# SetFlag bozo : dll : LINKFLAGS : -R /usr/local/lib ;
#
rule SetFlag
{
  local s t ;

  # flags for anylib are both lib & dll
  if $(2) = anylib
  {
    MakeName s : $(1) : dll ;
    MakeName t : $(2) : lib ;
    s += t ;
  }
  else
  {
    MakeName s : $(1) : $(2) ;
  }

  $(3) on $(s) += $(4) ;
}


# ------------------
# Global rules
# ------------------

# Build an application, e.g. BhbJam:
#
# Application myFancyProgram : sourcefile.cpp fancyprog.cpp ;
rule Application
{
  MainFromObjects $(<) : $(>) : app ;
  Objects $(>) ;
}

# BuildPch pchfile : cppfileusedtobuild : headerupto ;
# e.g.
# BuildPch bhbafx.pch : bhbafx.cpp : bhbafx.h ;
# or
# BuildPch cellsafx.pch : cellsafx.cpp : stdafx.h ;
#
# the third paramater is optional, but otherwise you need that
# hdrstop pragma.  You should use a cppfile tailored to this purpose;
# the pchfile will depend on anything it depends on.
rule BuildPch
{
  if $(NT)
  {
    local o p h ;
    makeGristedName s : $(>) ;
    makeGristedName o : $(>:S=$(SUFOBJ)) ;
    makeGristedName p : $(<:S=.pch) ;

    MakeLocate $(p) : $(LOCATE_TARGET) ;

    BuiltByBuildOf $(p) : $(o) ;

    if $(3)
    {
      endh = $(3) ;
    }
    else
    {
      endh = "" ;
    }

    # /Yc = create precompiled header up to endheader
    C++FLAGS on $(o) = /Yc$(endh) ;
    CCFLAGS on $(o) = /Yc$(endh) ;
    PCHFILE on $(o) = $(p) ;
    $(o)-builds-$(p) = true ;
  }
}

# This is done on a file-for-file basis at the moment, since it's not
# normally safe to use it for all files in the dir.
# Syntax :
# UsePch file : pchfile : endhdr ;
# endhdr is optional, but requires #pragma hdrstop
rule UsePch
{
  if $(NT)
  {
    local o ;
    local p ;
    makeGristedName o : $(<:S=$(SUFOBJ)) ;
    makeGristedName p : $(>:S=.pch) ;

    if $(3)
    {
      endh = $(3) ;
    }
    else
    {
      endh = "" ;
    }

    for i in $(o)
    {
      if ! $($(i)-builds-$(p))
      {
        DEPENDS $(i) : $(p) ;
        # /Yu = use pch
        C++FLAGS on $(i) += /Yu$(endh) ;
        CCFLAGS on $(i) += /Yu$(endh) ;
        PCHFILE on $(i) = $(p) ;
      }
    }
  }
}

# Syntax:
# SubDirUsePch pchfile : endhdr ;
# Uses the pch file for all C and C++ files in the directory
rule SubDirUsePch
{
  SUBDIR_PCH_FILE = $(<) ;
  SUBDIR_PCH_END = $(>) ;
}

# Build a browse info file (.bsc) from the sbrs.
#
# We will build the .sbr files if $(BROWSE) is set.
rule BrowseInfo
{
  NOTFILE browse ;
  DEPENDS browse : $(<) ;
  ALWAYS $(<) ;
  Clean clean : $(<) ;
  Clean clean : $(TOP)$(SLASH)browse ;
}

# Tells jam that $(<) was built when we built $(>)
rule BuiltByBuildOf
{
  DEPENDS $(<) : $(>) ;
}

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

  CCFLAGS on $(<) += $(STANDARDCFLAGS) $(CCFLAGS) $(SUBDIRCCFLAGS) ;

  CcCommonFlags $(<) : $(>) ;
}

rule C++
{
  DEPENDS $(<) : $(>) ;

  C++FLAGS on $(<) += $(STANDARDCFLAGS) $(C++FLAGS) $(SUBDIRC++FLAGS) ;

  CcCommonFlags $(<) : $(>) ;
}

rule CcCommonFlags
{
  if $(NT)
  {
    # precompiled headers
    if $(SUBDIR_PCH_FILE)
    {
      UsePch $(<) : $(SUBDIR_PCH_FILE) : $(SUBDIR_PCH_END) ;
    }

    if $(DEBUGGING)
    {
      # all .obj's share a .pdb file -- this is much cleaner and
      # faster than the alternatives.  The debugging info will
      # get copied from this .pdb file to the pdb file of the exe's
      # by the linker.
      PDBFILE on $(<) = $(OBJECTPDBFILE) ;
      DEPENDS $(<) : $(OBJECTPDBFILE:D) ;
      MkDir $(OBJECTPDBFILE:D) ;
      Clean veryclean : $(OBJECTPDBFILE) ;
    }

    if $(BROWSE) && $(DEBUGGING)
    {
      # build browse info for Visual C++
      C++FLAGS on $(<) += /FR$(TOP)$(SLASH)browse$(SLASH) ;
      CCFLAGS on $(<) += /FR$(TOP)$(SLASH)browse$(SLASH) ;
      DEPENDS $(<) : $(TOP)$(SLASH)browse ;
      MkDir $(TOP)$(SLASH)browse ;
    }
  }
}

# Add entry(ies) to the classpath
rule ClassPath
{
  local path ;

  for path in $(<)
  {
    if $(NT)
    {
      CLASSPATH = $(CLASSPATH)";"$(path:R=$(PWD)) ;
    }
    else
    {
      CLASSPATH = $(CLASSPATH)":"$(path:R=$(PWD)) ;
    }
  }
}

# Clean files from a pattern.  This can be useful if you
# don't quite know what silly files got created.
# e.g.
# CleanMany clean : *.class ;
rule CleanMany
{
  DEPENDS $(<) : $(>) ;
  NOTFILE $(>) ;
}

# compile the versant .imp file to an .obj by way of schcomp
rule DBSchemaCompile
{
  local _schema _cxx ;
  makeGristedName _schema : $(>:S=.sch) ;
  makeGristedName _cxx : $(>:S=.cxx) ;
  MakeLocate $(_cxx) : $(LOCATE_TARGET) ;

  SchComp $(_schema) $(_cxx) : $(>) ;
  Objects $(_cxx) ;
}

# Build the .sch and the .cxx from the versant Schema .imp file
# must call with $(schemaName) $(cxxName) as targets in that order!
rule SchComp
{
  C++FLAGS on $(<) += $(SUBDIRC++FLAGS) $(C++FLAGS) $(STANDARDCFLAGS) ;
  LOCATE_TARGET on $(<) = $(LOCATE_TARGET) ;
  LOCATE on $(<) = $(LOCATE_TARGET) ;

  CcCommonFlags $(<) : $(>) ;

	HDRS on $(<) = $(HDRS) $(SUBDIRHDRS) ;

  if ! $(FAST)
  {
    HDRRULE on $(>) = HdrRule ;
    HDRSCAN on $(>) = $(HDRPATTERN) ;
    HDRSEARCH on $(>) = $(HDRS) $(SUBDIRHDRS) $(STDHDRS) ;
    HDRGRIST on $(>) = $(HDRGRIST) ;
  }
  
  SEARCH on $(>) = $(SEARCH_SOURCE) ;

  NOTFILE schema ;
  DEPENDS schema : $(<) ;
  DEPENDS $(<) : $(>) ;

  Clean clean : $(<) ;
}

# This is used for a define that should be set up if you're compling
# the file as a DLL.  Usually this is guarding some kind of dllexport/
# dllimport define.
# e.g.
# DefineForDLL _INV_FTL_INTERNAL ;
rule DefineForDLL
{
  SUBDIRC++FLAGS += "-D"$(<) ;
  SUBDIRCCFLAGS +=  "-D"$(<) ;
}

# Use the export library from an executable (and copy it to the lib dir.)
rule ExportLibrary
{
  if $(NT) && ! $(NOLINK)
  {
    local exeName libName ;
    MakeName exeName : $(<) : exe ;
    MakeName libName : $(<) : lib : locate ;

    DEPENDS lib : $(libName) ;

    local libWithExe = $(exeName:G=$(PREINSTALL):S=$(SUFLIB)) ;
    BuiltByBuildOf $(libWithExe) : $(exeName) ;
    LOCATE on $(libWithExe) = $(BINPATH) ;

    File $(libName) : $(libWithExe) ;
    NOPROPAGATE $(libName) ;
    Clean clean : $(libName) ;
  }
}

# Define some preprocessor macro for compliation
rule Define
{
  SubDirC++Flags -D$(<) ;
  SubDirCcFlags -D$(<) ;
}

# Copy a file.
rule File
{
  DEPENDS files : $(<) ;
  DEPENDS $(<) : $(>) ;
  SEARCH on $(>) = $(SEARCH_SOURCE) ;
}

# Files a1 b1 c1 : a b c ; 
#
# copies a to a1, b to b1, etc.
rule Files
{
  if $(<) && $(>)
  {
    RmFile $(<[1]) ;
    File $(<[1]) : $(>[1]) ;

    if $(<[2-]) && $(>[2-])
    {
      Files $(<[2-]) : $(>[2-]) ;
    }
  }
}

rule HdrRule
{
  # HdrRule source : headers : boundNameOfSource ;

  # N.B.	This rule is called during binding, potentially after
  # the fate of many targets has been determined, and must be
  # used with caution: don't add dependencies to unrelated
  # targets, and don't set variables on $(<).

  # Tell Jam that anything depending on $(<) also depends on $(>),
  # set SEARCH so Jam can find the headers, but then say we don't
  # care if we can't actually find the headers (they may have been
  # within ifdefs),

  local s ;

  if $(HDRGRIST) 
  { 
      s = $(>:G=$(HDRGRIST)) ;
  } else { 
      s = $(>) ; 
  }

  # we can use the boundNameOfSource to add the current directory
  # of the source into the search so #includes with quotes can search
  # there (the standard on NT).

  local headerDir = $(3:D) ;

  INCLUDES $(<) : $(s) ;
  SEARCH on $(s) = $(headerDir) $(HDRSEARCH) ;
  NOCARE $(s) ;

  # Propagate on $(<) to $(>)

  HDRSEARCH on $(s) = $(HDRSEARCH) ;
  HDRSCAN on $(s) = $(HDRSCAN) ;
  HDRRULE on $(s) = $(HDRRULE) ;
  HDRGRIST on $(s) = $(HDRGRIST) ;
}

# install everything...  The syntax looks like
#
# InstallTarget from : ToDir : ToName ;
#
# This is really a utility rule for Install
rule InstallTarget
{
  local installTarget ;

  if $(3)
  {
    installTarget = $(3:G="<install>") ;
  }
  else
  {
    installTarget = $(<:G="<install>") ;
  }
  
  MakeLocate $(installTarget) : $(>:R=$(INSTALL_DIR)) ;
  Files $(installTarget) : $(<) ;
  DEPENDS install : $(installTarget) ;
}

# Install a decorated name.  For example
#
# Install BhbJam : exe : bin ;
#  installs BhbJam84lg.exe (or whatever) into $(INSTALL_DIR)/bin
# Install BhbJam : lib : sdk : sdk.lib ;
#  installs BhbJam84lg.lib (from $(TOP)/lib) into $(INSTALL_DIR)/sdk/sdk.lib
# Install fdkfuncs.h : installFile : sdk ;
#  isntalls fdkfuncs.h into $(INSTALL_DIR)/sdk
rule Install
{
  local file ;
  if $(2) = installFile
  {
    makeGristedName file : $(1) ;
    SEARCH on $(file) = $(SEARCH_SOURCE) ;
  }
  else
  {
    MakeName file : $(1) : $(2) ;
  }

  InstallTarget $(file) : $(3) : $(4) ;
}

# Compiling the package all-in-one, by making a new class that merely
# includes all of the classes in the package.  The point is to reduce
# the number of costly calls to javac, and to avoid having jam deal
# with dependencies
rule JavaPackage
{
  local s ;
  makeGristedName s : $(>) ;
  LOCATE on $(s) = $(SUBDIR) ;

  local jp jc ;
  makeGristedName jp : JamPackage.java ;
  jc = $(jp:S=.class) ;
  LOCATE on $(jp) $(jc) = $(SUBDIR) ;

  local pkj ;

  if $(<) != ""
  {
    pkj = $(<).JamPackage ;
  }
  else
  {
    pkj = JamPackage ;
  }

  PACKAGENAME on $(jp) = $(pkj) ;

  JamPackage $(jp) : $(>:S="") ;

  INCLUDES $(jp) : $(s) ;
  DEPENDS $(jp) : $(SUBDIR)$(SLASH)Jamfile ;
  DEPENDS $(jp) : $(SUBDIR)$(SLASH)$(>) ;

  RootJamPackage $(jp) : $(pkj) ;

  Clean clean : $(jc) $(jp) ;
  CleanMany clean : $(SUBDIR)$(SLASH)*.class ;
}

# build the JamPackage.java file
rule JamPackage
{
  NOTFILE $(>) ;
}

# build the RootJamPackage.java file (only once) and compile it.
rule RootJamPackage
{
  local rjp = $(JAVAGRIST)RootJamPackage.java ;
  local rjc = $(rjp:S=.class) ;

  LOCATE on $(rjp) $(rjc) = $(JAVAROOT) ;

  PACKAGENAME on $(rjp) = RootJamPackage ;

  INCLUDES $(rjp) : $(<) ;

  DEPENDS $(rjp) : $(<) ;

  JamPackage $(rjp) : $(>) ;

  Clean clean : $(rjp) $(rjc) ;

  if ! $(root-jam-package-initted)
  {
    root-jam-package-initted = true ;
    JavaC $(rjc) : $(rjp) ;
    SUBDIR on $(rjc) = $(JAVAROOT) ;
  }
}

# compile a java file.
rule JavaC
{
  DEPENDS $(<) : $(>) ;
  DEPENDS java : $(<) ;
  # ensure that RootJamPackage is built every time any java
  # file needs to be built.  This does two things - 1. get around
  # a bug in 1.2.2's javac 2. creates minimal builds from subdirs
  DEPENDS RootJamPackage : java ;
}

# build a jar file from various packages. 
# $(2) is from packages that we build
# $(3) is third party packages.
# includes subpackages in package
#
# so, this looks like:
# Jar poserver :
#   com.mbruce.poserver
#   com.mbruce.util
#   com.mbruce.db
#   :
#   com.javtech.coppelia
#   org.xml.sax
#   ;
# 
# optional 4th argument is patterns for files to include.
# default:
#  *.class *.properties
rule Jar
{
  local jarFile ;
  MakeName jarFile : $(<) : jar : declare ;
  DEPENDS $(jarFile) : java ;
  NOTFILE $(2) $(3) ;
  DEPENDS jar : $(<) ;

  if $(3)
  {
    JAR3RDPARTY on $(<) = $(3) ;
    JARHAS3RDPARTY on $(<) = true ;
  }
  else
  {
    JAR3RDPARTY on $(<) = foo ;
    JARHAS3RDPARTY on $(<) = false ;
  }

  if $(4)
  {
    # -type b == type block-special -- effectively -false
    # for the null condition at the end of the ors
    # so it looks like : -name "*.class" -type b -- effectively
    # -name "*.class"
    JARPATTERNS on $(<) = -type f | egrep '$(4)' ;
  }
  else
  {
    JARPATTERNS on $(<) = -type f | egrep '.*(class|properties|fmt)$' | grep -v JamPackage.class ;
  }

  Clean clean : $(jarFile) ;
}


# much like Jar, but runs the persistable object store stuff on
# the classes first
rule JarPersistable
{
  local jarFile ;
  MakeName jarFile : $(<) : jar : declare ;
  DEPENDS $(jarFile) : java ;
  NOTFILE $(2) $(3) ;
  DEPENDS jar : $(<) ;

  if $(3)
  {
    JAR3RDPARTY on $(<) = $(3) ;
    JARHAS3RDPARTY on $(<) = true ;
  }
  else
  {
    JAR3RDPARTY on $(<) = foo ;
    JARHAS3RDPARTY on $(<) = false ;
  }

  if $(4)
  {
    # -type b == type block-special -- effectively -false
    # for the null condition at the end of the ors
    # so it looks like : -name "*.class" -type b -- effectively
    # -name "*.class"
    JARPATTERNS on $(<) = -type f | egrep '$(4)' ;
  }
  else
  {
    JARPATTERNS on $(<) = -type f | egrep '.*(class)$' | grep -v JamPackage.class ;
  }

  Clean clean : $(jarFile) ;
}


# like jar, but obfuscates.
#
# Jode pricing : 
#      pricing.jos 
#      : 
#      *.properties resources/*
#      ;
#
# i.e. obfuscate with file pricing.jos as a spec.  After obfuscation
# include anything that matches the find pattern.
rule Jode
{
  local jarFile ;
  MakeName jarFile : $(<) : jar : declare ;
  DEPENDS $(jarFile) : java ;
  DEPENDS jar : $(<) ;

  MakeLocate $(>) : $(JAVAROOT) ;
  DEPENDS $(jarFile) : $(>) ;

  if $(3)
  {
    JARHASEXTRAS on $(<) = true ;
    JAREXTRAS on $(<) = -name" "\"$(3)\"" "-o -type b ;
  }

  Clean clean : $(jarFile) $(jarFile:S=".tbl") ;
}

#
# like jar but makes tar files:
#
# Tar wpserver :
#   apacheBhbJam 
#   :
#   apache*s.dll
#   ftl*s.dll
#   ;
#
rule Tar
{
  local tarFile ;
  MakeName tarFile : $(<) : tar.gz : declare ;
  DEPENDS $(tarFile) : $(2) ;
  NOTFILE $(2) ;
  TARPATTERNS on $(<) = -name" "\"$(3)\"" "-o -type b ;

  Clean clean : $(tarFile) ;
}

# Build a standard BhbJam library (a dll on nt)
# Syntax is like application
# Library mfctool : regkey.cpp font.cpp ... ;
rule Library
{
  LibraryOfType $(<) : $(>) : dll ;
}

# A library that's always static.
rule StaticLibrary
{
  LibraryOfType $(<) : $(>) : lib ;
}

# A library that's always a dll
rule DynamicLibrary
{
  LibraryOfType $(<) : $(>) : dll ;
}

# A library that might be a DLL or a static lib.  If it's a DLL, then
# the export symbols should be defined by a def file that's generated
# from the objects.  (Sparing the code writer some __declspec(dllexport)
# nonsense).  Note that static variables cannot be exported in this
# fashion.
rule DefLibrary
{
  DefDynamicLibrary $(<) : $(>) ;
}

# a library that's a dll and always uses a generated .def file
rule DefDynamicLibrary
{
  if $(NT)
  {
    local libName dllName ;
    MakeName libName : $(<) : lib ;
    MakeName dllName : $(<) : dll ;

    local def ;
    makeGristedName def : $(<:S=.def) ;
    MakeLocate $(def) : $(LOCATE_TARGET) ;

    DefFile $(def) : $(>) ;
    DEFFILE on $(libName) $(dllName) = $(def) ;
    DEPENDS $(libName) $(dllName) : $(def) ;
  }

  LibraryOfType $(<) : $(>) : dll ;
}

if $(NT)
{
  # Generate .def file for a library from the .objs
  rule DefFile
  {
    local s ;
    makeGristedName s : $(>:S=$(SUFOBJ)) ;

    DEPENDS $(<) : $(s) ;
    DEPENDS $(<) : $(SUBDIR)$(SLASH)Jamfile ;

    SUBDIR on $(<) = $(SUBDIR) ;

    DefHeader $(<) ;
    DefSymbols $(<) : $(s) ;

    Clean clean : $(<) ;
  }
}

# utility rule for building some form of library
rule LibraryOfType
{
  LibraryFromObjects $(<) : $(>) : $(3) ;
  Objects $(>) ;
}

# Build a .lib or a .dll from the objects.   There's a lot to clean
# up.  Note the use of the export library -- it depends on the .dll.
rule LibraryFromObjects
{
  local name objName ;
  MakeName name : $(<) : $(3) : declare ;
  MakeName objName : $(>) : obj ;

  DEPENDS obj : $(objName) ;
  DEPENDS lib : $(name) ;

  DEPENDS $(name) : $(objName) ;

  if $(3) = dll && $(NT)
  {
    local exportName ;
    MakeName exportName : $(<) : lib : declare ;
    # building the lib makes the exportName -- tell jam this
    BuiltByBuildOf $(exportName) : $(name) ;
    Clean clean : $(exportName) ;
    NOPROPAGATE $(exportName) ;
  }

  if $(3) = dll
  {
    SetFlag $(<) : dll : LINKFLAGS : $(LINKDLL) ;
    SetFlag $(>) : obj : C++FLAGS : $(DLLCOMPILEFLAG) ;
    SetFlag $(>) : obj : CCFLAGS : $(DLLCOMPILEFLAG) ;

    if $(DEBUGGING) && $(NT)
    {
      SetFlag $(<) : lib : PDBFILE : $(LIBPATH)$(SLASH)$(name:S=.pdb) ;
      Clean clean : $(LIBPATH)$(SLASH)$(name:S=.pdb) ;
    }

    if $(NT)
    {
      Clean clean : $(LIBPATH)$(SLASH)$(name:S=.map) ;
      Clean clean : $(LIBPATH)$(SLASH)$(name:S=.pdb) ;
      Clean clean : $(LIBPATH)$(SLASH)$(name:S=.ilk) ;
      Clean clean : $(LIBPATH)$(SLASH)$(name:S=.exp) ;
      Clean clean : $(LIBPATH)$(SLASH)$(name:S=.lib) ;
      Clean clean : $(LIBPATH)$(SLASH)$(name:S=._ll) ;
      Clean clean : $(LIBPATH)$(SLASH)$(name:S=.pbi) ;
      Clean clean : $(LIBPATH)$(SLASH)$(name:S=.pbo) ;
      Clean clean : $(LIBPATH)$(SLASH)$(name:S=.pbt) ;
    }

    if ! $(NOLINK)
    {
      Link $(name) : $(objName) ;
    }
  }
  else
  {
    SetFlag $(<) : lib : LINKFLAGS : $(LINKLIBRARY) ;
    SetFlag $(>) : obj : C++FLAGS : $(LIBCOMPILEFLAG) ;
    SetFlag $(>) : obj : CCFLAGS : $(LIBCOMPILEFLAG) ;
    if ! $(NOLINK)
    {
      LinkStaticLibrary $(name) : $(objName) ;
    }
  }

  Clean clean : $(name) ;
}

# Link an executable.
rule Link
{
  # so we can change directories
  SUBDIR on $(<) = $(SUBDIR) ;
  LOCATE_TARGET on $(<) = $(LOCATE_TARGET) ;
}

# set some linkflags on an executable or dll
rule LinkFlags
{
  SetFlag $(<) : exe : LINKFLAGS : $(>) ;
  SetFlag $(<) : dll : LINKFLAGS : $(>) ;
}

# Tell the linker which libraries to link an executable too.  Note
# that we need to link for .dll's and .exe's but not for .lib's.
#
# LinkLibraries BhbJam : mfctool mdi ... ;
rule LinkLibraries
{
  local exeName dllName libraries ;
  MakeName exeName : $(<) : exe ;
  MakeName dllName : $(<) : dll ;

  if $(NT)
  {
    MakeName libraries : $(>) : lib : $(3) ;

    DEPENDS $(exeName) $(dllName) : $(libraries) ;
    NEEDLIBS on $(exeName) $(dllName) += $(libraries) ;
  }
  else
  {
    # depend on the abstract name of the libraries so we don't have
    # to figure out if the're .so or .a
    NOTFILE $(>) ;
    DEPENDS $(exeName) $(dllName) : $(>) ;

    LINKLIBS on $(exeName) $(dllName) += 
      -L$(LIBPATH) -l$(>)$(BHBVERSION)$(ARCH) ;
  }
}

# Build a command-line program (rather than a gui-based mess)
#
# Main putreg : putreg.cpp ;
rule Main
{
  MainFromObjects $(<) : $(>) : main ;
  Objects $(>) ;
}

rule MainFromObjects
{
  local name objName ;
  MakeName name : $(<) : exe : declare ;
  MakeName objName : $(>) : obj ;

  DEPENDS exe : $(name) ;
  DEPENDS $(name) : $(objName) ;

  Clean clean : $(name) ;

  if $(3) = main
  {
    SetFlag $(<) : exe : LINKFLAGS : $(LINKMAIN) ;
    SetFlag $(>) : obj : C++FLAGS : $(MAINCOMPILEFLAG) ;
    SetFlag $(>) : obj : CCFLAGS : $(MAINCOMPILEFLAG) ;
  }
  else
  {
    SetFlag $(<) : exe : LINKFLAGS : $(LINKAPPLICATION) ;
    SetFlag $(>) : obj : C++FLAGS : $(APPLICATIONCOMPILEFLAG) ;
    SetFlag $(>) : obj : CCFLAGS : $(APPLICATIOCOMPILEFLAG) ;
  }

  if $(DEBUGGING)
  {
    SetFlag $(<) : exe : PDBFILE : $(BINPATH)$(SLASH)$(name:S=.pdb) ;
    Clean clean : $(BINPATH)$(SLASH)$(name:S=.pdb) ;
  }

  Clean clean : $(BINPATH)$(SLASH)$(name:S=.map) ;
  Clean clean : $(BINPATH)$(SLASH)$(name:S=.pdb) ;
  Clean clean : $(BINPATH)$(SLASH)$(name:S=.ilk) ;
  Clean clean : $(BINPATH)$(SLASH)$(name:S=.exp) ;
  Clean clean : $(BINPATH)$(SLASH)$(name:S=.lib) ;

  if ! $(NOLINK)
  {
    Link $(name) : $(objName) ;
  }
}

# Tell jam where a file goes, and make sure the directory exists.
rule MakeLocate
{
  if $(>)
  {
    LOCATE on $(<) = $(>) ;
    Depends $(<) : $(>[1]) ;
    MkDir $(>[1]) ;
  }
}

# Make sure a directory exists.  Note that this is gated, so you
# can safely call it more than once on the same directory.
rule MkDir
{
	if $(<) != $(DOT) && ! $($(<)-mkdir) 
	{
    local s ;

    # Cheesy gate to prevent multiple invocations on same dir
    # MkDir1 has the actions 
    # If dir exists, don't update it
    # Arrange for jam dirs

    $(<)-mkdir = true ;
    MkDir1 $(<) ;
    NOUPDATE $(<) ;
    Depends dirs : $(<) ;

    # Recursively make parent directories.
    # $(<:P) = $(<)'s parent, & we recurse until root

    s = $(<:P) ;

    if $(NT)
    {
      switch $(s)
      {
      case *:   : s = ;
      case *:\\ : s = ;
      }
    }

    if $(s) && $(s) != $(<)
    {
      Depends $(<) : $(s) ;
      MkDir $(s) ;
    }
    else if $(s)
    {
      NOTFILE $(s) ;
    }
	}
  else if $(<) = $(DOT)
  {
    NOUPDATE $(<) ;
  }
}

# Compile some file into a .obj
#
# This assigns the standard $(LOCATE_TARGET), $(SEARCH_SOURCE) stuff
rule Object
{
	local h ;

	# locate object and search for source, if wanted

	Clean clean : $(<) ;

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

	# Save HDRS for -I$(HDRS) on compile.

	HDRS on $(<) = $(HDRS) $(SUBDIRHDRS) ;

	# handle #includes for source: Jam scans for headers with
	# the regexp pattern $(HDRSCAN) and then invokes $(HDRRULE)
	# with the scanned file as the target and the found headers
	# as the sources.  HDRSEARCH is the value of SEARCH used for
	# the found header files.  Finally, if jam must deal with 
	# header files of the same name in different directories,
	# they can be distinguished with HDRGRIST.

  if ! $(FAST)
  {
    HDRRULE on $(>) = HdrRule ;
    HDRSCAN on $(>) = $(HDRPATTERN) ;
    HDRSEARCH on $(>) = $(HDRS) $(SUBDIRHDRS) $(STDHDRS) ;
    HDRGRIST on $(>) = $(HDRGRIST) ;
  }

	# if source is not .c, generate .c with specific rule

	switch $(>:S)
	{
	  case .c :	Cc $(<) : $(>) ;
	  case .C :	C++ $(<) : $(>) ;
	  case .cc :	C++ $(<) : $(>) ;
	  case .cpp : C++ $(<) : $(>) ;
    case .cxx : C++ $(<) : $(>) ;
    case .imp : DBSchemaCompile $(<) : $(>) ;
	  case * :	EXIT "Unknown suffix" $(>:S) "in Object!" ;
	}
}

# Set flags.  Even easier wrappers to SetFlag
rule ObjectCcFlags { SetFlag $(<) : obj : CCFLAGS : $(>) ; }
rule ObjectC++Flags { SetFlag $(<) : obj : C++FLAGS : $(>) ; }
rule ObjectHdrs { SetFlag $(<) : obj : HDRS : $(>) ; }

# This rule loops through the objects and builds them.
# We build objects only once for a given
# grist; note that one source file compiled with multiple
# different flags (for example) should give two gristed names.
rule Objects
{
  local i s ;

  # Add grist to file names
  makeGristedName s : $(<) ;

  for i in $(s)
  {
    if ! $($(i)-object)
    {
      Object $(i:S=$(SUFOBJ)) : $(i) ;
      DEPENDS obj : $(i:S=$(SUFOBJ)) ;
      $(i)-object = true ;
    }
  }
}

# Say that an application depends on some compiled resources:
#
# Resources BhbJam : BhbJam.rc ;
rule Resources
{
  # Fully qualify the source and target names according to our convention.
  makeGristedName s : $(>) ;

  local te td ;
  MakeName te : $(<) : exe ;
  MakeName td : $(<) : dll ;
  local t = $(te) $(td) ;

  # Invoke the ResourceCompiler rule on each .rc file.
  for i in $(s)
  {
    local res = $(i:S=$(SUFRES)) ;
    ResourceCompiler $(res) : $(i) ;
  }

  # Specify the link-time dependency of the exe on the compiled resources.
  NEEDRES on $(t) += $(s:S=$(SUFRES)) ;
  DEPENDS $(t) : $(s:S=$(SUFRES)) ;
}

# This rule is to .rc files what the C++ rule is to .cpp files.
rule ResourceCompiler
{
  MakeLocate $(<) : $(LOCATE_TARGET) ;
  SEARCH on $(>) = $(SEARCH_SOURCE) ;

  if ! $(FAST)
  {
    HDRRULE on $(>) = HdrRule ;
    HDRSCAN on $(>) = $(HDRPATTERN) ;
    HDRSEARCH on $(>) = $(SEARCH_SOURCE) $(HDRS) $(SUBDIRHDRS) $(STDHDRS) ;
    HDRGRIST on $(>) = $(HDRGRIST) ;
  }

  RCFLAGS on $(<) += $(RCFLAGS) ;
  SUBDIRRCFLAGS on $(<) += $(SUBDIRRCFLAGS) ;

  Clean clean : $(<) ;
  DEPENDS $(<) : $(>) ;
}

# Set some resource compilation flags
#
# ResourceFlags BhbJam.rc : -I../mfctool ;
rule ResourceFlags
{
  SetFlag $(<) : res : RCFLAGS : $(>) ;
}

rule RmTemps
{
  TEMPORARY $(>) ;
}

# Add to the subdirectories of the current directory where jam
# will go looking for your source files.
rule Search
{
  SEARCH_SOURCE += $(SUBDIR)$(SLASH)$(<) ;
}

rule SubDirCcFlags
{
  SUBDIRCCFLAGS += $(<) ;
}

rule SubDirC++Flags
{
  SUBDIRC++FLAGS += $(<) ;
}

rule SubDirHdrs
{
  SUBDIRHDRS += $(<) ;
}

rule SubInclude
{
	local s ;

	# That's
	#	SubInclude TOP d1 [ d2 [ d3 [ d4 ] ] ]
	#
	# to include a subdirectory's Jamfile.

	if ! $($(<[1]))
	{
	    EXIT Top level of source tree has not been set with $(<[1]) ;
	}

	makeDirName s : $(<[2-]) ;
	
	include $(JAMFILE:D=$(s):R=$($(<[1]))) ;
}

rule UserSubDir
{
	#
	# d1 ... are the directory elements that lead to this directory 
	# from $(TOP).  We construct the system dependent path from these
	# directory elements in order to set search&locate stuff.
	# 

	# Get path to current directory from root using makeSubDir.
	# Save dir tokens for other potential uses.

	makeDirName s : $(<[2-]) ;
	SUBDIR = $(s:R=$($(<[1]))) ;
  SUBDIR_TOKENS = $(<[2-]) ;

	# Now set up SEARCH_SOURCE, LOCATE_TARGET, SOURCE_GRIST
	# These can be reset if needed.	 For example, if the source
	# directory should not hold object files, LOCATE_TARGET can
	# subsequently be redefined.

	SEARCH_SOURCE = $(SUBDIR) ;
	LOCATE_SOURCE = $(ALL_LOCATE_TARGET) $(SUBDIR) ;
  LOCATE_TARGET = $(SUBDIR)$(SLASH)$(ARCHDIR) ;
	makeGrist SOURCE_GRIST : $(<[2-]) ;

	# Reset per-directory ccflags, hdrs

	SUBDIRCCFLAGS = ;
	SUBDIRC++FLAGS = ;
	SUBDIRHDRS = ;
  SUBDIR_PCH_FILE = ;
  SUBDIR_PCH_END = ;

  SUBDIR_RCFLAGS = ;
}

# ----------
# Actions
# ----------

# We should make sure the timestamp of the the target is the same as the 
# the timestamp of the dependency, so we don't rebuild it by mistake
actions quietly BuiltByBuildOf 
{ 
  touch -cf $(>) $(<)
}

actions together JamPackage
{
  sh $(TOP)/tools/makepackage.sh $(PACKAGENAME) $(>) > $(<)
}

if ! $(JIKESPATH)
{
  actions JavaC
  {
    cd $(SUBDIR)
    javac $(JAVAFLAGS) -classpath "$(CLASSPATH)" -sourcepath "$(JAVAROOT:R=$(PWD))" -J-Xmx256m $(>:BS)
  }
}
else
{
  # note the use of the shell's JIKESPATH, not ours -- because otherwise
  # jam would split it.
  JIKESPATHQUOTE = "$JIKESPATH" ;
  actions together JavaC
  {
    cd $(JAVAROOT)
    if jikes $(JAVAFLAGS) -classpath "$(JAVAROOT:R=$(PWD))$(SPLITPATH)$(CLASSPATH)$(SPLITPATH)$(JIKESPATHQUOTE)" -Xdepend $(>:R=$(PWD))
    then
      exit 0
    else
      rm -f $(<)
    fi
  }
}

actions Jar
{
rm -f $(<:R=$(JAVAROOT):S=.jar)
touch $(<:R=$(JAVAROOT):S=.jar)

function doPackage
$(LCURLY)
  package=$1
  path=$2
  dir=`echo $package | sed s,\\\\.,/,g` 
  (
    cd $path
    find $dir $(JARPATTERNS) | xargs jar uf $(<:R=$(JAVAROOT):S=.jar)
  )
$(RCURLY)

for pkg in $(2)
do
  doPackage $pkg $(JAVAROOT)
done

if [ " $(JARHAS3RDPARTY) " = " true " ]
then
  for pkg in $(JAR3RDPARTY)
  do
    doPackage $pkg $(JAVA3RDPARTYROOT)
  done
fi
}


actions JarPersistable
{
rm -f $(<:R=$(JAVAROOT):S=.jar)
touch $(<:R=$(JAVAROOT):S=.jar)
rm -f $(<:R=$(JAVAROOT):S=.temp.jar)
touch $(<:R=$(JAVAROOT):S=.temp.jar)
rm -rf $(<:R=$(JAVAROOT):S=.osjitemp)
mkdir $(<:R=$(JAVAROOT):S=.osjitemp)

function doPackage
$(LCURLY)
  package=$1
  path=$2
  dir=`echo $package | sed s,\\\\.,/,g` 
  class=`echo $dir.class`
  (
    cd $path
    jar uf $(<:R=$(JAVAROOT):S=.temp.jar) $class
  )
$(RCURLY)

for pkg in $(2)
do
  doPackage $pkg $(JAVAROOT)
done

if [ " $(JARHAS3RDPARTY) " = " true " ]
then
  for pkg in $(JAR3RDPARTY)
  do
    doPackage $pkg $(JAVA3RDPARTYROOT)
  done
fi

# must set the classpath for OSJI to run properly.  This next line sux and should go.
# if anyone thinks of a good way to get rid of it, go for it.
export CLASSPATH=$(CLASSPATH)
$(OSJI_HOME)/bin/osjcfp -dest $(<:R=$(JAVAROOT):S=.osjitemp) -classpath $(CLASSPATH) -quiet $(<:R=$(JAVAROOT):S=.temp.jar)

# now take osji's results and put them in the actual jar file, then clean up.
cd $(<:R=$(JAVAROOT):S=.osjitemp)
find . -name "*.class" -print | xargs jar uf $(<:R=$(JAVAROOT):S=.jar)
cd $(JAVAROOT)
rm -rf $(<:R=$(JAVAROOT):S=.osjitemp)
rm -f $(<:R=$(JAVAROOT):S=.temp.jar)
}


actions Jode
{
  cd $(JAVAROOT)
  java -cp ".$(SPLITPATH)$(CLASSPATH)$(SPLITPATH)$(TOP:R=$(PWD))/tools/jode.jar" jode.obfuscator.Main $(>)
  if [ $? = 0 ] && ! [ " $(JARHASEXTRAS) " = " true " ]
  then
      find . $(JAREXTRAS) | xargs jar uf $(<:R=$(JAVAROOT):S=.jar)
  fi
  exit $?
}

actions Tar
{
  find $(TOP) $(TARPATTERNS) | xargs tar czf $(<:R=$(TOP):S=.tar.gz)
}

actions piecemeal together existing Clean
{
  $(RM) $(>)
}

actions piecemeal together CleanMany
{
  $(RM) $(>)
}

actions File
{
  $(RM) $(<)
  $(CP) $(>) $(<)
}

actions GenFile1
{
  $(>[1]) $(<) $(>[2-])
}

actions MkDir1
{
  $(MKDIR) $(<)
}

actions quietly RmFile
{
  $(RM) $(<)
}

actions quietly updated piecemeal together RmTemps
{
  $(RM) $(>)
}

actions SchComp
{
  # cd to where the target files go (we know that's writable)
  cd $(LOCATE_TARGET)
  # run schcomp
  if schcomp $(OPTIM) $(C++FLAGS) -I$(HDRS:R=$(PWD)) $(>:R=$(PWD))
  then
    # that just made .sch and .cxx in locate-target. hopefully they go there.

    # OK, the schema compiler erased some all important stuff from xstring.
    # put it back
    sed \
      -e '/^#line 603 .*xstring"$/ {' \
      -e '  n' \
      -e '  /^#pragma warning(disable:4231)$/ {' \
      -e '    r $(TOP:R=$(PWD))/tools/stringexport.h' \
      -e '  }' \
      -e '}' \
      < $(>:B).cxx > $(>:B).tmp

    # remove #line directives, which seem to choke the compiler...
    sed 's:^#line://#line:' < $(>:B).tmp > $(>:B).cxx 
    rm -f $(>:B).tmp
  else
    exit 1
  fi
}

# ----------
# Platform Actions
# ----------

if $(NT)
{
  actions Cc bind PCHFILE
  {
    $(CC) /c $(OPTIM) /I$(HDRS) $(CCFLAGS) /Fo$(<[1]) /Fp$(PCHFILE) /Tc$(>[1) /Fd$(PDBFILE)
  }

  actions C++ bind PCHFILE
  {
    $(C++) /c $(OPTIM) /I$(HDRS) $(C++FLAGS) /Fo$(<[1]) /Fp$(PCHFILE) /Tp$(>[1]) /Fd$(PDBFILE)
  }

  # we need to CD to where the object files are so we don't have to give the
  # full path names of the objects (notice the $(>:BS)) -- otherwise
  # the linker internally runs out of room and dies...
  actions Link bind NEEDLIBS NEEDRES DEFFILE
  {
    cd $(LOCATE_TARGET)
    $(LINK) $(LINKFLAGS) /def:$(DEFFILE:R=$(PWD)) /out:$(<:R=$(PWD)) $(NEEDRES:R=$(PWD)) /pdb:$(PDBFILE:R=$(PWD)) $(UNDEFS) $(>:BS) $(LINKLIBS) $(NEEDLIBS:R=$(PWD)) /LIBPATH:$(3RDPARTYLIB:R=$(PWD))
  }

  # nt links libraries in the same way as dlls and exes
  rule LinkStaticLibrary
  {
    Link $(<) : $(>) ;
  }

  actions DefHeader
  {
    echo LIBRARY $(<:B)$(BHBVERSION)$(ARCH) > $(<)
    echo >> $(<)
    echo EXPORTS >> $(<)
  }

  actions piecemeal DefSymbols
  {
    cd $(SUBDIR)$(SLASH)$(ARCHDIR)
    sh $(TOP:R=$(PWD))/tools/exportsymbols.sh $(>:BS) >> $(<:R=$(PWD))
  }

  actions ResourceCompiler
  {
    $(RC) /fo $(<) $(RCFLAGS) $(UNITTESTFLAGS) $(SUBDIRRCFLAGS) $(>)
  }

  actions BrowseInfo
  {
    bscmake /nologo /n /o$(<) $(TOP)/browse/*.sbr
  }

  if $(BROWSE)
  {
    BrowseInfo $(TOP)$(SLASH)bin$(SLASH)browse.bsc ;
  }
}
else
{
  actions Cc
  {
    $(C++) -c $(C++FLAGS) $(OPTIM) -I$(HDRS) -o $(<) $(>)
  }

  actions C++
  {
    $(C++) -c $(C++FLAGS) $(OPTIM) -I$(HDRS) -o $(<) $(>)
  }

  actions Link
  {
    $(LINK) $(LINKFLAGS) -o $(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKIBS)
  }

  actions together LinkStaticLibrary
  {
    $(C++) $(ARCHIVEFLAGS) -o $(<) $(>) ;
  }

  actions BrowseInfo
  {
    bscmake /nologo /n /o$(<) $(TOP)/browse/*.sbr
  }

  if $(BROWSE)
  {
    BrowseInfo $(TOP)$(SLASH)bin$(SLASH)browse.bsc ;
  }
}

#
# Compatibility
#
rule BhbLibrary { Library $(<) : $(>) ; }
rule BhbDefLibrary { Library $(<) : $(>) ; }
rule BhbDefLibrary { Library $(<) : $(>) ; }
rule BhbDLLDebugLibraries { LinkLibraries $(<) : $(>) : $(3) ; }
rule BhbDLLDebugDefine { DefineForDLL $(<) : $(>) ; }
rule BhbDLLLibraries { LinkLibraries $(<) : $(>) : $(3) ; }
rule BhbDefine { Define $(<) : $(>) ; }
rule BhbLinkFlags  
{ 
  SetFlag $(<) : exe : LINKFLAGS : $(>) ; 
  SetFlag $(<) : dll : LINKFLAGS : $(>) ; 
}
rule BhbDLLLinkFlags { SetFlag $(<) : dll : LINKFLAGS : $(>) ; }
rule NTSucks_ReorderLibraries
{
  if $(NT)
  {
    if $(CF) = debug
    {
      BhbLinkFlags $(<) :
        /nodefaultlib:msvcrtd
        /nodefaultlib:libcmtd
        msvcrtd.lib
        libcmtd.lib
        ;
    }
    else if $(CF) = release
    {
      BhbLinkFlags $(<) :
        /nodefaultlib:msvcrt
        /nodefaultlib:libcmt
        msvcrt.lib
        libcmt.lib
        ;
    }
    else if $(CF) = rbug
    {
      BhbLinkFlags $(<) :
        /nodefaultlib:msvcrt
        /nodefaultlib:libcmt
        msvcrt.lib
        libcmt.lib
        ;
    }
  }
}
rule BhbMain { Main $(<) : $(>) ; }
rule BhbApplication { Application $(<) : $(>) ; }
rule BhbLinkLibraries { LinkLibraries $(<) : $(>) : $(3) ; }
rule BhbDynamicLibrary { DynamicLibrary $(<) : $(>) ; }
rule BhbStaticLibrary { StaticLibrary $(<) : $(>) ; }
rule BhbExeExportLibrary { ExportLibrary $(<) : $(>) ; }
rule InstallProgram { Install $(<) : exe : $(2) : $(3) ; }
rule InstallDLL { Install $(<) : dll : $(2) : $(3) ; }
rule InstallFiles { Install $(<) : installFile : $(2) : $(3) ; }
rule BhbResources { Resources $(<) : $(>) ; }
rule BhbSearch { Search $(<) ; }