#
# /+\
# +\    Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
# \+/
  JAMBASEDATE = 2004.07.24 ;
#
# This file is part of Jam - see jam.c for Copyright information.
# 05/17/04 (dunbar)- Support for Siebel 
#
#
# JAMBASE - jam 2.5 ruleset providing make(1)-like functionality
#
# Special targets defined in this file:
#
# all           - parent of first, shell, files, lib, exe
# first         - first dependent of 'all', for potential initialization
# shell         - parent of all Shell targets
# files         - parent of all File targets
# lib           - parent of all Library targets
# exe           - parent of all Main targets
# dirs          - parent of all MkDir targets
# clean         - removes all Shell, File, Library, and Main targets
# uninstall     - removes all Install targets

# Rules and Actions defined by this file:
#
# Archive lib : source ;                archive library from compiled sources
# ArchiveFromObjects lib : objects ;    archive library from objects
# As obj.o : source.s ;                 .s -> .o
# Bulk dir : files ;                    populate directory with many files
# Cc obj.o : source.c ;                 .c -> .o
# C++ obj.o : source.cc ;               .cc -> .o
# Clean clean : sources ;               remove sources with 'jam clean'
# File dest : source ;                  copy file
# GenFile source.c : program args ;     make custom file
# HardLink target : source ;            make link from source to target
# HdrRule source : headers ;            handle #includes
# InstallInto dir : sources ;           install any files
# InstallBin dir : sources ;            install binaries
# InstallLib dir : sources ;            install files
# InstallFile dir : sources ;           install files
# InstallMan dir : sources ;            install man pages
# InstallShell dir : sources ;          install shell scripts
# Lex source.c : source.l ;             .l -> .c
# Library lib : source ;                shared library from compiled sources
# LibraryFromObjects lib : objects ;    shared library from objects
# LinkLibraries images : libraries ;    bag libraries onto Mains
# Main image : source ;                 link executable from compiled sources
# MainFromObjects image : objects ;     link executable from objects
# MkDir dir ;                           make a directory, if not there
# Object object : source ;              compile object from source
# ObjectCcFlags source : flags ;        add compiler flags for object
# ObjectC++Flags source : flags ;       add compiler flags for object
# ObjectDefines
# ObjectHdrs source : dirs ;            add include directories for object
# Objects sources ;                     compile sources
# Resource  xxx : yyy ;                 resource compiler
# RmTemps target : sources ;            remove temp sources after target made
# Setuid images ;                       mark executables Setuid
# Shell exe : source ;                  make a shell executable
# SoftLink target : source ;            make symlink from source to target
# SubDir TOP d1 d2 ... ;                start a subdirectory Jamfile
# SubDirCcFlags flags ;                 add compiler flags until next SubDir
# SubDirC++Flags flags ;                add compiler flags until next SubDir
# SubDirHdrs d1 d2 ... ;                add include dir until next SubDir
# SubInclude TOP d1 d2 ... ;            include a subdirectory Jamfile
# SubRules
# Undefines images : symbols ;          save undef's for linking
# UserObject object : source ;          handle unknown suffixes for Object
# Yacc source.c : source.y ;            .y -> .c

# Utility rules that have no side effects (not supported):
#
# FAppendSuffix f1 f2 ... : $(SUF) ;    return $(<) with suffixes
# Fdefines
# FDirName d1 d2 ... ;                  return path from root to dir
# FGrist d1 d2 ... ;                    return d1!d2!...
# FGristFiles value ;                   return $(value:G=$(SOURCE_GRIST))
# FGristSourceFiles value ;             return $(value:G=$(SOURCE_GRIST))
# FStripCommon v1 : v2 ;                strip common initial parts of v1 v2
# FSubDirPath
# FReverse a1 a2 ... ;                  return ... a2 a1
# FRelPath d1 : d2 ;                    return rel path from d1 to d2
# FSubDir d1 d2 ... ;                   return path to root
# FDefines
# FIncludes
# FQuote

