#
# /+\
#  +\    Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
# \+/
#
# This file is part of Jam - see jam.c for Copyright information.
#

# As part of XJam, this file is intended to only contain host-specific things.
# Anything related to C++, compiling, target-specific rules, etc, should be
# moved out into a module.

# 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
#

# Rules defined by this file:
#
# Bulk dir : files ;                    populate directory with many files
# 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
# MkDir dir ;                           make a directory, if not there
# RmTemps target : sources ;            remove temp sources after target made
# Setuid images ;                       mark executables Setuid
# SoftLink target : source ;            make symlink from source to target
# SubDir TOP d1 d2 ... ;                start a subdirectory Jamfile
# SubInclude TOP d1 d2 ... ;            include a subdirectory Jamfile
# Shell exe : source ;                  make a shell executable
#
# Utility rules that have no side effects:
#
# FAppendSuffix f1 f2 ... : $(SUF) ;    return $(<) with suffixes
# FDirName d1 d2 ... ;                  return path from root to dir
# FGrist d1 d2 ... ;                    return d1!d2!...
# FGristFiles value ;                   return $(value:G=$(SOURCE_GRIST))
# FStripCommon v1 : v2 ;                strip common initial parts of v1 v2
# FReverse a1 a2 ... ;                  return ... a2 a1
# FRelPath d1 : d2 ;                    return rel path from d1 to d2
# FSubDir d1 d2 ... ;                   return path to root
#


# 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 host xxx (UNIX, VMS, NT, OS2, MAC)
#   $(OS) - name of host 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
#

# for perforce use -- jambase version

JAMBASEDATE = 2008.06.08 ;

#
# Host OS specific variable settings
#

if $(NT)
{
    CP      ?= copy ;
    DOT     ?= . ;
    DOTDOT  ?= .. ;
    HOSTSUFEXE  ?= .exe ;
    MV      ?= move /y ;
    RM      ?= del /f/q ;
    RMDIR   ?= rmdir /s /q ;
    SLASH   ?= \\ ;
}
else if $(OS2)
{
    CP       = copy ;
    DOT     ?= . ;
    DOTDOT  ?= .. ;
    HOSTSUFEXE  ?= .exe ;
    MV      ?= move ;
    RM       = del /f ;
}
else if $(VMS)
{
    CHMOD       ?= set file/prot= ;
    CP          ?= copy/replace ;
    DOT         ?= [] ;
    DOTDOT      ?= [-] ;
    EXEMODE     ?= (w:e) ;
    FILEMODE    ?= (w:r) ;
    HOSTSUFEXE  ?= .exe ;
    MKDIR       ?= create/dir ;
    MV          ?= rename ;
    RM          ?= delete ;
    RUNVMS      ?= mcr ;
    SHELLMODE   ?= (w:er) ;
    SLASH       ?= . ;
}
else if $(MAC)
{
    CP          ?= duplicate -y ;
    DOT         ?= ":" ;
    DOTDOT      ?= "::" ;
    MKDIR       ?= newfolder ;
    MV          ?= rename -y ;
    RM          ?= delete -y ;
    SLASH       ?= ":" ;
}
else if $(OS) = BEOS
{
    CHMOD       ?= chmod ;
    CHGRP       ?= chgrp ;
    CHOWN       ?= chown ;
}
else if $(UNIX)
{
    switch $(OS)
    {
    case CYGWIN :
	    HOSTSUFEXE  ?= .exe ;
	    JAMSHELL    ?= sh -c ;

    case INTERIX :
	    JAMSHELL    ?= sh -c ;
    }

    # UNIX defaults
    CHMOD       ?= chmod ;
    CHGRP       ?= chgrp ;
    CHOWN       ?= chown ;
}

#
# General defaults; a lot like UNIX
#
AWK           ?= awk ;
CP            ?= cp -f ;
DOT           ?= . ;
DOTDOT        ?= .. ;
EXEMODE       ?= 711 ;
FILEMODE      ?= 644 ;
HOSTSUFEXE    ?= "" ;
JAMFILE       ?= Jamfile ;
JAMRULES      ?= Jamrules ;
MKDIR         ?= mkdir ;
MV            ?= mv -f ;
RM            ?= rm -f ;
RMDIR         ?= $(RM) ;
SHELLHEADER   ?= "#!/bin/sh" ;
SHELLMODE     ?= 755 ;
SLASH         ?= / ;
SUBDIRRULES   ?= ;
SUBDIRRESET   ?= HDRS ;