# Brief review of the jam language:
#
# Statements:
#       rule RULE - statements to process a rule
#       actions RULE - system commands to carry out target update
#
# Modifiers on actions:
#       together - multiple instances of same rule on target get executed
#                  once with their sources ($(>)) concatenated
#       updated - refers to updated sources ($(>)) only
#       ignore - ignore return status of command
#       quietly - don't trace its execution unless verbose
#       piecemeal - iterate command each time with a small subset of $(>)
#       existing - refers to currently existing sources ($(>)) only
#       bind vars - subject to binding before expanding in actions
#
# Special rules:
#       Always - always build a target
#       Depends - builds the dependency graph
#       Echo - blurt out targets on stdout
#       Exit - blurt out targets and exit
#       Includes - marks sources as headers for target (a codependency)
#       NoCare - don't panic if the target can't be built
#       NoUpdate - create the target if needed but never update it
#       NotFile - ignore the timestamp of the target (it's not a file)
#       Temporary - target need not be present if sources haven't changed
#
# Special variables set by jam:
#       $(<) - targets of a rule (to the left of the :)
#       $(>) - sources of a rule (to the right of the :)
#       $(xxx) - true on xxx (UNIX, VMS, NT, OS2, MAC)
#       $(OS) - name of OS - varies wildly
#       $(JAMVERSION) - version number (2.5)
#
# Special variables used by jam:
#       SEARCH  - where to find something (used during binding and actions)
#       LOCATE  - where to plop something not found with SEARCH
#       HDRRULE - rule to call to handle include files
#       HDRSCAN - egrep regex to extract include files
#
# Special targets:
#       all - default if none given on command line
#
# Initialize variables
#
# OS specific variable settings
#
if $(NT) {
        MV              ?= move /y ;
        CP              ?= xcopy ;
        RM              ?= del /f/q ;
        RMDIR           ?= rmdir /s/q ;
        SLASH           ?= \\ ;
        SUFDLL          ?= .dll ;
        SUFLIB          ?= .lib ;
        SUFOBJ          ?= .obj ;
        SUFEXE          ?= .exe ;
     if $(MSVCDIR) { # Visual C++ 6.0 uses MSVCDIR
        AR              ?= lib ;
        AS              ?= masm386 ;
        CC              ?= $(MSVCDIR)\\bin\\cl /nologo ;             
        CCFLAGS         ?= "" ;
        C++             ?= $(CC) ;
        C++FLAGS        ?= $(CCFLAGS) ;
        LIBDIR          ?= $(MSVCDIR)\\lib ;
        LIBFLAGS        ?= "" ;
        LINK            ?= $(MSVCDIR)\\bin\\link /nologo ;            
        LINKFLAGS       ?= "" ;
        LINKLIBS        ?= $(LIBDIR)\\kernel32.lib $(LIBDIR)\\oldnames.lib ;
        OPTIM           ?= "" ;
        RC              ?= rc ;
        STDHDRS         ?= $(MSVCDIR)\\include ;
        UNDEFFLAG       ?= "/u _" ;
    } else if $(DMCDIR) {
        CC              ?= $(DMCDIR)\\bin\\dmc.exe ;
        CCFLAGS         ?= "" ;
        C++             ?= $(CC) ;
        C++FLAGS        ?= $(CCFLAGS) ;
        LIBDIR          ?= $(DMCDIR)\\lib ;
        LIBFLAGS        ?= "" ;
        LINK            ?= $(DMCDIR)\\bin\\link /nologo ;
        LINKFLAGS       ?= "" ;
        LINKLIBS        ?= $(DMCDIR)\\lib\\kernel32.lib $(DMCDIR)\\lib\\oldnames.lib ;
        OPTIM           ?= "" ;
        RC              ?= "" ;
        STDHDRS         ?= $(DMCDIR)\\Include ;
        UNDEFFLAG       ?= "-u " ;
    } else {
        Echo set MSVCDIR=d:\\progra~1\\micros~1\\vc98 ;
        EXIT On NT, set MSVCDIR to the root of the Microsoft directories. ;
    }
} else if $(UNIX) {
    switch $(OS) {
    case AIX :
        CC              ?= xlc_r ;
        C++             ?= xlC_r ;
        LIBFLAGS        ?= "-qmkshrobj -qtwolink -G -bnoerok -bf" ;
    case HPUX :
        RANLIB          ?= "" ;
    case SOLARIS :
        CC              ?= /opt/SUNWspro/bin/cc ;
        C++             ?= /opt/SUNWspro/bin/CC ;
        RANLIB          ?= "" ;
        AR              ?= "/usr/ccs/bin/ar ru" ;
    }
    # UNIX defaults
    CCFLAGS         ?= ;
    C++FLAGS        ?= $(CCFLAGS) ;
    CHMOD           ?= chmod ;
    CHGRP           ?= chgrp ;
    CHOWN           ?= chown ;
    LEX             ?= lex ;
    LINKFLAGS       ?= $(CCFLAGS) ;
    LINKLIBS        ?= ;
    OPTIM           ?= -O ;
    RANLIB          ?= ranlib ;
    YACC            ?= yacc ;
    YACCGEN         ?= .c ;
    YACCFILES       ?= y.tab ;
    YACCFLAGS       ?= -d ;
    }
#
# General defaults; a lot like UNIX
#
    AR              ?= ar ru ;
    AS              ?= as ;
    ASFLAGS         ?= ;
    AWK             ?= awk ;
    BINDIR          ?= /usr/local/bin ;
    C++             ?= cc ;
    C++FLAGS        ?= ;
    CC              ?= cc ;
    CCFLAGS         ?= ;
    CP              ?= cp -f ;
    DOT             ?= . ;
    DOTDOT          ?= .. ;
    EXEFLAGS        ?= ;
    EXEMODE         ?= 755 ;
    FILEMODE        ?= 644 ;
    HDRS            ?= ;
    INSTALLGRIST    ?= installed ;
    JAMFILE         ?= Jamfile ;
    JAMRULES        ?= Jamrules ;
    LEX             ?= ;
    LIBDIR          ?= /usr/local/lib ;
    LINK            ?= $(C++) ;                         # ?? $(CC) Linking is compiler dependent.
    LINKFLAGS       ?= ;
    LINKLIBS        ?= ;
    LN              ?= ln ;
    MANDIR          ?= /usr/local/man ;
    MKDIR           ?= mkdir ;
    MV              ?= mv -f ;
    OPTIM           ?= ;
    OSFULL           = $(OS)$(OSVER)$(OSPLAT) ;
    RCP             ?= rcp ;
    RM              ?= rm -f ;
    RMDIR           ?= $(RM) ;
    RSH             ?= rsh ;
    SED             ?= sed ;
    SHELLHEADER     ?= "#!/bin/sh" ;
    SHELLMODE       ?= 755 ;
    SLASH           ?= / ;
    STDHDRS         ?= /usr/include ;
    SUBDIRRULES     ?= ;
    SUBDIRRESET     ?= ASFLAGS HDRS C++FLAGS CCFLAGS DEFINES ;    # There is no SUBDIRDEFINES ??
    SUFEXE          ?= "" ;
    SUFDLL          ?= .so ;                            # MS centric. Unix uses .so suffix
    SUFLIB          ?= .so ;                            # MS has .lib and .dll
    SUFOBJ          ?= .o ;
    UNDEFFLAG       ?= "-u _" ;
    YACC            ?= ;
    YACCGEN         ?= ;
    YACCFILES       ?= ;
    YACCFLAGS       ?= ;
# Caution: HDRPATTERN contains 3 <blank><tab>  char sequences.  Do not remove/expand tabs.
    HDRPATTERN = "^[ 	]*#[ 	]*include[ 	]*[<\"]([^\">]*)[\">].*$" ;
#   HDRPATTERN = "^[ T]*#[ T]*include[ T]*[<\"]([^\">]*)[\">].*$" ;  (tabs (\t) shown as "T"

# Base dependencies - first for "bootstrap" kinds of rules ;
NotFile all clean dirs exe files first lib obj shell uninstall ;
Depends all : exe lib files obj shell ;
Depends all   exe lib files obj shell : first ;
Always clean uninstall ;

#
# Rules
#

rule    Archive {
        ArchiveFromObjects $(<) : $(>:S=$(SUFOBJ)) ; # :Suffix
        Objects $(>) ;
        }
rule    ArchiveFromObjects {
        local _file _lib _src ;
        _src = [ FGristFiles $(>) ] ;              # Add grist to file names
        _lib = $(<:S=$(SUFLIB)) ;                  # Archive :Suffix
        if $(KEEPOBJS) { Depends obj : $(_src) ; # library depends on its member objects
        } else         { Depends lib : $(_lib) ; }
        if ! $(_lib:D) { MakeLocate $(_lib) $(_lib)($(_src:BS)) : $(LOCATE_TARGET) ; } # :Base/:Suffix/:Directory
        if $(NOARSCAN) {
            Depends $(_lib) : $(_src) ;
        } else {
            Depends $(_lib) : $(_lib)($(_src:BS)) ;   # :Base/:Suffix
            for _file in $(_src) {
                Depends $(_lib)($(_file:BS)) : $(_file) ;   # :Base/:Suffix
                }
            }
        Clean clean : $(_lib) ;
        FArchive $(_lib) : $(_src) ;
        if $(RANLIB) { Ranlib $(_lib) ; }
        if ! ( $(NOARSCAN) || $(NOARUPDATE) ) { RmTemps $(_lib) : $(_src) ; }
        }
actions updated together piecemeal FArchive { $(AR) $(<) $(>) }
actions together Ranlib { $(RANLIB) $(<) }
rule    As {
        Depends $(<) : $(>) ;
        ASFLAGS on $(<) += $(ASFLAGS) $(SUBDIRASFLAGS) ;
        ASHDRS on $(<) = [ FIncludes $(SEARCH_SOURCE) $(SUBDIRHDRS) $(HDRS) ] ;
        }
actions As       { $(AS) $(ASFLAGS) $(ASHDRS) -o $(<) $(>) }
rule    Bulk {
        local _file ;
        for _file in $(>) {
            File $(_file:D=$(<)) : $(_file) ;            # :Directory
            }
        }
rule    Cc {
        Depends $(<) : $(>) ;
        # Just to clarify here: this sets the per-target CCFLAGS to
        # be the current value of (global) CCFLAGS and SUBDIRCCFLAGS.
        # CCHDRS and CCDEFS must be reformatted each time for some
        # compiles (NT) that malign multiple -D or -I flags.
        CCFLAGS on $(<) += $(CCFLAGS) $(SUBDIRCCFLAGS) $(OPTIM) ;
        CCHDRS  on $(<) = [ on $(<) FIncludes $(HDRS) ] ;
        CCDEFS  on $(<) = [ on $(<) FDefines  $(DEFINES) ] ;
        }
actions Cc       { $(CC)  $(CCFLAGS)  $(CCDEFS) $(CCHDRS) $(>) -c -o $(<) }
rule    C++ {
        Depends $(<) : $(>) ;
        C++FLAGS on $(<) += $(C++FLAGS) $(SUBDIRC++FLAGS) $(OPTIM) ;
        CCHDRS   on $(<) = [ on $(<) FIncludes $(HDRS) ] ;
        CCDEFS   on $(<) = [ on $(<) FDefines  $(DEFINES) ] ;
        }
actions C++      { $(C++) $(C++FLAGS) $(CCDEFS) $(CCHDRS) $(>) -c -o $(<) }
rule    C++Flags { C++FLAGS += $(<) ; }
actions Chgrp    { $(CHGRP) $(GROUP) $(<) }
rule    Chmod    { if $(CHMOD) { Chmod1 $(<) ; } }
actions Chmod1   { $(CHMOD) $(MODE) $(<) }
actions Chown    { $(CHOWN) $(OWNER) $(<) }
actions piecemeal together existing Clean { $(RM) $(>) }  # ??
rule    Defines { DEFINES += $(<) ; }
rule    File {
        Depends files : $(<) ;
        Depends $(<) : $(>) ;
        SEARCH on $(>) = $(SEARCH_SOURCE) ;
        MODE   on $(<) = $(FILEMODE) ;
        Chmod $(<) ;
        }
actions File     { $(CP) "$(>)" $(<) }                       
rule    GenFile {
        local _tgt = [ FGristSourceFiles $(<) ] ;
        local _src = [ FAppendSuffix $(>[1]) : $(SUFEXE) ] ;
        Depends  $(_tgt) : $(_src) $(>[2-]) ;
        GenFile1 $(_tgt) : $(_src) $(>[2-]) ;
        Clean clean : $(_tgt) ;
        }
rule    GenFile1 {
        MakeLocate $(<) : $(LOCATE_SOURCE) ;
        SEARCH on  $(>) = $(SEARCH_SOURCE) ;
        }
actions GenFile1 { PATH="$PATH:." $(>[1]) $(<) $(>[2-]) }
rule    HardLink {
        Depends files : $(<) ;
        Depends $(<) : $(>) ;
        SEARCH on $(>) = $(SEARCH_SOURCE) ;
        }
actions HardLink { $(RM) $(<) && $(LN) $(>) $(<) }
rule    HdrRule {            # HdrRule source : headers ;
        # 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 _hdr = $(>:G=$(HDRGRIST:E)) ;               # :Grist/:Value
        Includes $(<) : $(_hdr) ;
        SEARCH on $(_hdr) = $(HDRSEARCH) ;
        NoCare $(_hdr) ;
        # Propagate on $(<) to $(>)
        HDRSEARCH on $(_hdr) = $(HDRSEARCH) ;
        HDRSCAN   on $(_hdr) = $(HDRSCAN) ;
        HDRRULE   on $(_hdr) = $(HDRRULE) ;
        HDRGRIST  on $(_hdr) = $(HDRGRIST) ;
        }
actions Install  { $(CP) $(>) $(<) }
rule    InstallInto {            # InstallInto dir : sources ;
        local _src _sfile _tfile ;
        _src = $(>:G=$(INSTALLGRIST)) ;                   # :Grist
        # Arrange for jam install
        # Arrange for jam uninstall
        # sources are in SEARCH_SOURCE
        # targets are in dir
        Depends install : $(_src) ;
        Clean uninstall : $(_src) ;
        SEARCH on $(>) = $(SEARCH_SOURCE) ;
        MakeLocate $(_src) : $(<) ;
        # For each source, make gristed target name
        # and Install, Chmod, Chown, and Chgrp
        for _sfile in $(>) {
            _tfile = $(_sfile:G=$(INSTALLGRIST)) ;        # :Grist
            Depends $(_tfile) : $(_sfile) ;
            Install $(_tfile) : $(_sfile) ;
            Chmod $(_tfile) ;
            if $(OWNER) && $(CHOWN) {
                Chown    $(_tfile) ;
                OWNER on $(_tfile) = $(OWNER) ;
                }
            if $(GROUP) && $(CHGRP) {
                Chgrp    $(_tfile) ;
                GROUP on $(_tfile) = $(GROUP) ;
                }
            }
        }