OSFULL = $(OS)$(OSVER)$(OSPLAT) $(OS)$(OSPLAT) $(OS)$(OSVER) $(OS) ;


#
# Base dependencies - first for "bootstrap" kinds of rules
#

Depends all : shell files ;
Depends all shell files : first ;
NotFile all first shell files dirs clean ;
Always  clean ;

#
# Rules
#

# /Bulk  directory : sources ;
#
# Copies _sources_ into _directory_
#
rule Bulk
{
    local i ;

    for i in $(>)
    {
        File $(i:D=$(<)) : $(i) ;
    }
}

# /Chmod target ;
#
# (Unix and VMS only). Change file permissions on _target_ to target-specific
# $(MODE) value set by @Link, @File, @Install* and @Shell rules
#
rule Chmod
{
    if $(CHMOD) { Chmod1 $(<) ; }
}

# /Clean  clean : targets ;
#
# Removes existing _targets_ when _clean_ is built. clean is not a dependency
# of all, and must be built explicitely for targets to be removed
#

# /File target : source ;
#
# Copies _source_ into _target_
#
rule File
{
    Depends files : $(<) ;
    Depends $(<) : $(>) ;
    SEARCH on $(>) = $(SEARCH_SOURCE) ;
    MODE on $(<) = $(FILEMODE) ;
    Chmod $(<) ;
}

# /GenFile target : image sources ;
#
# Runs the command "_image_ _target_ _sources_" to create _target_ from
# _sources_ and _image_ (where _image_ is an executable built by the
# @Main rule)
#
rule GenFile
{
    local _t = [ FGristFiles $(<) ] ;
    local _s = [ FAppendSuffix $(>[1]) : $(HOSTSUFEXE) ] ;
    Depends $(_t) : $(_s) $(>[2-]) ;
    GenFile1 $(_t) : $(_s) $(>[2-]) ;
    Clean clean : $(_t) ;
}

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

# /HardLink target : source ;
#
# Makes _target_ a hard link to _source_, if it isn't one already
# (Unix only)
#
rule HardLink
{
    Depends files : $(<) ;
    Depends $(<) : $(>) ;
    SEARCH on $(>) = $(SEARCH_SOURCE) ;
}

# /MakeLocate  targets : directory
#
# Creates _dir_ and causes _target_ to be built into _dir_
#
# This is done by setting the target-specific variable LOCATE
# on _targets_, and arranges with @MkDir to create the target
# directory
#
rule MakeLocate
{
    # 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) ;
        MkDir $(>[1]:G=dir) ;
    }
}

# /MkDir  dir ;
#
# Creates _dir_ and its parent directories
#
rule MkDir
{
    # Ignore timestamps on directories: we only care if they
    # exist.

    NoUpdate $(<) ;

    # Don't create . or any directory already created.

    if $(<:G=) != $(DOT) && ! $($(<)-mkdir)
    {
        # 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.
        # $(<:P) = $(<)'s parent, & we recurse until root

        local s = $(<:P) ;

        # Don't try to create A: or A:\ on windows

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

        # handle "C:", "C:/", "/cygdrive" and "/cygdrive/" in Cygwin
        if $(UNIX) && $(OS) = CYGWIN
        {
            switch $(s)
            {
              case ?:   : s = ;
              case ?:/  : s = ;
              case <dir>/cygdrive   : s = ;
              case <dir>/cygdrive/  : s = ;
            }
        }

        if $(s) = $(<)
        {
	        # 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 $(s) ;
        }
        else if $(s:G=)
        {
	        # There's a parent; recurse.

	        Depends $(<) : $(s) ;
	        MkDir $(s) ;
        }
    }
}

rule RmTemps
{
    Temporary $(>) ;
}

rule Setuid
{
    MODE on [ FAppendSuffix $(<) : $(HOSTSUFEXE) ] = 4711 ;
}