rule    InstallBin {
        local _tgt = [ FAppendSuffix $(>) : $(SUFEXE) ] ;
        InstallInto $(<) : $(_tgt) ;
        MODE on $(_tgt:G=$(INSTALLGRIST)) = $(EXEMODE) ; # :Grist
        }
rule    InstallFile {
        InstallInto $(<) : $(>) ;
        MODE on $(>:G=$(INSTALLGRIST)) = $(FILEMODE) ; # :Grist
        }
rule    InstallLib {
        InstallInto $(<) : $(>) ;
        MODE on $(>:G=$(INSTALLGRIST)) = $(FILEMODE) ; # :Grist
        }
rule    InstallMan {       # This just strips the . from the suffix
        local _file _suf _dir ;
        for _file in $(>) {
            switch $(_file:S) {                   # :Suffix
              case .1 : _suf = 1 ; case .2 : _suf = 2 ; case .3 : _suf = 3 ;
              case .4 : _suf = 4 ; case .5 : _suf = 5 ; case .6 : _suf = 6 ;
              case .7 : _suf = 7 ; case .8 : _suf = 8 ; case .l : _suf = l ;
              case .n : _suf = n ; case .man : _suf = 1 ;
              }
            _dir = man$(_suf) ;
            InstallInto $(_dir:R=$(<)) : $(_file) ;                   # :Root
            }
        MODE on $(>:G=$(INSTALLGRIST)) = $(FILEMODE) ; # :Grist
        }
rule    InstallShell {
        InstallInto $(<) : $(>) ;
        MODE on $(>:G=$(INSTALLGRIST)) = $(SHELLMODE) ; # :Grist
        }
rule    Lex {
        LexMv   $(<) : $(>) ;
        Depends $(<) : $(>) ;
        MakeLocate $(<) : $(LOCATE_SOURCE) ;
        Clean clean : $(<) ;
        }
actions Lex      { $(LEX) $(>) }
actions LexMv    { $(MV) lex.yy.c $(<) }
rule    Library {
        LibraryFromObjects $(<) : $(>:S=$(SUFOBJ)) ; # :Suffix
        Objects $(>) ;
        LINKFLAGS += $(LIBFLAGS) ;
        }
# AIX example
#     xlC_r -G -qmkshrobj -g  shared.o -o libshared1.so -ldl
# Note: -G is combo flag for: erok, rtl, nortllib, nosymbolic, noautoexp, and M:SRE

rule    LibraryFromObjects {
        local _loc _src _lib _dll _file ;      # _src: sources
        _src   = [ FGristFiles $(>) ] ;        # Add grist to file names
        _lib = $(<:S=$(SUFLIB)) ;              # Library :Suffix  (.dll on windows, .so on unix)
        _dll = $(<:S=$(SUFDLL)) ;              # Library :Suffix  (.lib on windows, .so / .a on unix)
        if $(KEEPOBJS) { Depends obj : $(_src) ; # library depends on its member objects
        } else         { Depends lib : $(_lib) ; }
        # Set LOCATE for the library and its contents.  The bound
        # value shows up as $(NEEDLIBS) on the Link actions.
        # For compatibility, we only do this if the library doesn't already have a path.
        if ! $(_lib:D) {
             _loc = [ FDirName $(LOCATE_TARGET) ] ;
             MakeLocate $(_lib) $(_lib)($(_src:BS)) : $(_loc) ;
             } # :Base/:Suffix/:Directory
        Depends $(_lib) : $(_src) ;
        Depends $(_lib) : $(_lib)($(_src:BS)) ;
        for _file in $(_src) {
            Depends $(_lib)($(_file:BS)) : $(_file) ;
            }
        Clean clean : $(_lib) ;
        Link    $(_lib) : $(_src) ;
#       RmTemps $(_lib) : $(_src) ;      # Breaks incremental builds on win32 (probably AIX too)
        }
rule    LibFlags { LIBFLAGS += $(<) ; }
rule    Libs {
        # make library dependencies of target
        # set NEEDLIBS variable used by 'actions Main' / 'actions Library'
        local _exe = [ FAppendSuffix $(<) : $(SUFEXE) ] ;
        Depends     $(_exe) :  $(>:S=$(SUFLIB)) ;   # :Suffix
        NEEDLIBS on $(_exe) += $(>:S=$(SUFLIB)) ;   # :Suffix
        }
rule    Link {
        MODE on $(<) = $(EXEMODE) ;
        Chmod   $(<) ;
        }
actions Link bind NEEDLIBS { $(LINK) $(LINKFLAGS) -o $(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS) }
rule    LinkFlags { LINKFLAGS += $(<) ; }
rule    Main {
        LINKFLAGS += $(LIBFLAGS) ;                              # Siebel
        MainFromObjects $(<) : $(>:S=$(SUFOBJ)) ; # :Suffix
        Objects $(>) ;
        }
rule    MainFromObjects {
        local _src _tgt _loc _i ;
        # Add grist to file names
        # Add suffix to exe
        _src = [ FGristFiles $(>) ] ;
        _tgt = [ FAppendSuffix $(<) : $(SUFEXE) ] ;
        # so 'jam foo' works when it's really foo.exe
        if $(_tgt) != $(<) {
            Depends $(<) : $(_tgt) ;
            NotFile $(<) ;
            }
        # make compiled sources a dependency of target
        if ! $(_tgt:D) {                                      
           _loc = [ FDirName $(LOCATE_TARGET) ] ;
           MakeLocate $(_tgt) $(_tgt)($(_src:BS)) : $(_loc) ;
           }   # :Base/:Suffix/:Directory
        Depends exe : $(_tgt) ;
        Depends $(_tgt) : $(_src) ;
        Depends $(_tgt) : $(_tgt)($(_src:BS)) ;               
        for _i in $(_src) {                                   # Why? Difference from line above??
            Depends $(_tgt)($(_i:BS)) : $(i) ;
            }
        MakeLocate $(_tgt) : $(LOCATE_TARGET) ;               # Link2 Windows(no effect) AIX(needed) ??
        Clean clean   : $(_tgt) ;
        Link2 $(_tgt) : $(_src) ;
        }
rule    MakeLocate {           # MakeLocate targets : directory ;
        # Sets special variable LOCATE on targets, and arranges
        # with MkDir to create target directory.
        # Note we grist the directory name with 'dir',
        # so that directory path components and other
        # targets don't conflict.
        if $(>) {
            LOCATE on $(<) = $(>) ;
            Depends $(<) : $(>[1]:G=dir) ;             # :Grist
            MkDir $(>[1]:G=dir) ;                      # :Grist
            }
        }
rule    MkDir {                     # MkDir directory ;
        # Make a directory and all its parent directories.
        # Ignore timestamps on directories: we only care if they
        # exist.
        NoUpdate $(<) ;
        # Don't create . or any directory already created.
        if $(<:G=) != $(DOT) && ! $($(<)-mkdir) {      # :Grist
            # Cheesy gate to prevent multiple invocations on same dir
            # Arrange for jam dirs
            # MkDir1 has the actions
            $(<)-mkdir = true ;
            Depends dirs : $(<) ;
            MkDir1 $(<) ;
            # Recursively make parent directories.               #Siebel: Why not use mkdir -p 
            # $(<:P) = $(<)'s parent, & we recurse until root
            local _parent = $(<:P) ;              # :Parent
            # Don't try to create A: or A:\ on windows
            if $(NT) {
                switch $(_parent) {
                  case *:   : _parent = ;
                  case *:\\ : _parent = ;
                  }
                }
            if $(_parent) = $(<) {
                # The parent is the same as the dir.
                # We're at the root, which some OS's can't stat, so we mark
                # it as NotFile.
                NotFile $(_parent) ;
            } else if $(_parent:G=) {                        # :Grist
                # There's a parent; recurse.
                Depends $(<) : $(_parent) ;
                MkDir $(_parent) ;
                }
            }
        }
actions MkDir1   { $(MKDIR) $(<) }
rule    Object {
        # locate object and search for source, if wanted
        local _loc ;                              
        Clean clean : $(<) ;
        _loc = [ FDirName $(LOCATE_TARGET) ] ;    
        MakeLocate $(<) : $(_loc) ;               # Siebel Solve Src/foo.cpp windows directory structure
        SEARCH on $(>)  = $(SEARCH_SOURCE) ;
        # Save HDRS for -I$(HDRS) on compile.
        # We shouldn't need -I$(SEARCH_SOURCE) as cc can find headers
        # in the .c file's directory, but generated .c files (from
        # yacc, lex, etc) are located in $(LOCATE_TARGET), possibly
        # different from $(SEARCH_SOURCE).
        HDRS on $(<) = $(SEARCH_SOURCE) $(SUBDIRHDRS) $(HDRS) ;
        # 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.
        # $(SEARCH_SOURCE:E) is where cc first looks for #include
        # "foo.h" files.  If the source file is in a distant directory,
        # look there.  Else, look in "" (the current directory).
        HDRRULE   on $(>) = HdrRule ;
        HDRSCAN   on $(>) = $(HDRPATTERN) ;
        HDRSEARCH on $(>) = $(SEARCH_SOURCE:E) $(SUBDIRHDRS) $(HDRS) $(STDHDRS) ;  # :E value
        HDRGRIST  on $(>) = $(HDRGRIST) ;
        # propagate target specific-defines
        DEFINES on $(<) += $(DEFINES) ;
        # if source is not .c, generate .c with specific rule
        switch $(>:S) {                         # :Suffix
            case .asm : As  $(<) : $(>) ;
            case .c :   Cc  $(<) : $(>) ;
            case .C :   C++ $(<) : $(>) ;
            case .cc :  C++ $(<) : $(>) ;
            case .cpp : C++ $(<) : $(>) ;
            case .l :   Cc  $(<) : $(<:S=.c) ;  # :Suffix
                        Lex $(<:S=.c) : $(>) ;  # :Suffix
            case .s :   As  $(<) : $(>) ;
            case .y :   Cc  $(<) : $(<:S=$(YACCGEN)) ;  # :Suffix
                        Yacc $(<:S=$(YACCGEN)) : $(>) ; # :Suffix
            case * :    UserObject $(<) : $(>) ;
            }
        }
rule    ObjectCcFlags  { CCFLAGS  on [ FGristFiles $(<:S=$(SUFOBJ)) ] += $(>) ; }     # :Suffix
rule    ObjectC++Flags { C++FLAGS on [ FGristFiles $(<:S=$(SUFOBJ)) ] += $(>) ; }     # :Suffix
rule    ObjectDefines  {   # reformat CCDEFS according to current defines
        local _src = [ FGristFiles $(<:S=$(SUFOBJ)) ] ;  # :Suffix
        DEFINES on $(_src) += $(>) ;
        CCDEFS  on $(_src)  = [ on $(_src) FDefines $(DEFINES) ] ;
        }
rule    ObjectHdrs {
        # Add to HDRS for HdrScan's benefit.
        # must reformat CCHDRS according to headers
        local _obj = [ FGristFiles $(<:S=$(SUFOBJ)) ] ;  # :Suffix
        HDRS on $(_obj) += $(>) ;
        CCHDRS on $(_obj) = [ on $(_obj) FIncludes $(HDRS) ] ;
        }
rule    Objects {
        local _obj ;
        for _obj in [ FGristFiles $(<) ] {
                Object $(_obj:S=$(SUFOBJ)) : $(_obj) ;  # :Suffix
                Depends obj : $(_obj:S=$(SUFOBJ)) ;     # :Suffix
                }
        }