rule Shell
{
    Depends shell : $(<) ;
    Depends $(<) : $(>) ;
    SEARCH on $(>) = $(SEARCH_SOURCE) ;
    MODE on $(<) = $(SHELLMODE) ;
    Clean clean : $(<) ;
    Chmod $(<) ;
}

rule SoftLink
{
    Depends files : $(<) ;
    Depends $(<) : $(>) ;
    SEARCH on $(>) = $(SEARCH_SOURCE) ;
    Clean clean : $(<) ;
}

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="") ;
        $(_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)) ;
            include $(JAMRULES:R=$($(_top)):G=$(_top)) ;
        }
    }

    # 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) ] ;
    HDRGRIST = $(SOURCE_GRIST) ;

    # 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 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 _r = [ FRelPath $($(<[1])-UP) : $($(<[1])-DOWN) $(<[2-]) ] ;

    return $(_r:R=$($(<[1])-ROOT)) ;
}

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)) ;
}

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 UseModule module
{
	# UseModule module ;
	#
	# Includes a module.
	# The module will be search for in these places in order:
	#   - the current directory
	#   - any paths pointed to by JAM_MODULE_PATH
	#   - built into the Jam executable

	local cwd = $(DOT) ;
	if $(SUBDIR) {
		cwd = $(SUBDIR) ;
	}

	local dirs = $(JAM_MODULE_PATH) $(cwd) ;
	local files = [ Glob $(dirs) : $(module).jam ] ;

	if $(files)
	{
		files = [ FReverse $(files) ] ;
		include $(files[1]) ;
	} else {
		include +$(module) ;
	}
}


#
# Utility rules; no side effects on these
#

# /FGrist path to file ;
#
# Returns a single string that is used as grist
#
rule FGrist
{
    return $(<:J=!) ;

}

rule FGristFiles
{
    return $(<:G=$(SOURCE_GRIST:E)) ;
}

rule FReverse
{
    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 _i _d ;

        _d = $(DOTDOT) ;

        for _i in $(<[2-])
        {
        _d = $(_d:R=$(DOTDOT)) ;
        }

        return $(_d) ;
    }
}


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 FRelPath
{
    local _l _r ;

    # first strip off common parts

    _l = $(<) ;
    _r = $(>) ;

    FStripCommon _l : _r ;

    # now make path to root and path down

    _l = [ FSubDir $(_l) ] ;
    _r = [ FDirName $(_r) ] ;

    # Concatenate and save

    # XXX This should be better

    if $(_r) = $(DOT) {
        return $(_l) ;
    } else {
        return $(_r:R=$(_l)) ;
    }
}


rule FAppendSuffix
{
   # E.g., "FAppendSuffix yacc lex foo.bat : $(HOSTSUFEXE) ;"
   # returns (yacc,lex,foo.bat) on Unix and
   # (yacc.exe,lex.exe,foo.bat) on NT.

    if $(>)
    {
        local _i _o ;

        for _i in $(<)
        {
        if $(_i:S)
        {
            _o += $(_i) ;
        }
        else
        {
            _o += $(_i:S=$(>)) ;
        }
        }
        return $(_o) ;
    }
    else
    {
        return $(<) ;
    }
}

#
# Operating system specific utility rules
# First, the (generic) UNIX versions
#

rule FQuote { return "\\\"$(<)\\\"" ; }

rule FDirName
{
    # Turn individual elements in $(<) into a usable path.

    local _i ;
    local _s = $(DOT) ;

    for _i in $(<)
    {
        _s = $(_i:R=$(_s)) ;
    }

    return $(_s) ;
}

if $(OS2)
{
    rule FQuote { return "\"$(<)\"" ; }
}

else if $(MAC)
{
    rule FQuote { return "\"$(<)\"" ; }
}