rule    Resource  {
        local _src = [ FGristFiles $(>) ] ;
        local _res = $(_src:S=.res) ;
        local _exe = [ FAppendSuffix $(<) : $(SUFEXE) ] ;
        Depends $(_exe) : $(_res) ;
        Depends $(_res) : $(_src) ;
        LOCATE    on $(_res)  = $(LOCATE_TARGET) ;
        SEARCH    on $(_src)  = $(SEARCH_SOURCE) ;
        NEEDLIBS  on $(_exe) += $(_res) ;
        HDRS      on $(_res)  = $(HDRS) $(SEARCH_SOURCE) $(SUBDIRHDRS) ;
        HDRRULE   on $(_src)  = HdrRule ;
        HDRSCAN   on $(_src)  = $(HDRPATTERN) ;
        HDRSEARCH on $(_src)  = $(SEARCH_SOURCE) $(SUBDIRHDRS) ;
        HDRGRIST  on $(_src)  = $(HDRGRIST) ;
        Rc $(_res) : $(_src) ;
        Clean clean : $(<) ;
        }
actions Rc       { $(RC) $(RCFLAGS) /I$(HDRS) /I$(RCHDRS) /Fo $(<) $(>) }
rule    RmTemps { Temporary $(>) ; }       
actions quietly updated piecemeal together RmTemps { $(RM) $(>) }
rule    Setuid  { MODE on [ FAppendSuffix $(<) : $(SUFEXE) ] = 4711 ; }
rule    Shell   {
        Depends shell : $(<) ;
        Depends $(<) : $(>) ;
        SEARCH on $(>) = $(SEARCH_SOURCE) ;
        MODE   on $(<) = $(SHELLMODE) ;
        Clean clean : $(<) ;
        Chmod $(<) ;
        }
actions Shell    {
        $(AWK) '
                NR == 1 { print "$(SHELLHEADER)" }
                NR == 1 && /^[#:]/ { next }
                /^##/ { next }
                { print }
        ' < $(>) > $(<)
        }
rule    SoftLink {
        Depends files : $(<) ;
        Depends $(<)  : $(>) ;
        SEARCH on $(>) = $(SEARCH_SOURCE) ;
        Clean clean : $(<) ;
        }
actions SoftLink { $(RM) $(<) && $(LN) -s $(>) $(<) }
rule    SubDir {              # SubDir TOP d1 d2 ... ;
        # Support for a project tree spanning multiple directories.
        #
        # SubDir declares a Jamfile's location in a project tree, setting
        # Jambase variables (SEARCH_SOURCE, LOCATE_TARGET) so that source
        # files can be found.
        #
        # TOP is a user-select variable name for root of the tree, and
        # d1 d2 ...  are the directory elements that lead from the root
        # of the tree to the directory of the Jamfile.
        #
        # TOP can be set externally, but normally the first SubDir call
        # computes TOP as the path up from the current directory; the
        # path contains one ../ for each of d1 d2 ...
        #
        # SubDir reads once the project-specific rules file Jamrules
        # in the TOP directory, if present.  This can be overridden
        # with the variable TOPRULES.
        #
        # SubDir supports multiple, overlaid project trees:  SubDir
        # invocations with different TOPs can appear in the same Jamfile.
        # The location established by the first SubDir call is used set
        # the TOPs for the subsequent SubDir calls.
        #
        # SubDir's public variables:
        #
        #       $(TOP) = path from CWD to root.
        #       $(SUBDIR) = path from CWD to the directory SubDir names.
        #       $(SUBDIR_TOKENS) = path from $(TOP) to $(SUBDIR) as dir names
        #       $(SEARCH_SOURCE) = $(SUBDIR)
        #       $(LOCATE_SOURCE) = $(ALL_LOCATE_TARGET) $(SUBDIR)
        #       $(LOCATE_TARGET) = $(ALL_LOCATE_TARGET) $(SUBDIR)
        #       $(SOURCE_GRIST) = $(SUBDIR_TOKENS) with !'s
        #
        local _top    = $(<[1]) ;
        local _tokens = $(<[2-]) ;
        #
        # First time through sets up relative root and includes Jamrules.
        #
        if ! $(_top) { Exit SubDir syntax error ; }
        if ! $($(_top)-SET) {
            $(_top)-SET = true ;       # First time we've seen this TOP.
            # We'll initialize a number of internal variables:
            #
            #   $(TOP-UP) = directories from ROOT to a common point
            #   $(TOP-DOWN) = directories from common point to TOP
            #   $(TOP-ROOT) = root directory for UP/DOWN -- normally CWD
            #   $(SUBDIR_UP) = current value of $(TOP-UP)
            #   $(SUBDIR_DOWN) = current value of $(TOP-DOWN)
            #   $(SUBDIR_ROOT) = current value of $(TOP-ROOT)
            #
            if $($(_top)) {
                # TOP externally set.
                # We'll ignore the relative (UP/DOWN) path that
                # got us here, and instead remember the hard ROOT.
                $(_top)-UP = ;
                $(_top)-DOWN = ;
                $(_top)-ROOT = $($(_top)) ;
            } else {                   # TOP not preset.
                # Establishing a new TOP.  In the simplest case,
                # (SUBDIR_UP/SUBDIR_DOWN/SUBDIR_ROOT unset), it's
                # merely a certain number of directories down from
                # the current directory, and FSubDirPath will set
                # TOP to a path consisting of ../ for each of the
                # elements of _tokens, because that represents how
                # far below TOP the current directory sits.
                #
                # In the more complicated case, the starting directory
                # isn't the directory of jam's invocation but an
                # location established by previous SubDir call.  The
                # starting directory is SUBDIR_UP directories up from
                # SUBDIR_ROOT, and then SUBDIR_DOWN directories down
                # from that.   If SUBDIR_ROOT is not set, that means
                # SUBDIR_DOWN and SUBDIR_UP represent the path from
                # the directory of jam's invocation.
                #
                # In the most complicated case, the _tokens also
                # represents directories down, because TOP is being
                # estalished in a directory other than TOP's root.
                # Hopefully, _tokens and SUBDIR_DOWN represent the
                # same final directory, relative to the new TOP and
                # the previous SubDIr's TOP.  To find the new TOP,
                # we have to chop off any common directories from
                # then ends of _tokens and SUBDIR_DOWN.  To do so,
                # we reverse each of them, call FStripCommon to
                # remove the initial common elements, and then
                # reverse them again.  After this process, if
                # both _tokens and SUBDIR_DOWN have elements, it
                # means the directory names estalished by the two
                # SubDir calls don't match, and a warning is issued.
                # All hell will likely break loose at this point,
                # since the whole SubDir scheme relies on the SubDir
                # calls accurately naming the current directory.
                # Strip common trailing elements of _tokens and SUBDIR_DOWN.
                _tokens = [ FReverse $(_tokens) ] ;
                SUBDIR_DOWN = [ FReverse $(SUBDIR_DOWN) ] ;
                FStripCommon _tokens : SUBDIR_DOWN ;
                SUBDIR_DOWN = [ FReverse $(SUBDIR_DOWN) ] ;
                _tokens = [ FReverse $(_tokens) ] ;
                if $(SUBDIR_DOWN) && $(_tokens) { Echo Warning: SubDir $(<) misplaced! ; }
                # We'll remember the relative (UP/DOWN) path that
                # got us here, plus any hard ROOT starting point
                # for the UP/DOWN.  If TOP is never set externally,
                # ROOT will always be "" (directory of jam's invocation).
                $(_top)-UP = $(SUBDIR_UP) $(_tokens) ;
                $(_top)-DOWN = $(SUBDIR_DOWN) ;
                $(_top)-ROOT = $(SUBDIR_ROOT:E="") ;                               # :E value
                $(_top) = [ FSubDirPath $(_top) ] ;
                }
            # Set subdir vars for the inclusion of the Jamrules,
            # just in case they have SubDir rules of their own.
            # Note that SUBDIR_DOWN is empty: it's all the way
            # up where the Jamrules live.  These gets overrided
            # just after the inclusion.
            SUBDIR_UP   = $($(_top)-UP) ;
            SUBDIR_DOWN = ;
            SUBDIR_ROOT = $($(_top)-ROOT) ;
            # Include $(TOPRULES) or $(TOP)/Jamrules.
            # Include $(TOPRULES) if set.
            # Otherwise include $(TOP)/Jamrules if present.
            if $($(_top)RULES) {
                include $($(_top)RULES) ;
            } else {
                NoCare  $(JAMRULES:R=$($(_top)):G=$(_top)) ;   # :Root/:Grist
                include $(JAMRULES:R=$($(_top)):G=$(_top)) ;   # :Root/:Grist
                }
           }
        # Get path from $(TOP) to named directory.
        # Save dir tokens for other potential uses.
        SUBDIR_UP     = $($(_top)-UP) ;
        SUBDIR_DOWN   = $($(_top)-DOWN) $(_tokens) ;
        SUBDIR_ROOT   = $($(_top)-ROOT) ;
        SUBDIR_TOKENS = $(SUBDIR_DOWN) ;
        SUBDIR = [ FSubDirPath $(<) ] ;
        # 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 = $(ALL_LOCATE_TARGET) $(SUBDIR) ;
        SOURCE_GRIST  = [ FGrist $(SUBDIR_TOKENS) ] ;
        # Reset per-directory ccflags, hdrs, etc,
        # listed in SUBDIRRESET.
        # Note use of variable expanded assignment var
        SUBDIR$(SUBDIRRESET) = ;
        # Invoke user-specific SubDir extensions,
        # rule names listed in SUBDIRRULES.
        # Note use of variable expanded rule invocation
        $(SUBDIRRULES) $(<) ;
        }
rule    SubDirCcFlags  { SUBDIRCCFLAGS  += $(<) ; }
rule    SubDirC++Flags { SUBDIRC++FLAGS += $(<) ; }
rule    SubDirDefines  { SUBDIRC++FLAGS += [ FDefines $(<) ] ; }
rule    SubDirHdrs     { SUBDIRHDRS += [ FDirName $(<) ] ; }
rule    SubInclude {                # SubInclude TOP d1 ... ;
        # Include a subdirectory's Jamfile.
        # We use SubDir to get there, in case the included Jamfile
        # either doesn't have its own SubDir (naughty) or is a subtree
        # with its own TOP.
        if ! $($(<[1])) { Exit SubInclude $(<[1]) without prior SubDir $(<[1]) ; }
        SubDir  $(<) ;
        include $(JAMFILE:D=$(SUBDIR)) ;                             # :Directory
        }
rule    SubRules {                  # SubRules TOP d1 ... : Other-TOP ;
        #
        # Read another tree's Jamrules, by giving it's path according
        # to this tree and it's own name.
        if ! $($(<[1])) { Exit SubRules $(<[1]) without prior SubDir $(<[1]) ; }
        SubDir $(<) ;
        SubDir $(>) ;
        }
rule    Undefines { UNDEFS on [ FAppendSuffix $(<) : $(SUFEXE) ] += $(UNDEFFLAG)$(>) ; }
rule    UserObject { Exit "Unknown suffix on" $(>) "- see UserObject rule in Jamfile(5)." ; }
rule    Yacc {
        local _hdr ;
        _hdr = $(<:BS=.h) ;    # :Base/:Suffix
        MakeLocate $(<) $(_hdr) : $(LOCATE_SOURCE) ; # Some places don't have yacc.
        if $(YACC) {
            Depends $(<) $(_hdr) : $(>) ;
            Yacc1 $(<) $(_hdr) : $(>) ;
            YaccMv $(<) $(_hdr) : $(>) ;
            Clean clean : $(<) $(_hdr) ;
            }
        # make sure someone includes $(_hdr) else it will be
        # a deadly independent target
        Includes $(<) : $(_hdr) ;
        }
actions Yacc1    { $(YACC) $(YACCFLAGS) $(>) }
actions YaccMv   {
        $(MV) $(YACCFILES).c $(<[1])
        $(MV) $(YACCFILES).h $(<[2])
        }
#
# Utility rules; no side effects on these
#
rule    FAppendSuffix {    # "FAppendSuffix yacc lex foo.bat : $(SUFEXE) ;"
       # returns (yacc,lex,foo.bat) on Unix and
       # (yacc.exe,lex.exe,foo.bat) on NT.
        local _file _out ;
        if $(>) {
            for _file in $(<) {
                if $(_file:S) { _out += $(_file) ;          # :Suffix
                } else        { _out += $(_file:S=$(>)) ;   # :Suffix
                }
            }
            return $(_out) ;
        } else { return $(<) ; }
        }
rule    FDefines  { return -D$(<) ; }
rule    FDirName  {
        # Turn individual elements in $(<) into a usable path.
        local _dir ;
        local _path = $(DOT) ;
        for _dir in $(<) { _path = $(_dir:R=$(_path)) ; }       # :Root
        return $(_path) ;
        }
rule    FGrist      { return $(<:J=!) ; }        # :Join
rule    FGristFiles { return $(<:G=$(SOURCE_GRIST:E)) ; }   # :Grist # :E value
rule    FGristSourceFiles {
        # Produce source file name with grist in it,
        # if SOURCE_GRIST is set.
        # Leave header files alone, because they have a global visibility.
        if ! $(SOURCE_GRIST) { return $(<) ;
        } else {
            local _src _gsrc ;
            for _src in $(<) {
                switch $(_src) {
                  case *.h : _gsrc += $(_src) ;
                  case *   : _gsrc += $(_src:G=$(SOURCE_GRIST)) ; # :Grist
                  }
                }
            return $(_gsrc) ;
            }
        }
rule    FIncludes { return -I$(<) ; }
rule    FRelPath {
        local _tgt _src ;       # first strip off common parts
        _tgt = $(<) ;
        _src = $(>) ;
        FStripCommon _tgt : _src ;
        _tgt = [ FSubDir  $(_tgt) ] ;   # now make path to root and path down
        _src = [ FDirName $(_src) ] ;
        # Concatenate and save
        if $(_src) = $(DOT) { return $(_tgt) ;
        } else              { return $(_src:R=$(_tgt)) ; }           # :Root
        }
rule    FReverse {               # FReverse a1 a2 a3 ... ;
        # return ... a3 a2 a1 ;
        if $(1) { return [ FReverse $(1[2-]) ] $(1[1]) ; }
        }
rule    FSubDir {
        # If $(>) is the path to the current directory, compute the
        # path (using ../../ etc) back to that root directory.
        # Sets result in $(<)
        if ! $(<[1]) { return $(DOT) ;
        } else {
            local _dir _path ;
            _path = $(DOTDOT) ;
            for _dir in $(<[2-]) { _path = $(_path:R=$(DOTDOT)) ; }    # :Root
            return $(_path) ;
            }
        }
rule    FSubDirPath {             # FSubDirPath TOP d1 ... ;
        # Returns path to named directory.
        # If jam is invoked in a subdirectory of the TOP, then we
        # need to prepend a ../ for every level we must climb up
        # (TOP-UP), and then append the directory names we must
        # climb down (TOP-DOWN), plus the named directories d1 ...
        # If TOP was set externally, or computed from another TOP
        # that was, we'll have to reroot the whole thing at TOP-ROOT.
        local _path = [ FRelPath $($(<[1])-UP) : $($(<[1])-DOWN) $(<[2-]) ] ;
        return $(_path:R=$($(<[1])-ROOT)) ;                       # :Root
        }
rule    FStripCommon {          # FStripCommon v1 : v2 ;
        # Strip common initial elements of variables v1 and v2.
        # Modifies the variable values themselves.
        if $($(<)[1]) && $($(<)[1]) = $($(>)[1]) {
            $(<) = $($(<)[2-]) ;
            $(>) = $($(>)[2-]) ;
            FStripCommon $(<) : $(>) ;
            }
        }
rule    FQuote    { return \\\"$(<)\\\" ; }

if $(MSVCDIR) {                             # NT specific actions
   rule    FDefines  { return /D$(<) ; }
   actions GenFile1 { $(>[1]) $(<) $(>[2-]) }
   rule    FIncludes { return /I$(<) ; }
   actions updated together piecemeal FArchive {
      if exist $(<) set _$(<:B)_= $(<) ; else set _$<:B) = ;
      $(AR) /out:$(<) %_$(<:B)_% $(>)
      }
   actions As  { $(AS)  /Ml /p /v /w2 $(>) $(<) ,nul,nul }
   actions Cc  { $(CC)  $(CCFLAGS)  $(CCDEFS) $(CCHDRS) /I$(STDHDRS)    $(>) /c /Fo".\\$(<:D)\\" /Fd".\\$(<:D)\\" }
   actions C++ { $(C++) $(C++FLAGS) $(CCDEFS) $(CCHDRS) /I$(STDHDRS) /Tp$(>) /c /Fo".\\$(<:D)\\" /Fd".\\$(<:D)\\" }
   actions Link  bind NEEDLIBS { $(LINK) /subsystem:windows /dll $(LINKFLAGS) $(UNDEFS) $(>) /libpath:$(LIBDIR) $(NEEDLIBS) $(LINKLIBS) /out:$(<:S=.dll) /implib:$(<:S=.lib) /pdb:$(<:S=.pdb) }
   actions Link2 bind NEEDLIBS { $(LINK) /subsystem:console      $(LINKFLAGS) $(UNDEFS) $(>) /libpath:$(LIBDIR) $(NEEDLIBS) $(LINKLIBS) /out:$(<:S=.exe) /implib:$(<:S=.lib) /pdb:$(<:S=.pdb) }
   }
# Compatibility with jam 2.5
rule    LinkLibraries { Libs $(<) ; }

# Compatibility with jam 2.2.
rule    addDirName   { $(<)   += [ FDirName $(>) ] ; }
rule     makeCommon  { FStripCommon $(<) : $(>) ; }
rule    _makeCommon  { FStripCommon $(<) : $(>) ; }
rule    makeDirName  { $(<)    = [ FDirName $(>) ] ; }
rule    makeGrist    { $(<)    = [ FGrist $(>) ] ; }
rule    makeGristedName { $(<) = [ FGristSourceFiles $(>) ] ; }
rule    makeRelPath  { $(<[1]) = [ FRelPath $(<[2-]) : $(>) ] ; }
rule    makeString   { $(<)    = $(>:J) ; }         # :Join
rule    makeSubDir   { $(<)    = [ FSubDir $(>) ] ; }
rule    makeSuffixed { $(<[1]) = [ FAppendSuffix $(>) : $(<[2]) ] ; }
#
# Now include the user's Jamfile.
#
include $(JAMFILE) ;