else if $(VMS)
{
    rule FQuote { return "\"\"\"$(<)\"\"\"" ; }

    rule FDirName
    {
        local _s _i ;

        # Turn individual elements in $(<) into a usable path.

        if ! $(<)
        {
            _s = $(DOT) ;
        }
        else
        {
            # This handles the following cases:
            #   a -> [.a]
            #   a b c -> [.a.b.c]
            #   x: -> x:
            #   x: a -> x:[a]
            #   x:[a] b -> x:[a.b]

            switch $(<[1])
            {
                case *:* :     _s = $(<[1]) ;
                case \\[*\\] : _s = $(<[1]) ;
                case * :       _s = [.$(<[1])] ;
            }

            for _i in [.$(<[2-])]
            {
                _s = $(_i:R=$(_s)) ;
            }
        }

        return $(_s) ;
    }
}

#
# Actions
#

#
# First the defaults
#

actions Chgrp
{
    $(CHGRP) $(GROUP) $(<)
}

actions Chmod1
{
    $(CHMOD) $(MODE) $(<)
}

actions Chown
{
    $(CHOWN) $(OWNER) $(<)
}

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

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

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

actions HardLink
{
    $(RM) $(<) && $(LN) $(>) $(<)
}

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

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

actions Shell
{
    $(AWK) '
        NR == 1 { print "$(SHELLHEADER)" }
        NR == 1 && /^[#:]/ { next }
        /^##/ { next }
        { print }
    ' < $(>) > $(<)
}

actions SoftLink
{
    $(RM) $(<) && $(LN) -s $(>) $(<)
}

#
# UNIX specific actions
#

if $(UNIX)
{
    actions GenFile1
    {
    PATH="$PATH:."
    $(>[1]) $(<) $(>[2-])
    }
}

#
# NT specific actions
#

if $(NT)
{
    actions Shell
    {
        $(CP) $(>) $(<)
    }
}

#
# OS2 specific actions
#

if $(OS2)
{
	actions Shell
	{
	    $(CP) $(>) $(<)
	}
}

#
# VMS specific actions
#

if $(VMS)
{
    actions piecemeal together existing Clean
    {
        $(RM) $(>[1]);* ,$(>[2-]);*
    }
    
    actions GenFile1
    {
        mcr $(>[1]) $(<) $(>[2-])
    }

    actions quietly updated piecemeal together RmTemps
    {
        $(RM) $(>[1]);* ,$(>[2-]);*
    }

    actions Shell
    {
        $(CP) $(>) $(<)
    }
}

#
# Win98 specific actions
#

if $(WIN98)
{
    actions existing Clean
    {
        del $(>)
    }
}

#
# Backwards compatibility with jam 1, where rules were uppercased.
#

rule BULK { Bulk $(<) : $(>) ; }
rule FILE { File $(<) : $(>) ; }
rule SETUID { Setuid $(<) ; }
rule SHELL { Shell $(<) : $(>) ; }

# Compatibility with jam 2.2.

rule addDirName { $(<) += [ FDirName $(>) ] ; }
rule makeCommon { FStripCommon $(<) : $(>) ; }
rule _makeCommon { FStripCommon $(<) : $(>) ; }
rule makeDirName { $(<) = [ FDirName $(>) ] ; }
rule makeGrist { $(<) = [ FGrist $(>) ] ; }
rule makeGristedName { $(<) = [ FGristFiles $(>) ] ; }
rule makeRelPath { $(<[1]) = [ FRelPath $(<[2-]) : $(>) ] ; }
rule makeString { $(<) = $(>:J) ; }
rule makeSubDir { $(<) = [ FSubDir $(>) ] ; }
rule makeSuffixed { $(<[1]) = [ FAppendSuffix $(>) : $(<[2]) ] ; }
rule FGristSourceFiles { return [ FGrist $(>) ] ; }

# Autodetect the correct modules if asked.
# Try and pull in what's needed to build for the host we're running on.
if $(JAM_AUTODETECT)
{
	UseModule autodetect ;
} else {
	# Declare a default rule, so they get an error if they don't override it.
	rule Main
	{
		Echo "error: unknown rule Main" ;
		Echo "If you wish Jam to autodetect this host's configuration," ;
		Echo "either use the -c switch on the command line, or set" ;
		Echo "the JAM_AUTODETECT=1 environment variable." ;
		Exit ;
	}
}


#
# Now include the user's Jamfile.
#

include $(JAMFILE) ;
