Boost logo

Boost-Build :

From: Francesco Gabbanini (f.gabbanini_at_[hidden])
Date: 2006-01-02 08:08:52


Hi Reece,

thanks to your help, it seems I have finally found a way to compile the
boost signals library for WINCE, using BBV2.
I modified some bbv2 configuration files as described in the message you
posted on December 10 2005, "[Boost-build] [BBv2] [msvc] Various
additions to the toolset".
I also had to make some other modifications to get things working, and
therefore I am attaching all the jam files I modified, in case someone
finds them helpful.

There are some points that I would like to highlight:
- I found that dll's with long names (>31 characters) cause problems
when WINCE tries to load them, so I modified the file stage.jam in order
not to include the toolset version in the dll name; this shortens the
names, but it is of course a "patch", I don't know how the problem could
be handled in a more elegant and systematic way...
- I had some problems creating static libraries, because I couldn't
obtain them with the appropriate "lib" prefix (instead of
libboost_signals-vc80-gd-1_34.lib I get boost_signals-vc80-gd-1_34.lib):
to correct this, I modified the add-prefix-and-suffix rule in the file
virtual-target.jam (you can see the change in the source file I am
attaching). Again, I am not an expert in boost-build configuration
files, so I don't know if this is the best way to correct the problem of
static library names generation.
- I modified Microsoft Visual Studio 8\VC\vcvarsall.bat in order to call
Microsoft Visual Studio 8\VC\bin\my_vcvars_arm.bat, which I wrote to
appropriately set VC environment variables.

That's all, I think (I hope I am not forgetting anything!).

Francesco.


@SET VSINSTALLDIR=C:\Programmi\Microsoft Visual Studio 8
@SET VCINSTALLDIR=C:\Programmi\Microsoft Visual Studio 8\VC
@SET FrameworkDir=C:\WINNT\Microsoft.NET\Framework
@SET FrameworkVersion=v2.0.50727
@SET FrameworkSDKDir=C:\Programmi\Microsoft Visual Studio 8\SDK\v2.0
@if "%VSINSTALLDIR%"=="" goto error_no_VSINSTALLDIR
@if "%VCINSTALLDIR%"=="" goto error_no_VCINSTALLDIR

@echo Setting environment for using Microsoft Visual Studio 2005 PocketPC 2003 ARM tools.

@rem
@rem Root of Visual Studio IDE installed files.
@rem
@set DevEnvDir=C:\Programmi\Microsoft Visual Studio 8\Common7\IDE

@set PATH=%VCINSTALLDIR%\ce\bin\x86_arm;%VCINSTALLDIR%\bin;%VCINSTALLDIR%\PlatformSDK\bin;%VSINSTALLDIR%\Common7\Tools;%VSINSTALLDIR%\Common7\IDE;%VSINSTALLDIR%\Common\Tools;%VSINSTALLDIR%\Common\IDE;%VSINSTALLDIR%;%FrameworkSDKDir%\Bin;%PATH%
@set INCLUDE=%VCINSTALLDIR%\ce\include;%VSINSTALLDIR%\SmartDevices\SDK\PocketPC2003\include;%VCINSTALLDIR%\ce\atlmfc\include;%VSINSTALLDIR%\SmartDevices\SDK\SQL Server\Mobile\v3.0;%INCLUDE%
@set LIB=%VSINSTALLDIR%\SmartDevices\SDK\PocketPC2003\lib\ARMV4;%VCINSTALLDIR%\ce\atlmfc\lib\ARMV4;%VCINSTALLDIR%\ce\lib\ARMV4;%LIB%
@set LIBPATH=%VCINSTALLDIR%\ce\atlmfc\src\atl\;%VCINSTALLDIR%\ce\atlmfc\src\mfc\;%VCINSTALLDIR%\ce\crt\src\;%LIBPATH%

@goto end

@rem set PATH=C:\Programmi\Microsoft Visual Studio 8\Common7\IDE;C:\Programmi\Microsoft Visual Studio 8\VC\BIN;C:\Programmi\Microsoft Visual Studio 8\Common7\Tools;C:\Programmi\Microsoft Visual Studio 8\Common7\Tools\bin;C:\Programmi\Microsoft Visual Studio 8\VC\PlatformSDK\bin;C:\Programmi\Microsoft Visual Studio 8\SDK\v2.0\bin;C:\WINNT\Microsoft.NET\Framework\v2.0.50727;C:\Programmi\Microsoft Visual Studio 8\VC\VCPackages;%PATH%
@rem set INCLUDE=C:\Programmi\Microsoft Visual Studio 8\VC\ATLMFC\INCLUDE;C:\Programmi\Microsoft Visual Studio 8\VC\INCLUDE;C:\Programmi\Microsoft Visual Studio 8\VC\PlatformSDK\include;C:\Programmi\Microsoft Visual Studio 8\SDK\v2.0\include;%INCLUDE%
@rem set LIB=C:\Programmi\Microsoft Visual Studio 8\VC\ATLMFC\LIB;C:\Programmi\Microsoft Visual Studio 8\VC\LIB;C:\Programmi\Microsoft Visual Studio 8\VC\PlatformSDK\lib;C:\Programmi\Microsoft Visual Studio 8\SDK\v2.0\lib;%LIB%
@rem set LIBPATH=C:\WINNT\Microsoft.NET\Framework\v2.0.50727;C:\Programmi\Microsoft Visual Studio 8\VC\ATLMFC\LIB

:error_no_VSINSTALLDIR
@echo ERROR: VSINSTALLDIR variable is not set.
@goto end

:error_no_VCINSTALLDIR
@echo ERROR: VCINSTALLDIR variable is not set.
@goto end

:end


@echo off
if "%1" == "" goto x86
if not "%2" == "" goto usage

if /i %1 == x86 goto x86
if /i %1 == amd64 goto amd64
if /i %1 == x64 goto amd64
if /i %1 == ia64 goto ia64
if /i %1 == x86_amd64 goto x86_amd64
if /i %1 == x86_ia64 goto x86_ia64
if /i %1 == arm goto arm
goto usage

:x86
if not exist "%~dp0bin\vcvars32.bat" goto missing
call "%~dp0bin\vcvars32.bat"
goto :eof

:amd64
if not exist "%~dp0bin\amd64\vcvarsamd64.bat" goto missing
call "%~dp0bin\amd64\vcvarsamd64.bat"
goto :eof

:ia64
if not exist "%~dp0bin\ia64\vcvarsia64.bat" goto missing
call "%~dp0bin\ia64\vcvarsia64.bat"
goto :eof

:x86_amd64
if not exist "%~dp0bin\x86_amd64\vcvarsx86_amd64.bat" goto missing
call "%~dp0bin\x86_amd64\vcvarsx86_amd64.bat"
goto :eof

:x86_ia64
if not exist "%~dp0bin\x86_ia64\vcvarsx86_ia64.bat" goto missing
call "%~dp0bin\x86_ia64\vcvarsx86_ia64.bat"
goto :eof

:arm
if not exist "%~dp0bin\my_vcvars_arm.bat" goto missing
call "%~dp0bin\my_vcvars_arm.bat"
goto :eof

:usage
echo Error in script usage. The correct usage is:
echo %0 [option]
echo where [option] is: x86 ^| ia64 ^| amd64 ^| x86_amd64 ^| x86_ia64
echo:
echo For example:
echo %0 x86_ia64
goto :eof

:missing
echo The specified configuration type is missing. The tools for the
echo configuration might not be installed.
goto :eof


# Copyright (C) Vladimir Prus 2002. Permission to copy, use, modify, sell and
# distribute this software is granted provided this copyright notice appears in
# all copies. This software is provided "as is" without express or implied
# warranty, and with no claim as to its suitability for any purpose.

# Implements virtual targets, which correspond to actual files created during
# build, but are not yet targets in Jam sense. They are needed, for example,
# when searching for possible transormation sequences, when it's not known
# if particular target should be created at all.

import "class" : new ;
import path property-set utility sequence errors set type os ;

# +--------------------------+
# | virtual-target |
# +==========================+
# | actualize |
# +--------------------------+
# | actualize-action() = 0 |
# | actualize-location() = 0 |
# +----------------+---------+
# |
# ^
# / \
# +-+-+
# |
# +---------------------+ +-------+--------------+
# | action | | abstract-file-target |
# +=====================| * +======================+
# | action-name | +--+ action |
# | properties | | +----------------------+
# +---------------------+--+ | actualize-action() |
# | actualize() |0..1 +-----------+----------+
# | path() | |
# | adjust-properties() | sources |
# | actualize-sources() | targets |
# +------+--------------+ ^
# | / \
# ^ +-+-+
# / \ |
# +-+-+ +-------------+-------------+
# | | |
# | +------+---------------+ +--------+-------------+
# | | file-target | | searched-lib-target |
# | +======================+ +======================+
# | | actualize-location() | | actualize-location() |
# | +----------------------+ +----------------------+
# |
# +-+------------------------------+
# | |
# +----+----------------+ +---------+-----------+
# | compile-action | | link-action |
# +=====================+ +=====================+
# | adjust-properties() | | adjust-properties() |
# +---------------------+ | actualize-sources() |
# +---------------------+
#
# The 'compile-action' and 'link-action' classes are defined not here,
# but in builtin.jam modules. They are shown in the diagram to give
# the big picture.

# Potential target. It can be converted into jam target and used in
# building, if needed. However, it can be also dropped, which allows
# to search for different transformation and select only one.
#
class virtual-target
{
    import virtual-target utility scanner ;
    
    rule __init__ ( name # Name of this target -- specifies the name of
        : project # Project to which this target belongs
    )
    {
        self.name = $(name) ;
        self.project = $(project) ;
        self.dependencies = ;
    }
    
    # Name of this target.
    rule name ( ) { return $(self.name) ; }

    # Project of this target.
    rule project ( ) { return $(self.project) ; }

    # Adds additional instances of 'virtual-target' that this
    # one depends on.
    rule depends ( d + )
    {
        self.dependencies = [ sequence.merge $(self.dependencies)
                               : [ sequence.insertion-sort $(d) ] ] ;
    }

    rule dependencies ( )
    {
        return $(self.dependencies) ;
    }

    # Generates all the actual targets and sets up build actions for
    # this target.
    #
    # If 'scanner' is specified, creates an additional target
    # with the same location as actual target, which will depend on the
    # actual target and be associated with 'scanner'. That additional
    # target is returned. See the docs (#dependency_scanning) for rationale.
    # Target must correspond to a file if 'scanner' is specified.
    #
    # If scanner is not specified, then actual target is returned.
    rule actualize ( scanner ? )
    {
        local actual-name = [ actualize-no-scanner ] ;

        if ! $(scanner)
        {
            return $(actual-name) ;
        }
        else
        {
            # Add the scanner instance to the grist for name.
            local g = [ sequence.join
                [ utility.ungrist $(actual-name:G) ] $(scanner) : - ] ;
            local name = $(actual-name:G=$(g)) ;

            if ! $(self.made.$(name)) {
                self.made.$(name) = true ;

                DEPENDS $(name) : $(actual-name) ;

                actualize-location $(name) ;

                scanner.install $(scanner) : $(name) $(__name__) ;
            }
            return $(name) ;
        }

    }

# private: (overridables)

    # Sets up build actions for 'target'. Should call appropriate rules
    # and set target variables.
    rule actualize-action ( target )
    {
        errors.error "method should be defined in derived classes" ;
    }

    # Sets up variables on 'target' which specify its location.
    rule actualize-location ( target )
    {
        errors.error "method should be defined in derived classes" ;
    }
    
    # If the target is generated one, returns the path where it will be
    # generated. Otherwise, returns empty list.
    rule path ( )
    {
        errors.error "method should be defined in derived classes" ;
    }
    
    # Return that actual target name that should be used
    # (for the case where no scanner is involved)
    rule actual-name ( )
    {
        errors.error "method should be defined in derived classes" ;
    }

# implementation
    rule actualize-no-scanner ( )
    {
        # In fact, we just need to merge virtual-target with
        # abstract-virtual-target and the latter is the only class
        # derived from the former. But that's for later.
        errors.error "method should be defined in derived classes" ;
    }
}

# Target which correspond to a file. The exact mapping for file
# is not yet specified in this class. (TODO: Actually, the class name
# could be better...)
#
# May be a source file (when no action is specified), or
# derived file (otherwise).
#
# The target's grist is concatenation of project's location,
# properties of action (for derived files), and, optionally,
# value identifying the main target.
class abstract-file-target : virtual-target
{
    import project regex sequence path type ;
    import property-set ;
    import indirect ;
    
    rule __init__ (
         name # Name for this target
        exact ? # If non-empty, the name is exactly the name
                  # created file should have. Otherwise, the '__init__'
                  # method will add suffix obtained from 'type' by
                  # calling 'type.generated-target-suffix'.
        : type ? # The type of this target.
        : project
        : action ?
    )
    {
        virtual-target.__init__ $(name) : $(project) ;
            
        self.type = $(type) ;
        self.action = $(action) ;
        if $(action)
        {
            $(action).add-targets $(__name__) ;

            if $(self.type) && ! $(exact)
            {
                _adjust-name $(name) ;
            }
        }
    }
    
    rule type ( ) { return $(self.type) ; }

    # Sets the path. When generating target name, it will override any path
    # computation from properties.
    rule set-path ( path )
    {
        self.path = [ path.native $(path) ] ;
    }

    # If 'a' is supplied, sets action to 'a'.
    # Returns the action currently set.
    rule action ( )
    {
        return $(self.action) ;
    }

    # Sets/gets the 'root' flag. Target is root is it directly correspods to some
    # variant of a main target.
    rule root ( set ? )
    {
        if $(set)
        {
            self.root = true ;
        }
        return $(self.root) ;
    }
    
    # Gets or sets the subvariant which created this target. Subvariant
    # is set when target is brought into existance, and is never changed
    # after that. In particual, if target is shared by subvariant, only
    # the first is stored.
    rule creating-subvariant ( s ? # If specified, specified the value to set,
                                   # which should be instance of 'subvariant'
                                   # class.
                             )
    {
        if $(s) && ( ! $(self.creating-subvariant) && ! $(overwrite) )
        {
            if $(self.creating-subvariant)
            {
                errors.error "Attempt to change 'dg'" ;
            }
            else
            {
                self.creating-subvariant = $(s) ;
            }
        }
        return $(self.creating-subvariant) ;
    }

    rule actualize-action ( target )
    {
        if $(self.action)
        {
            $(self.action).actualize ;
        }
    }
          
    # Return a human-readable representation of this target
    #
    # If this target has an action, that's:
    #
    # { <action-name>-<self.name>.<self.type> <action-sources>... }
    #
    # otherwise, it's:
    #
    # { <self.name>.<self.type> }
    #
    rule str ( )
    {
        local action = [ action ] ;
        
        local name-dot-type = [ sequence.join $(self.name) "." $(self.type) ] ;
        
        if $(action)
        {
            local sources = [ $(action).sources ] ;
            
            local action-name = [ $(action).action-name ] ;

            local ss ;
            for local s in $(sources)
            {
                ss += [ $(s).str ] ;
            }
            
            return "{" $(action-name)-$(name-dot-type) $(ss) "}" ;
        }
        else
        {
            return "{" $(name-dot-type) "}" ;
        }
    }

    rule less ( a )
    {
        if [ str ] < [ $(a).str ]
        {
            return true ;
        }
    }

    rule equal ( a )
    {
        if [ str ] = [ $(a).str ]
        {
            return true ;
        }
    }

# private:
    rule actual-name ( )
    {
        if ! $(self.actual-name)
        {
            local grist = [ grist ] ;

            local basename = [ path.native $(self.name) ] ;
            self.actual-name = <$(grist)>$(basename) ;
            
        }
        return $(self.actual-name) ;
    }
        
    # Helper to 'actual-name', above. Compute unique prefix used to distinguish
    # this target from other targets with the same name which create different
    # file.
    rule grist ( )
    {
        # Depending on target, there may be different approaches to generating
        # unique prefixes. We'll generate prefixes in the form
        # <one letter approach code> <the actual prefix>
        local path = [ path ] ;
        if $(path)
        {
            # The target will be generated to a known path. Just use the path
            # for identification, since path is as unique as it can get.
            return p$(path) ;
        }
        else
        {
            # File is either source, which will be searched for, or is not a file at
            # all. Use the location of project for distinguishing.
            local project-location = [ $(self.project).get location ] ;
            local location-grist =
              [ sequence.join [ regex.split $(project-location) "/" ] : "!" ] ;
            
            if $(self.action)
            {
                local ps = [ $(self.action).properties ] ;
                local property-grist = [ $(ps).as-path ] ;
                # 'property-grist' can be empty when 'ps' is an empty
                # property set.
                if $(property-grist)
                {
                    location-grist = $(location-grist)/$(property-grist) ;
                }
            }
                        
            return l$(location-grist) ;
        }
    }

    # Given the target name specified in constructor, returns the
    # name which should be really used, by looking at the <tag> properties.
    # The tag properties come in two flavour:
    # - <tag>value,
    # - <tag>@rule-name
    # In the first case, value is just added to name
    # In the second case, the specified rule is called with specified name,
    # target type and properties and should return the new name.
    # If not <tag> property is specified, or the rule specified by
    # <tag> returns nothing, returns the result of calling
    # virtual-target.add-suffix
    rule _adjust-name ( specified-name )
    {
        local ps ;
        if $(self.action)
        {
            ps = [ $(self.action).properties ] ;
        }
        else
        {
            ps = [ property-set.empty ] ;
        }
        
        local tag = [ $(ps).get <tag> ] ;

        if $(tag)
        {
            local rule-name = [ MATCH ^@(.*) : $(tag) ] ;
            if $(rule-name)
            {
                if $(tag[2])
                {
                    errors.error "<tag>@rulename is present but is not the only <tag> feature" ;
                }
                
                self.name = [ indirect.call $(rule-name) $(specified-name) :
                  $(self.type) : $(ps) ] ;
            }
            else
            {
                errors.error
                  "The value of the <tag> feature must be '@rule-nane'" ;
            }
        }
        
        # If there's no tag or the tag rule returned nothing.
        if ! $(tag) || ! $(self.name)
        {
            self.name = [ virtual-target.add-prefix-and-suffix
                $(specified-name) : $(self.type) : $(ps) ] ;
        }
    }

    rule actualize-no-scanner ( )
    {
        local name = [ actual-name ] ;

        # Do anything only on the first invocation
        if ! $(self.made.$(name)) {
            self.made.$(name) = true ;
            
            if $(self.action)
            {
                # For non-derived target, we don't care if there
                # are several virtual targets that refer to the same name.
                # One case when this is unavoidable is when file name is
                # main.cpp and two targets have types CPP (for compiling)
                # and MOCCABLE_CPP (for convertion to H via Qt tools).
                virtual-target.register-actual-name $(name) : $(__name__) ;
            }
                        
            for local i in $(self.dependencies) {
                DEPENDS $(name) : [ $(i).actualize ] ;
            }

            actualize-location $(name) ;
            actualize-action $(name) ;
        }
        return $(name) ;
    }
    
}

# Appends the suffix appropriate to 'type/property-set' combination
# to the specified name and returns the result.
rule add-prefix-and-suffix ( specified-name : type ? : property-set )
{
    local suffix = [ type.generated-target-suffix $(type) : $(property-set) ] ;
    suffix = .$(suffix) ;
    
    local prefix ;
            
    #FRA ADDON
    if [ type.is-derived $(type) STATIC_LIB ] && ! [ type.is-derived $(type) IMPORT_LIB ] && ! [ MATCH ^(lib) : $(specified-name) ]
    #if [ type.is-derived $(type) LIB ] && [ os.on-unix ]
    # && ! [ MATCH ^(lib) : $(specified-name) ]
    #END
    {
        prefix = "lib" ;
    }
    return $(prefix:E="")$(specified-name)$(suffix:E="") ;
}

# File target with explicitly known location.
#
# The file path is determined as
# - value passed to the 'set-path' method, if any
# - for derived files, project's build dir, joined with components
# that describe action's properties. If the free properties
# are not equal to the project's reference properties
# an element with name of main target is added.
# - for source files, project's source dir
#
# The file suffix is
# - the value passed to the 'suffix' method, if any, or
# - the suffix which correspond to the target's type.
#
class file-target : abstract-file-target
{
    import common ;
    import errors ;
    import "class" : new ;
    
    rule __init__ (
      name exact ?
        : type ? # Optional type for this target
        : project
        : action ?
        : path ?
    )
    {
        abstract-file-target.__init__ $(name) $(exact) : $(type) : $(project)
          : $(action) ;

        self.path = $(path) ;
    }
    
    rule clone-with-different-type ( new-type )
    {
        return [ new file-target $(self.name) exact : $(new-type)
          : $(self.project) : $(self.action) : $(self.path) ] ;
    }
            
    rule actualize-location ( target )
    {
        if $(self.action)
        {
            # This is a derived file.
            local path = [ path ] ;
            LOCATE on $(target) = $(path) ;

            # Make sure the path exists.
            DEPENDS $(target) : $(path) ;
            common.MkDir $(path) ;

            # It's possible that the target name includes a directory
            # too, for example when installing headers. Create that
            # directory.
            if $(target:D)
            {
                local d = $(target:D) ;
                d = $(d:R=$(path)) ;
                DEPENDS $(target) : $(d) ;

                common.MkDir $(d) ;
            }
            
            # For real file target, we create gristless target that
            # depends on the real target. This allows to run
            #
            # bjam hello.o
            #
            # without trying to guess the name of the real target.
            DEPENDS $(target:G=) : $(target) ;
        }
        else
        {
            SEARCH on $(target) = [ path.native $(self.path) ] ;
        }
    }
    
    # Returns the directory for this target
    rule path ( )
    {
        if ! $(self.path)
        {
            if $(self.action)
            {
                local p = [ $(self.action).properties ] ;
                local path = [ $(p).target-path ] ;
                
                if $(path[2]) = true
                {
                    # Indicates that the path is relative to
                    # build dir.
                    path = [ path.join [ $(self.project).build-dir ]
                       $(path[1]) ] ;
                }
                                
                # Store the computed path, so that it's not recomputed
                # any more
                self.path = [ path.native $(path) ] ;
            }
        }
        return $(self.path) ;
     }

}

class notfile-target : abstract-file-target
{
    rule __init__ ( name : project : action ? )
    {
        abstract-file-target.__init__ $(name) : : $(project) : $(action) ;
    }
    
    # Returns nothing, to indicate that target path is not known.
    rule path ( )
    {
        return ;
    }
            
    rule actualize-location ( target )
    {
        NOTFILE $(target) ;
        ALWAYS $(target) ;
    }
}

# Class which represents an action.
# Both 'targets' and 'sources' should list instances of 'virtual-target'.
# Action name should name a rule with this prototype
# rule action-name ( targets + : sources * : properties * )
# Targets and sources are passed as actual jam targets. The rule may
# not establish dependency relationship, but should do everything else.
class action
{
    import type toolset property-set indirect class path assert ;
    
    rule __init__ ( sources * : action-name + : property-set ? )
    {
        self.sources = $(sources) ;
    
        self.action-name = [ indirect.make-qualified $(action-name) ] ;
        
        if ! $(property-set)
        {
            property-set = [ property-set.empty ] ;
        }
        
        if ! [ class.is-instance $(property-set) ]
        {
            errors.error "Property set instance required" ;
        }
        
        self.properties = $(property-set) ;
    }
    
    rule add-targets ( targets * )
    {
        self.targets += $(targets) ;
    }
        
    rule targets ( )
    {
        return $(self.targets) ;
    }

    rule sources ( )
    {
        return $(self.sources) ;
    }

    rule action-name ( )
    {
        return $(self.action-name) ;
    }

    rule properties ( )
    {
        return $(self.properties) ;
    }

    # Generates actual build instructions.
    rule actualize ( )
    {
        if ! $(self.actualized)
        {
            self.actualized = true ;

            local ps = [ properties ] ;
            local properties = [ adjust-properties $(ps) ] ;

            local actual-targets ;
            for local i in [ targets ]
            {
                actual-targets += [ $(i).actualize ] ;
            }

            actualize-sources [ sources ] : $(properties) ;

            DEPENDS $(actual-targets) : $(self.actual-sources) $(self.dependency-only-sources) ;

            # Action name can include additional argument to rule, which should not
            # be passed to 'set-target-variables'
            toolset.set-target-variables
              [ indirect.get-rule $(self.action-name[1]) ] $(actual-targets)
                : $(properties) ;
            
            indirect.call $(self.action-name)
              $(actual-targets) : $(self.actual-sources) : [ $(properties).raw ]
                ;
            
            # Since we set up creating action here, we also set up
            # action for cleaning up
            common.Clean clean : $(actual-targets) ;
        }
    }

    # Helper for 'actualize-sources'.
    # For each passed source, actualizes it with the appropriate scanner.
    # Returns the actualized virtual targets.
    rule actualize-source-type ( sources * : property-set )
    {
        local result = ;
        for local i in $(sources)
        {
            local scanner ;
            if [ $(i).type ]
            {
                scanner =
                  [ type.get-scanner [ $(i).type ] : $(property-set) ] ;
            }
            result += [ $(i).actualize $(scanner) ] ;
        }
        
        return $(result) ;
    }
    
    # Creates actual jam targets for sources. Initialized two member
    # variables:.
    # 'self.actual-sources' -- sources which are passed to updating action
    # 'self.dependency-only-sources' -- sources which are made dependencies, but
    # are not used otherwise.
    #
    # New values will be *appended* to the variables. They may be non-empty,
    # if caller wants it.
    rule actualize-sources ( sources * : property-set )
    {
        local dependencies = [ $(self.properties).get <dependency> ] ;
                
        self.dependency-only-sources += [
          actualize-source-type $(dependencies) : $(property-set) ] ;
        self.actual-sources += [
          actualize-source-type $(sources) : $(property-set) ] ;
    }

    # Determined real properties when trying building with 'properties'.
    # This is last chance to fix properties, for example to adjust includes
    # to get generated headers correctly. Default implementation returns
    # its argument.
    rule adjust-properties ( property-set )
    {
        return $(property-set) ;
    }
}

# Action class which does nothing --- it produces the targets with
# specific properties out of nowhere. It's needed to distinguish virtual
# targets with different properties that are known to exist, and have no
# actions which create them.
class null-action : action
{
    rule __init__ ( property-set ? )
    {
        action.__init__ : .no-action : $(property-set) ;
    }
        
    rule actualize ( )
    {
        if ! $(self.actualized)
        {
            self.actualized = true ;

            for local i in [ targets ]
            {
                $(i).actualize ;
            }
        }
    }
}

# Class which acts exactly like 'action', except that the sources
# are not scanned for dependencies.
class non-scanning-action : action
{
    rule __init__ ( sources * : action-name + : property-set ? )
    {
        action.__init__ $(sources) : $(action-name) : $(property-set) ;
    }
    rule actualize-source-type ( sources * : property-set )
    {
        local result ;
        for local i in $(sources)
        {
            result += [ $(i).actualize ] ;
        }
        return $(result) ;
    }
}

# Creates a virtual target with approariate name and type from 'file'.
# If a target with that name in that project was already created, returns that already
# created target.
# FIXME: more correct way would be to compute path to the file, based on name and source location
# for the project, and use that path to determine if the target was already created.
# TODO: passing project with all virtual targets starts to be annoying.
rule from-file ( file : file-loc : project )
{
    import type ; # had to do this here to break a circular dependency

    # Check if we've created a target corresponding to this file.
    local path = [ path.root [ path.root $(file) $(file-loc) ]
                             [ path.pwd ] ] ;

    if $(.files.$(path))
    {
        return $(.files.$(path)) ;
    }
    else
    {
        local name = [ path.make $(file) ] ;
        local type = [ type.type $(file) ] ;
        local result ;

        result = [ new file-target $(file)
                         : $(type)
                         : $(project)
                         : #action
                         : $(file-loc) ] ;

        .files.$(path) = $(result) ;
        return $(result) ;
    }
}

# Registers a new virtual target. Checks if there's already registered target, with the same
# name, type, project and subvariant properties, and also with the same sources
# and equal action. If such target is found it is retured and 'target' is not registers.
# Otherwise, 'target' is registered and returned.
rule register ( target )
{
    local signature = [ sequence.join
       [ $(target).path ] [ $(target).name ] : - ] ;

            
    local result ;
    for local t in $(.cache.$(signature))
    {
        local a1 = [ $(t).action ] ;
        local a2 = [ $(target).action ] ;
        
        if ! $(result)
        {
            if ! $(a1) && ! $(a2)
            {
                result = $(t) ;
            }
            else
            {
                if $(a1) && $(a2) && [ $(a1).action-name ] = [ $(a2).action-name ] &&
                  [ $(a1).sources ] = [ $(a2).sources ]
                {
                    local ps1 = [ $(a1).properties ] ;
                    local ps2 = [ $(a2).properties ] ;
                    local p1 = [ $(ps1).base ] [ $(ps1).free ] [ $(ps1).dependency ] ;
                    local p2 = [ $(ps2).base ] [ $(ps2).free ] [ $(ps2).dependency ] ;
                    if $(p1) = $(p2)
                    {
                        result = $(t) ;
                    }
                }
            }
        }
    }
    
    if ! $(result)
    {
        .cache.$(signature) += $(target) ;
        result = $(target) ;
    }
    
    .recent-targets += $(result) ;

    return $(result) ;
}

# Each target returned by 'register' is added to a list of
# 'recent-target', returned by this function. So, this allows
# us to find all targets created when building a given main
# target, even if the target
rule recent-targets ( )
{
    return $(.recent-targets) ;
}

rule clear-recent-targets ( )
{
    .recent-targets = ;
}

rule register-actual-name ( actual-name : virtual-target )
{
    if $(.actual.$(actual-name))
    {
        local cs1 = [ $(.actual.$(actual-name)).creating-subvariant ] ;
        local cs2 = [ $(virtual-target).creating-subvariant ] ;
        local cmt1 = [ $(cs1).main-target ] ;
        local cmt2 = [ $(cs2).main-target ] ;
        
        
        local action1 = [ $(.actual.$(actual-name)).action ] ;
        local action2 = [ $(virtual-target).action ] ;
        local properties-added ;
        local properties-removed ;
        if $(action1) && $(action2)
        {
            local p1 = [ $(action1).properties ] ;
            p1 = [ $(p1).raw ] ;
            local p2 = [ $(action2).properties ] ;
            p2 = [ $(p2).raw ] ;
            properties-removed = [ set.difference $(p1) : $(p2) ] ;
            properties-removed ?= "none" ;
            properties-added = [ set.difference $(p2) : $(p1) ] ;
            properties-added ?= "none" ;
        }
        errors.error "Duplicate name of actual target:" $(actual-name)
          : "previous virtual target" [ $(.actual.$(actual-name)).str ]
          : "created from" [ $(cmt1).full-name ]
          : "another virtual target" [ $(virtual-target).str ]
          : "created from" [ $(cmt2).full-name ]
          : "added properties: " $(properties-added)
          : "removed properties: " $(properties-removed) ;
    }
    else
    {
        .actual.$(actual-name) = $(virtual-target) ;
    }
}

# Traverses the dependency graph of 'target' and return all targets that will
# be created before this one is created. If root of some dependency graph is
# found during traversal, it's either included or not, dependencing of the
# value of 'include-roots'. In either case, sources of root are not traversed.
rule traverse ( target : include-roots ? : include-sources ? )
{
    local result ;
    if [ $(target).action ]
    {
        local action = [ $(target).action ] ;
        # This includes 'target' as well
        result += [ $(action).targets ] ;

        for local t in [ $(action).sources ]
        {
            if ! [ $(t).root ]
            {
                result += [ traverse $(t) : $(include-roots) : $(include-sources) ] ;
            }
            else if $(include-roots)
            {
                result += $(t) ;
            }
        }
    }
    else if $(include-sources)
    {
        result = $(target) ;
    }
    return $(result) ;
}

# Takes an 'action' instances and creates new instance of it
# and all produced target. The rule-name and properties are set
# to 'new-rule-name' and 'new-properties', if those are specified.
# Returns the cloned action.
rule clone-action ( action : new-project : new-action-name ? : new-properties ? )
{
    if ! $(new-action-name)
    {
        new-action-name = [ $(action).action-name ] ;
    }
    if ! $(new-properties)
    {
        new-properties = [ $(action).properties ] ;
    }

    local action-class = [ modules.peek $(action) : __class__ ] ;
    local cloned-action = [ class.new $(action-class)
      [ $(action).sources ] : $(new-action-name) : $(new-properties) ] ;
                        
    local cloned-targets ;
    for local target in [ $(action).targets ]
    {
        local n = [ $(target).name ] ;
        # Don't modify the name of the produced targets.Strip the directory f
        local cloned-target = [ class.new file-target $(n) exact : [ $(target).type ]
          : $(new-project) : $(cloned-action) ] ;
        local d = [ $(target).dependencies ] ;
        if $(d)
        {
            $(cloned-target).depends $(d) ;
        }
        $(cloned-target).root [ $(target).root ] ;
        $(cloned-target).creating-subvariant [ $(target).creating-subvariant ] ;
        
        cloned-targets += $(cloned-target) ;
    }
                    
    return $(cloned-action) ;
}

class subvariant
{
    import sequence ;
    import type ;
    
    rule __init__ ( main-target # The instance of main-target class
        : property-set # Properties requested for this target
        : sources *
        : build-properties # Actually used properties
        : sources-usage-requirements # Properties propagated from sources
        : created-targets * ) # Top-level created targets
    {
        self.main-target = $(main-target) ;
        self.properties = $(property-set) ;
        self.sources = $(sources) ;
        self.build-properties = $(build-properties) ;
        self.sources-usage-requirements = $(sources-usage-requirements) ;
        self.created-targets = $(created-targets) ;

        # Pre-compose the list of other dependency graphs, on which this one
        # depends
        local deps = [ $(build-properties).get <implicit-dependency> ] ;
        for local d in $(deps)
        {
            self.other-dg += [ $(d:G=).creating-subvariant ] ;
        }
        
        self.other-dg = [ sequence.unique $(self.other-dg) ] ;
    }
    
               
    rule main-target ( )
    {
        return $(self.main-target) ;
    }
    
    rule created-targets ( )
    {
        return $(self.created-targets) ;
    }
    
    rule requested-properties ( )
    {
        return $(self.properties) ;
    }
    
    rule build-properties ( )
    {
        return $(self.build-properties) ;
    }
        
    rule sources-usage-requirements ( )
    {
        return $(self.sources-usage-requirements) ;
    }
    
    rule set-usage-requirements ( usage-requirements )
    {
        self.usage-requirements = $(usage-requirements) ;
    }
    
    rule usage-requirements ( )
    {
        return $(self.usage-requirements) ;
    }
            
    # Returns all targets referenced by this subvariant,
    # either directly or indirectly, and
    # either as sources, or as dependency properties.
    # Targets referred with dependency property are returned a properties,
    # not targets.
    rule all-referenced-targets ( )
    {
        # Find directly referenced targets.
        local deps = [ $(self.build-properties).dependency ] ;
        local all-targets = $(self.sources) $(deps) ;
        
        # Find other subvariants.
        local r ;
        for local t in $(all-targets)
        {
            r += [ $(t:G=).creating-subvariant ] ;
        }
        r = [ sequence.unique $(r) ] ;
        for local s in $(r)
        {
            if $(s) != $(__name__)
            {
                all-targets += [ $(s).all-referenced-targets ] ;
            }
        }
        return $(all-targets) ;
    }
               
    # Returns the properties which specify implicit include paths to
    # generated headers. This traverses all targets in this subvariant,
    # and subvariants referred by <implcit-dependecy>properties.
    # For all targets which are of type 'target-type' (or for all targets,
    # if 'target-type' is not specified), the result will contain
    # <$(feature)>path-to-that-target.
    rule implicit-includes ( feature : target-type ? )
    {
        local key = ii$(feature)-$(target-type:E="") ;
        if ! $($(key))-is-nonempty
        {
            local target-paths = [ all-target-directories $(target-type) ] ;
            target-paths = [ sequence.unique $(target-paths) ] ;
            local result = $(target-paths:G=$(feature)) ;
            if ! $(result)
            {
                result = "" ;
            }
            $(key) = $(result) ;
        }
        if $($(key)) = ""
        {
            return ;
        }
        else
        {
            return $($(key)) ;
        }
    }
        
    rule all-target-directories ( target-type ? )
    {
        if ! $(self.target-directories)
        {
            compute-target-directories $(target-type) ;
        }
        return $(self.target-directories) ;
    }
    
    rule compute-target-directories ( target-type ? )
    {
        local result ;
        for local t in $(self.created-targets)
        {
            if $(target-type) && ! [ type.is-derived [ $(t).type ] $(target-type) ]
            {
                # Skip target which is of wrong type.
            }
            else
            {
                result = [ sequence.merge $(result) : [ $(t).path ] ] ;
            }
        }
        for local d in $(self.other-dg)
        {
            result += [ $(d).all-target-directories $(target-type) ] ;
        }
        self.target-directories = $(result) ;
    }
}


# Copyright (C) Vladimir Prus 2002. Permission to copy, use, modify, sell and
# distribute this software is granted provided this copyright notice appears in
# all copies. This software is provided "as is" without express or implied
# warranty, and with no claim as to its suitability for any purpose.

# This module defines the 'install' rule, used to copy a set of targets to
# a single location

import targets ;
import "class" : new ;
import property ;
import errors : error ;
import type : type ;
import type ;
import regex ;
import generators ;
import feature ;
import project ;
import property-set ;
import virtual-target ;
import path ;

feature.feature <install-dependencies> : off on : incidental ;
feature.feature <install-type> : : free incidental ;
feature.feature <install-source-root> : : free path ;
feature.feature <so-version> : : free incidental ;

class install-target-class : basic-target
{
    import feature project type errors generators path stage ;
    import "class" : new ;
    
    rule __init__ ( name-and-dir : project : sources * : requirements * : default-build * )
    {
        basic-target.__init__ $(name-and-dir) : $(project) : $(sources) : $(requirements)
          : $(default-build) ;
    }

    # If <location> is not set, sets it based on the project data.
    rule update-location ( property-set )
    {
        local loc = [ $(property-set).get <location> ] ;
        if ! $(loc)
        {
            loc = [ path.root $(self.name) [ $(self.project).get location ] ] ;

            property-set = [ $(property-set).add-raw $(loc:G=<location>) ] ;
        }
        
        return $(property-set) ;
    }
            
    # Takes a target that is installed and property set which is
    # used when installing.
    rule adjust-properties ( target : build-property-set )
    {
        local ps-raw ;
        local a = [ $(target).action ] ;
        if $(a)
        {
            local ps = [ $(a).properties ] ;
            ps-raw = [ $(ps).raw ] ;
                        
            # Unless <hardcode-dll-paths>true is in properties, which can
            # happen only if the user has explicitly requested it, nuke all
            # <dll-path> properties
            if [ $(property-set).get <hardcode-dll-paths> ] != true
            {
                ps-raw = [ property.change $(ps-raw) : <dll-path> ] ;
            }
            
            # If any <dll-path> properties were specified for installing,
            # add them.
            local l = [ $(build-property-set).get <dll-path> ] ;
            ps-raw += $(l:G=<dll-path>) ;
        }
        
        # Remove the <tag> feature on original targets.
        ps-raw = [ property.change $(ps-raw) : <tag> ] ;
        # And <location>. If stage target has another stage target
        # in sources, then we'll get virtual targets with <location>
        # property set.
        ps-raw = [ property.change $(ps-raw) : <location> ] ;
        
        
        local d = [ $(build-property-set).get <dependency> ] ;
        ps-raw += $(d:G=<dependency>) ;
        
        local d = [ $(build-property-set).get <location> ] ;
        ps-raw += $(d:G=<location>) ;
        
        local d = [ $(build-property-set).get <install-source-root> ] ;
        # Make the path absolute: we'll use it to compute relative
        # paths and making the path absolute will help.
        if $(d)
        {
            d = [ path.root $(d) [ path.pwd ] ] ;
            ps-raw += $(d:G=<install-source-root>) ;
        }
        
        if $(ps-raw)
        {
            return [ property-set.create $(ps-raw) ] ;
        }
        else
        {
            return [ property-set.empty ] ;
        }
    }
    
        
    rule construct ( name : source-targets * : property-set )
    {
        source-targets = [
          targets-to-stage $(source-targets) : $(property-set) ] ;
        
        property-set = [ update-location $(property-set) ] ;
                                       
        local result ;
        for local i in $(source-targets)
        {
            local staged-targets ;
                        
            local new-properties =
              [ adjust-properties $(i) : $(property-set) ] ;
                                    
            # See if something special should be done when staging this
            # type. It is indicated by presense of special "staged" type
            local t = [ $(i).type ] ;
            if $(t) && [ type.registered INSTALLED_$(t) ]
            {
                local targets = [ generators.construct $(self.project) $(name) :
                  INSTALLED_$(t) : $(new-properties) : $(i) : * ] ;
                staged-targets += $(targets[2-]) ;
            }
            else
            {
                staged-targets = [ stage.copy-file $(self.project)
                  : $(i) : $(new-properties) ] ;
            }
            
            if ! $(staged-targets)
            {
                errors.error "Unable to generate staged version of " [ $(source).str ] ;
            }
            
            for t in $(staged-targets)
            {
                result += [ virtual-target.register $(t) ] ;
            }
        }
        
        return [ property-set.empty ] $(result) ;
    }
    

    # Given the list of source targets explicitly passed to 'stage',
    # returns the list of targets which must be staged.
    rule targets-to-stage ( source-targets * : property-set )
    {
        local result ;
        
        # Traverse the dependencies, if needed.
        if [ $(property-set).get <install-dependencies> ] = "on"
        {
            source-targets = [ collect-targets $(source-targets) ] ;
        }
        
        # Filter the target types, if needed
        local included-types = [ $(property-set).get <install-type> ] ;
        for local r in $(source-targets)
        {
            local ty = [ $(r).type ] ;
            if $(ty)
            {
                # Don't stage searched libs.
                if $(ty) != SEARCHED_LIB
                {
                    if $(included-types)
                    {
                        if [ include-type $(ty) : $(included-types) ]
                        {
                            result += $(r) ;
                        }
                    }
                    else
                    {
                        result += $(r) ;
                    }
                }
            }
            else
            {
                result += $(r) ;
            }
        }
                
        return $(result) ;
    }
    
    # CONSIDER: figure out why we can't use virtual-target.traverse here.
    rule collect-targets ( targets * )
    {
        # Find subvariants
        local s ;
        for local t in $(targets)
        {
            s += [ $(t).creating-subvariant ] ;
        }
        s = [ sequence.unique $(s) ] ;
        
        local result = $(targets) ;
        for local i in $(s)
        {
            result += [ $(i).all-referenced-targets ] ;
        }
        local result2 ;
        for local r in $(result)
        {
            if $(r:G) != <use>
            {
                result2 += $(r:G=) ;
            }
        }
        result = [ sequence.unique $(result2) ] ;
    }
                
    # Returns true iff 'type' is subtype of some element of 'types-to-include'.
    local rule include-type ( type : types-to-include * )
    {
        local found ;
        while $(types-to-include) && ! $(found)
        {
            if [ type.is-subtype $(type) $(types-to-include[1]) ]
            {
                found = true ;
            }
            types-to-include = $(types-to-include[2-]) ;
        }
        
        return $(found) ;
    }
}

# Creates a copy of target 'source'. The 'properties' object should
# have a <location> property which specifies where the target must
# be placed.
rule copy-file ( project : source : properties )
{
    local targets ;
    local name = [ $(source).name ] ;
               
    new-a = [
      new non-scanning-action $(source) : common.copy : $(properties) ] ;
    local source-root = [ $(properties).get <install-source-root> ] ;
    if $(source-root)
    {
        # Get the real path of the target. We probably need to strip
        # relative path from the target name at construction...
        local path = [ $(source).path ] ;
        path = [ path.root $(name:D) $(path) ] ;
        # Make the path absolute. Otherwise, it's hard to compute relative
        # path. The 'source-root' is already absolute, see the
        # 'adjust-properties' method above.
        path = [ path.root $(path) [ path.pwd ] ] ;

        relative = [ path.relative-to $(source-root) $(path) ] ;
        
        targets = [ new file-target $(name:D=$(relative)) exact : [ $(source).type ]
          : $(project) : $(new-a) ] ;
    }
    else
    {
        targets = [ new file-target $(name:D=) exact : [ $(source).type ]
          : $(project) : $(new-a) ] ;
    }
            
    return $(targets) ;
}

rule symlink ( name : project : source : properties )
{
    local a = [ new action $(source) : symlink.ln :
      $(properties) ] ;
    local targets = [
     new file-target $(name) exact : [ $(source).type ] : $(project) : $(a) ] ;
    
    return $(targets) ;
}

rule relink-file ( project : source : property-set )
{
    local action = [ $(source).action ] ;
    local cloned-action = [ virtual-target.clone-action $(action) : $(project) :
      "" : $(property-set) ] ;
    local result = [ $(cloned-action).targets ] ;
    
    return $(result) ;
}

# Declare installed version of the EXE type. Generator for this type will
# cause relinking to the new location.
type.register INSTALLED_EXE : : EXE ;

class installed-exe-generator : generator
{
    import type property-set modules stage ;
    
    rule __init__ ( )
    {
        generator.__init__ install-exe : EXE : INSTALLED_EXE ;
    }
    
    rule run ( project name ? : property-set : source : multiple ? )
    {
        if [ $(property-set).get <os> ] in NT CYGWIN
        {
            # Relinking is never needed on NT
            return [ stage.copy-file $(project)
              : $(source) : $(property-set) ] ;
        }
        else
        {
            return [ stage.relink-file $(project)
              : $(source) : $(property-set) ] ;
        }
    }
}

generators.register [ new installed-exe-generator ] ;

# Installing shared link on Unix might cause a creation of
# versioned symbolic links.
type.register INSTALLED_SHARED_LIB : : SHARED_LIB ;
class installed-shared-lib-generator : generator
{
    import type property-set modules stage ;
    
    rule __init__ ( )
    {
        generator.__init__ install-shared-lib : SHARED_LIB
          : INSTALLED_SHARED_LIB ;
    }
    
    rule run ( project name ? : property-set : source : multiple ? )
    {
        if [ $(property-set).get <os> ] = NT
        {
            local copied = [ stage.copy-file $(project)
              : $(source) : $(property-set) ] ;
        
            copied = [ virtual-target.register $(copied) ] ;
            
            return $(copied) ;
        }
        else
        {
            local a = [ $(source).action ] ;
            local copied ;
            if ! $(a)
            {
                # Non-derived file, just copy.
                copied = [ stage.copy-file $(project)
                  : $(source) : $(property-set) ] ;
            }
            else
            {
                local cp = [ $(a).properties ] ;
                local current-dll-path = [ $(cp).get <dll-path> ] ;
                local new-dll-path = [ $(property-set).get <dll-path> ] ;
                                    
                if $(current-dll-path) != $(new-dll-path)
                {
                    # Rpath changed, need to relink.
                    copied = [ stage.relink-file
                        $(project) : $(source) : $(property-set) ] ;
                }
                else
                {
                    copied = [ stage.copy-file $(project)
                      : $(source) : $(property-set) ] ;
                }
            }
                                
            copied = [ virtual-target.register $(copied) ] ;
                                    
            local result = $(copied) ;
            # If the name is in the form NNN.XXX.YYY.ZZZ, where all
            # 'X', 'Y' and 'Z' are numbers, we need to create
            # NNN.XXX and NNN.XXX.YYY symbolic links.
            local m = [ MATCH (.*)\\.([0123456789]+)\\.([0123456789]+)\\.([0123456789]+)$
              : [ $(copied).name ] ] ;
            if $(m)
            {
                result += [ stage.symlink $(m[1]).$(m[2]) : $(project)
                  : $(copied) : $(property-set) ] ;
                result += [ stage.symlink $(m[1]).$(m[2]).$(m[3]) : $(project)
                  : $(copied) : $(property-set) ] ;
            }
                                    
            return $(result) ;
        }
    }
}

generators.register [ new installed-shared-lib-generator ] ;

# Main target rule for 'install'
rule install ( name : sources * : requirements * : default-build * )
{
    local project = [ project.current ] ;
    
    # Unless the user has explicitly asked us to hardcode dll paths, add
    # <hardcode-dll-paths>false in requirements, to override default
    # value.
    if ! <hardcode-dll-paths>true in $(requirements)
    {
        requirements += <hardcode-dll-paths>false ;
    }
    
    if <name> in $(requirements:G)
    {
        errors.user-error
          "The <name> property is not allowed for the 'install' rule" ;
    }
    if <tag> in $(requirements:G)
    {
        errors.user-error
          "The <tag> property is not allowed for the 'install' rule" ;
    }
           
    targets.main-target-alternative
      [ new install-target-class $(name) : $(project)
        : [ targets.main-target-sources $(sources) : $(name) ]
        : [ targets.main-target-requirements $(requirements) : $(project) ]
        : [ targets.main-target-default-build $(default-build) : $(project) ]
      ] ;
}

IMPORT $(__name__) : install : : install ;
IMPORT $(__name__) : install : : stage ;

rule add-variant-and-compiler ( name : type ? : property-set )
{
    return [ rename $(name) : $(type) : $(property-set) ] ;
}

rule add-variant ( name : type ? : property-set )
{
    return [ rename $(name) : $(type) : $(property-set) : unversioned ] ;
}

rule rename ( name : type ? : property-set : unversioned ? )
{
    if [ type.is-derived $(type) LIB ]
    {
        local properties = [ $(property-set).raw ] ;
    
        local tags = ;
    
        local thread-tag ;
        if <threading>multi in $(properties) { thread-tag = mt ; }
        
        local runtime-tag = ;
        if <runtime-link>static in $(properties) { runtime-tag += s ; }
        #FRA ADDON (SUGGESTED BY Volodya)
        #if <runtime-build>debug in $(properties) { runtime-tag += g ; }
        if <runtime-debugging>on in $(properties) { runtime-tag += g ; }
        #END
        
        if <variant>debug-python in $(properties) { runtime-tag += y ; }
        if <variant>debug in $(properties) { runtime-tag += d ; }
        if <stdlib>stlport in $(properties) { runtime-tag += p ; }
        if <stdlib-stlport:iostream>hostios in $(properties) { runtime-tag += n ; }
        
        local toolset-tag = ;
        # 'unversioned' should be a parameter.
        if ! $(unversioned)
        {
            switch [ $(property-set).get <toolset> ]
            {
                case borland* : toolset-tag += bcb ;
                case como* : toolset-tag += como ;
                case cw : toolset-tag += cw ;
                case darwin* : toolset-tag += ;
                case edg* : toolset-tag += edg ;
                case gcc* : toolset-tag += gcc ;
                case intel-linux* : toolset-tag += il ;
                case intel-win* : toolset-tag += iw ;
                case kcc* : toolset-tag += kcc ;
                case kylix* : toolset-tag += bck ;
                #case metrowerks* : toolset-tag += cw ;
                #case mingw* : toolset-tag += mgw ;
                case mipspro* : toolset-tag += mp ;
                case msvc* : toolset-tag += vc ;
                case sun* : toolset-tag += sw ;
                case tru64cxx* : toolset-tag += tru ;
                case vacpp* : toolset-tag += xlc ;
            }
            local version = [ MATCH "<toolset.*version>([0123456789]+)[.]([0123456789]*)" : $(properties) ] ;
            #FRA ADDON
            toolset-tag = "" ;
            #toolset-tag += $(version) ;
            #END
        }

        # Note yet clear if this should be added on Linux (where we have
        # version in soname) and how it should be done on Windows.
        #local version-tag = ;
        #if ! $(gUNVERSIONED_VARIANT_TAG)
        #{
        # local version-number = [ get-values <version> : $(properties) ] ;
        # version-number ?= $(BOOST_VERSION) ;
        # version-tag = [ MATCH "^([^.]+)[.]([^.]+)" : $(version-number[1]) ] ;
        # version-tag = $(version-tag:J="_") ;
        #}
    
        tags += $(toolset-tag:J=) ;
        tags += $(thread-tag:J=) ;
        tags += $(runtime-tag:J=) ;
        #tags += $(version-tag) ;
    
        local result ;
        
        if $(tags)
        {
            #FRA ADDON
            #result = $(name)-$(tags:J=-) ;
            result = $(name)$(tags:J=-) ;
            #END
        }
        else
        {
            result = $(name) ;
        }
        return [ virtual-target.add-prefix-and-suffix $(result) : $(type)
          : $(property-set) ] ;
    }
}


# Copyright (c) 2003 David Abrahams.
# Copyright (c) 2005 Vladimir Prus.
# Copyright (c) 2005 Alexey Pakhunov.
#
# Use, modification and distribution is subject to the Boost Software
# License Version 1.0. (See accompanying file LICENSE_1_0.txt or
# http://www.boost.org/LICENSE_1_0.txt)

import property ;
import generators ;
import os ;
import type ;
import toolset : flags ;
import errors : error ;
import feature : feature get-values ;
import path ;
import sequence : unique ;
import common ;
import "class" : new ;
import rc ;
import midl ;
import mc ;
import pch ;

import msplatformsdk ;

if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ]
{
    .debug-configuration = true ;
}

feature.extend toolset : msvc ;

feature.subfeature toolset msvc : vendor
  : intel
  : propagated optional
  # intel and msvc supposedly have link-compatible objects... remains
  # to be seen, though ;-)
  ;

feature clr : default managed cppcli : propagated ;
feature pure-clr : no yes : propagated ;
feature safe-clr : no yes : propagated ;
feature have-assembly : yes no : propagated ;
feature initial-app-domain : no yes : propagated ;

feature resource-only : no yes : incidental ;
feature debug-store : object database edit-and-continue lines-only : propagated ;

feature improve-fp-consistency : no yes : propagated ;
feature fiber-safe-optimization : no yes : propagated ;
feature optimize-for-windows : no yes : propagated ;
feature function-hooks : none enter exit both : propagated ;
feature string-pooling : no yes : propagated ;
feature minimal-rebuild : no yes : propagated ;
feature security-checks : no yes : propagated ;
feature separate-functions : no yes : propagated ;
feature stack-checking : default force enable : propagated ;

feature addressable-sections : 16 32 : propagated ;
feature code-analysis : no yes : propagated ;
feature consider-fp-exceptions : no yes : propagated ;
feature fp-model : default fast precise strict : propagated ;
feature function-padding : default hotpatch : propagated ;

feature inheritance-model : virtual multiple single : propagated ;
feature pointer-to-member : default class-first : propagated ;

feature aliasing : default none cross-function : propagated ;
feature language-extensions : on off : incidental ;

feature smaller-checks : no yes : propagated ;
feature runtime-checking
  :
    none
    fast
    stack-frame
    uninitialized-locals
  : propagated ;

feature calling-convention : cdecl fastcall stdcall : propagated ;

# List of all registered configurations
.versions = [ new configurations ] ;

# Inherit MIDL flags
# Inherit flags
toolset.inherit-flags msvc : midl ;

# Inherit MC flags
toolset.inherit-flags msvc : mc ;

toolset.inherit-flags msvc : msplatformsdk ;

RM = [ common.rm-command ] ;
nl = "
" ;

# Initialize the toolset for a specific version. As the result, path to
# compiler and, possible, program names are set up, and will be used when
# that version of compiler is requested. For example, you might have:
#
# using msvc : 6.5 : cl.exe ;
# using msvc : 7.0 : Y:/foo/bar/cl.exe ;
#
# The version paramater can be ommited:
#
# using msvc : : Z:/foo/bar/cl.exe ;
#
# Two special version keywords may be supplied:
# - all - all detected versions will be registered;
# - default - this is an equivalent to an empty version.
#
# Depending on a supplied version, detected configurations and presence
# 'cl.exe' in the path different results may be achieved. The following
# table describes all possible cases:
#
# Nothing "x.y"
# Passed Nothing "x.y" detected, detected,
# version detected detected cl.exe in path cl.exe in path
#
# default Error Use "x.y" Create "default" Use "x.y"
# all None Use all None Use all
# x.y - Use "x.y" - Use "x.y"
# a.b Error Error Create "a.b" Create "a.b"
#
# "x.y" - refers to a detected version;
# "a.b" - refers to an undetected version.
#
# Note: for free VC7.1 tools, we don't correctly find vcvars32.bar when user
# explicitly provides a path.
rule init (
    version ? # the msvc version which is being configured. When omitted
            # the tools invoked when no explicit version is given will be configured.
    : command *
    # the command to invoke the compiler. If not specified:
    # - if version is given, default location for that version will be searched
    #
    # - if version is not given, default locations for 7.1, 7.0 and 6.* will
    # be searched
    #
    # - if compiler is not found in default locations, PATH will be searched.
    : options *
    # options can include <setup>, <compiler>, <assembler>, <linker> and <resource-compiler>
)
{
    if $(command)
    {
        options += <command>$(command) ;
    }

    configure $(version) : $(options) ;
}

# 'configure' is a newer version of 'init'. The parameter 'command' is passed as
# a part of the 'options' list.
rule configure (
    version ? :
    options *
    )
{
    switch $(version)
    {
        case all :
            if $(options)
            {
                error "msvc: options should be empty when 'all' is specified" ;
            }

            # use all detected versions
            for local v in [ $(.versions).all ]
            {
                configure-really $(v) ;
            }

        case "default" :
            configure-really : $(options) ;

        case * :
                        configure-really $(version) : $(options) ;
    }
}

# Supported CPU architectures
cpu-arch-i386 =
    <architecture>/<address-model>
    <architecture>/<address-model>32
    <architecture>x86/<address-model>
    <architecture>x86/<address-model>32 ;

cpu-arch-amd64 =
    <architecture>/<address-model>64
    <architecture>x86/<address-model>64 ;

cpu-arch-ia64 =
    <architecture>ia64/<address-model>
    <architecture>ia64/<address-model>64 ;

cpu-arch-arm =
    <architecture>arm4
    <architecture>arm4t
    <architecture>arm5
    <architecture>arm5t
    ;

cpu-arch-mips =
    <architecture>mips4
    ;

cpu-arch-sh =
    <architecture>sh3
    <architecture>sh3dsp
    <architecture>sh4
    <architecture>sh5
    ;
    

local rule configure-really (
    version ? :
    options *
    )
{
    # If no version supplied use the default configuration. Note that condition
    # remains versionless.
    local v = $(version) ;
    if ! $(v)
    {
        # take the first detected version
        version = [ $(.versions).all ] ;
        version = $(version[1]) ;

        # Note: 'version' can still be empty at this point if no versions were
        # detected.
        version ?= "default" ;
    }

    # Version alias -> real version number
    if $(.version-alias-$(version))
    {
        version = $(.version-alias-$(version)) ;
    }
        # Check whether selected configuration is used already
    if $(version) in [ $(.versions).used ]
    {
        # Allow multiple 'toolset.usage' calls for the same configuration
        # if the identical sets of options are used
        if $(options) && ( $(options) != [ $(.versions).get $(version) : options ] )
        {
            error "msvc: the toolset version '$(version)' is configured already" ;
        }
    }
    else
    {
        # Register a new configuration
        $(.versions).register $(version) ;

        # Set new options if any
        if $(options)
        {
            $(.versions).set $(version) : options : $(options) ;
        }
                # Mark the configuration as 'used'.
        $(.versions).use $(version) ;

        # Get auto-detected or user-supplied options
        options = [ $(.versions).get $(version) : options ] ;
                
        # Generate condition and save it
        local condition = [ common.check-init-parameters msvc :
            version $(v) ] ;

        $(.versions).set $(version) : condition : $(condition) ;
                
        local command = [ get-values <command> : $(options) ] ;
                
        # If version is specified, we try to search first in default paths,
        # and only then in PATH.
        command = [ common.get-invocation-command msvc : cl.exe : $(command)
          : [ default-paths $(version) ] : $(version) ] ;

                common.handle-options msvc : $(condition) : $(command) : $(options) ;
            

        if ! $(version)
        {
            # Even if version is not explicitly specified, try to detect the version
            # from the path.
            if [ MATCH "(Microsoft Visual Studio 8)" : $(command) ]
            {
                version = 8.0 ;
            }
            else if [ MATCH "(NET 2003[\/\\]VC7)" : $(command) ]
            {
                version = 7.1 ;
            }
            else if [ MATCH "(Microsoft Visual C\\+\\+ Toolkit 2003)" : $(command) ]
            {
                version = 7.1toolkit ;
            }
            else if [ MATCH "(.NET[\/\\]VC7)" : $(command) ]
            {
                version = 7.0 ;
            }
            else
            {
                version = 6.0 ;
            }
        }

        
        # Generate and register setup command

        local below-8.0 = [ MATCH ^([67]\\.) : $(version) ] ;

        local cpu = i386 ;

        local setup ;
        local setup-option ;

        if $(command)
        {
            command = [ common.get-absolute-tool-path $(command[-1]) ] ;
                        local parent = [ path.make $(command) ] ;
            parent = [ path.parent $(parent) ] ;
            parent = [ path.native $(parent) ] ;
                        
            # setup will be used if the script name has been specified.
            # If setup is not specified, a default script will be used instead.
            setup = [ get-values <setup> : $(options) ] ;

            if ! $(setup)
            {
                if $(below-8.0)
                {
                    setup ?= vcvars32.bat ;
                }
                else
                {
                    setup ?= vcvarsall.bat ;
                }

                # The vccars32.bat is actually in "bin" directory.
                # (except for free VC7.1 tools)
                setup = [ GLOB $(command) $(parent) : $(setup) ] ;
                 
            }

            if $(setup)
            {
                # Note Cygwin to Windows translation
                setup = "\""$(setup[1]:W)"\"" ;

                if ! $(below-8.0)
                {
                    #FRA ADDON
                    #cpu = i386 amd64 ia64 ;
                    #setup-option = x86 x86_amd64 x86_ia64 ;
                    cpu = i386 amd64 ia64 arm ;
                    setup-option = x86 x86_amd64 x86_ia64 arm ;
                    
                }
                
            }
        }

        local prefix = "call " ;
        local suffix = " >nul
" ;
        if ! [ os.name ] in NT
        {
            prefix = "cmd.exe /S /C call " ;
            suffix = " \"&&\" " ;
        }
                
        command = $(prefix)$(setup)" "$(setup-option:E="")$(suffix) ;

        # Setup script is not required in some configurations
        command ?= "" ;
        # Get tool names (if any) and finish setup

        compiler = [ get-values <compiler> : $(options) ] ;
        compiler ?= cl ;
                        
        linker = [ get-values <linker> : $(options) ] ;
        linker ?= link ;

        resource-compiler = [ get-values <resource-compiler> : $(options) ] ;
        resource-compiler ?= rc ;

        assembler = [ get-values <assembler> : $(options) ] ;
        assembler ?= ml ;

        idl-compiler = [ get-values <idl-compiler> : $(options) ] ;
        idl-compiler ?= midl ;

        mc-compiler = [ get-values <mc-compiler> : $(options) ] ;
        mc-compiler ?= mc ;

        
        #FRA ADDON
        #for local i in 1 2 3
        for local i in 1 2 3 4
        
        {
            local c = $(cpu[$(i)]) ;
                        
            if $(c)
            {
                if $(.debug-configuration)
                {
                    ECHO "msvc: condition:"
                        "'$(condition)/$(cond-$(c))',"
                        "command: '$(command[$(i)])'" ;
                }
                                
                local cond = $(condition)/$(cpu-arch-$(c)) ;
                flags msvc.compile .CC $(cond) : $(command[$(i)])$(compiler) ;
                flags msvc.compile .RC $(cond) : $(command[$(i)])$(resource-compiler) ;
                flags msvc.compile .ASM $(cond) : $(command[$(i)])$(assembler) ;
                flags msvc.link .LD $(cond) : $(command[$(i)])$(linker) ;
                flags msvc.archive .LD $(cond) : $(command[$(i)])$(linker) ;
                flags msvc.compile .IDL $(cond) : $(command[$(i)])$(idl-compiler) ;
                flags msvc.compile .MC $(cond) : $(command[$(i)])$(mc-compiler) ;
            }
        }
        if ! $(below-8.0)
        {
            #flags msvc.link MANIFEST $(condition) : "mt -nologo -manifest " ;
            #flags msvc.link OUTPUTRESOURCE $(condition) : "-outputresource:" ;
        }

        # Set version-specific flags
        configure-version-specific $(version) : $(condition) ;
    }
}

# Supported CPU types
cpu-type-g5 = i586 pentium pentium-mmx ;
cpu-type-g6 =
    i686 pentiumpro pentium2 pentium3 pentium3m pentium-m k6 k6-2 k6-3
    winchip-c6 winchip2 c3 c3-2 ;

cpu-type-em64t = prescott nocona ;
cpu-type-amd64 = k8 opteron athlon64 athlon-fx ;

cpu-type-g7 =
    pentium4 pentium4m athlon athlon-tbird athlon-4 athlon-xp athlon-mp
    $(cpu-type-em64t) $(cpu-type-amd64) ;

cpu-type-itanium = itanium itanium1 merced ;
cpu-type-itanium2 = itanium2 mckinley ;

local rule configure-version-specific ( version : condition )
{
    # Starting with versions 7.0, the msvc compiler have the /Zc:forScope
    # and /Zc:wchar_t options that improve C++ standard conformance, but
    # those options are off by default.
    # If we're sure that msvc version is at 7.*, add those options explicitly.
    # We can be sure either if user specified version 7.* explicitly,
    # or if the installation path contain 7.* (this is checked above).
    if ! [ MATCH ^(6\\.) : $(version) ]
    {
        flags msvc.compile CFLAGS $(condition) : /Zc:forScope /Zc:wchar_t ;
        flags msvc.compile.c++ C++FLAGS $(condition) : /wd4675 ;
        
        flags msvc.compile CFLAGS $(condition)/<warnings>all : /Wp64 ; # 64-bit compatibility warning
        flags msvc.compile CFLAGS <fiber-safe-optimization>yes : /GT ;
        flags msvc.compile CFLAGS <function-hooks>enter : /Gh ;
        flags msvc.compile CFLAGS <function-hooks>exit : /GH ;
        flags msvc.compile CFLAGS <function-hooks>both : /Gh /GH ;
        flags msvc.compile CFLAGS <security-checks>yes : /GS ;
        flags msvc.compile CFLAGS <smaller-checks>yes : /RTCc ;
        flags msvc.compile CFLAGS <runtime-checking>fast : /RTCsu ;
        flags msvc.compile CFLAGS <runtime-checking>stack-frame : /RTCs ;
        flags msvc.compile CFLAGS <runtime-checking>uninitialized-locals : /RTCu ;
        flags msvc.compile CFLAGS <architecture>clr/<have-assembly>no : /clr:noAssembly ;
    }
    else # VC6
    {
        flags msvc.compile CFLAGS <function-hooks>enter : /Gh ;
        flags msvc.compile CFLAGS <function-hooks>exit : /Gh ;
        flags msvc.compile CFLAGS <function-hooks>both : /Gh ;
        
    }
    
    #
    # Processor-specific optimization
    #

    if [ MATCH ^([67]\\.) : $(version) ]
    {
        # 8.0 deprecates some of the options
        flags msvc.compile CFLAGS $(condition)/<optimization>speed $(condition)/<optimization>space : /Ogiy /Gs ;
        flags msvc.compile CFLAGS $(condition)/<optimization>speed : /Ot ;
        flags msvc.compile CFLAGS $(condition)/<optimization>space : /Os ;
                
        flags msvc.compile CFLAGS <improve-fp-consistency>yes : /Op ;
        flags msvc.compile CFLAGS <aliasing>none : /Oa ;
        flags msvc.compile CFLAGS <aliasing>cross-function : /Ow ;
                
                
        flags msvc.compile CFLAGS $(condition)/$(cpu-arch-i386)/<instruction-set> : /GB ;
        flags msvc.compile CFLAGS $(condition)/$(cpu-arch-i386)/<instruction-set>i386 : /G3 ;
        flags msvc.compile CFLAGS $(condition)/$(cpu-arch-i386)/<instruction-set>i486 : /G4 ;
        flags msvc.compile CFLAGS $(condition)/$(cpu-arch-i386)/<instruction-set>$(cpu-type-g5) : /G5 ;
        flags msvc.compile CFLAGS $(condition)/$(cpu-arch-i386)/<instruction-set>$(cpu-type-g6) : /G6 ;
        flags msvc.compile CFLAGS $(condition)/$(cpu-arch-i386)/<instruction-set>$(cpu-type-g7) : /G7 ;
        
        
        
        flags msvc.compile CFLAGS <architecture>clr : /clr ;
    }
    else # VC8+
    {
        flags msvc.compile CFLAGS <architecture>clr/<clr>default : /clr ;
        flags msvc.compile CFLAGS <architecture>clr/<clr>cppcli : /clr ;
        flags msvc.compile CFLAGS <architecture>clr/<clr>managed : /clr:oldSyntax ;
        flags msvc.compile CFLAGS <architecture>clr/<pure-clr>yes : /clr:pure ;
        flags msvc.compile CFLAGS <architecture>clr/<safe-clr>yes : /clr:safe ;
        flags msvc.compile CFLAGS <architecture>clr/<initial-app-domain>yes : /clr:initialAppDomain ;

        flags msvc.compile CFLAGS <consider-fp-exceptions>yes : /fp:except ;
        flags msvc.compile CFLAGS <fp-model>fast : /fp:fast ;
        flags msvc.compile CFLAGS <fp-model>precise : /fp:precise ;
        flags msvc.compile CFLAGS <fp-model>strict : /fp:strict ;
        flags msvc.compile CFLAGS <function-padding>hotpatch : /hotpatch ;
        flags msvc.compile CFLAGS <code-analysis>yes : /analyse ;
        flags msvc.compile CFLAGS <addressable-sections>32 : /bigobj ;
        
    }
}

# Returns the default installation path for the given version.
local rule default-path ( version )
{
    # Use auto-detected path if possible
    local path = [ get-values <command> :
        [ $(.versions).get $(version) : options ] ] ;

    if $(path)
    {
        path = $(path:D) ;
    }
    else
    {
        # Check environment
        if $(.version-$(version)-env)
        {
            local vc-path = [ os.environ $(.version-$(version)-env) ] ;
            if $(vc-path)
            {
                vc-path = [ path.make $(vc-path) ] ;
                vc-path = [ path.join $(vc-path) $(.version-$(version)-envpath) ] ;
                vc-path = [ path.native $(vc-path) ] ;

                path = $(vc-path) ;
            }
        }

        # Check default path
        if ! $(path) && $(.version-$(version)-path)
        {
            path = [ path.native [ path.join $(.ProgramFiles) $(.version-$(version)-path) ] ] ;
        }
    }

    return $(path) ;
}

# Returns either the default installation path (if 'version' is not empty) or list of all
# known default paths (if no version is given)
rule default-paths ( version ? )
{
    local possible-paths ;
    
    if $(version)
    {
        default-path += [ default-path $(version) ] ;
    }
    else
    {
        for local i in $(.known-versions)
        {
            default-path += [ default-path $(i) ] ;
        }
    }

    return $(possible-paths) ;
}

# Declare generators

# is it possible to combine these?
# make the generators non-composing, so that they don't convert each source
# into separate rsp file.
generators.register-linker msvc.link : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB : EXE : <toolset>msvc ;
generators.register-linker msvc.link.dll : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB : SHARED_LIB IMPORT_LIB : <toolset>msvc ;

generators.register-linker msvc.link.resource-dll : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB : SHARED_LIB : <toolset>msvc <resource-only>yes ;
generators.override msvc.link.resource-dll : msvc.link.dll ;

generators.register-archiver msvc.archive : OBJ : STATIC_LIB : <toolset>msvc ;
generators.register-c-compiler msvc.compile.c++ : CPP : OBJ : <toolset>msvc ;
generators.register-c-compiler msvc.compile.c : C : OBJ : <toolset>msvc ;

# Using 'register-c-compiler' adds the build directory to INCLUDES
generators.register-c-compiler msvc.compile.rc : RC : OBJ(%_res) : <toolset>msvc ;
generators.override msvc.compile.rc : rc.resource-compile ;
generators.register-standard msvc.compile.asm : ASM : OBJ : <toolset>msvc ;

generators.register-c-compiler msvc.compile.idl : IDL : MSTYPELIB H C(%_i) C(%_proxy) C(%_dlldata) : <toolset>msvc ;
generators.override msvc.compile.idl : midl.compile.idl ;

generators.register-standard msvc.compile.mc : MC : H RC : <toolset>msvc ;
generators.override msvc.compile.mc : mc.compile ;

generators.register [ new pch-generator msvc.compile.pch : PCHEADER : OBJ PCH : <toolset>msvc ] ;

#
# Declare flags and action for compilation
#

#feature.feature debug-store : object database : propagated ;

flags msvc.compile CFLAGS <optimization>speed : /O2 ;
flags msvc.compile CFLAGS <optimization>space : /O1 ;

flags msvc.compile CFLAGS <optimize-for-windows>yes : /GA ;

flags msvc.compile CFLAGS <string-pooling>yes : /GF ;
flags msvc.compile CFLAGS <debug-symbols>on/<debug-store>database/<minimal-rebuild>yes : /Gm ;
flags msvc.compile CFLAGS <stack-checking>force : /Ge ;
flags msvc.compile CFLAGS <stack-checking>enable : /Gs0 ;
flags msvc.compile CFLAGS <language-extensions>off : /Za ;
flags msvc.compile CFLAGS <calling-convention>cdecl : /Gd ;
flags msvc.compile CFLAGS <calling-convention>fastcall : /Gr ;
flags msvc.compile CFLAGS <calling-convention>stdcall : /Gz ;

flags msvc.compile CFLAGS <inheritance-model>virtual : /vmv ;
flags msvc.compile CFLAGS <inheritance-model>multiple : /vmm ;
flags msvc.compile CFLAGS <inheritance-model>single : /vms ;
flags msvc.compile CFLAGS <pointer-to-member>default : /vmg ;
flags msvc.compile CFLAGS <pointer-to-member>class-first : /vmb ;
 

flags msvc.compile CFLAGS $(cpu-arch-amd64)/<instruction-set> : /favor:blend ;
flags msvc.compile CFLAGS $(cpu-arch-amd64)/<instruction-set>$(cpu-type-em64t) : /favor:EM64T ;
flags msvc.compile CFLAGS $(cpu-arch-amd64)/<instruction-set>$(cpu-type-amd64) : /favor:AMD64 ;

flags msvc.compile CFLAGS $(cpu-arch-ia64)/<instruction-set>$(cpu-type-itanium) : /G1 ;
flags msvc.compile CFLAGS $(cpu-arch-ia64)/<instruction-set>$(cpu-type-itanium2) : /G2 ;

flags msvc.compile CFLAGS <debug-symbols>on/<debug-store>object : /Z7 ;
flags msvc.compile CFLAGS <debug-symbols>on/<debug-store>database : /Zi ;

flags msvc.compile CFLAGS $(cpu-arch-i386)/<debug-symbols>on/<debug-store>edit-and-continue : /ZI ;
flags msvc.compile CFLAGS <debug-symbols>on/<debug-store>lines-only : /Zd ;

flags msvc.compile CFLAGS <optimization>off : /Od ;
flags msvc.compile CFLAGS <inlining>off : /Ob0 ;
flags msvc.compile CFLAGS <inlining>on : /Ob1 ;
flags msvc.compile CFLAGS <inlining>full : /Ob2 ;

flags msvc.compile CFLAGS <alignment>1 : /Zp1 ;
flags msvc.compile CFLAGS <alignment>2 : /Zp2 ;
flags msvc.compile CFLAGS <alignment>4 : /Zp4 ;
flags msvc.compile CFLAGS <alignment>8 : /Zp8 ;
flags msvc.compile CFLAGS <alignment>16 : /Zp16 ;

flags msvc.compile CFLAGS <warnings>on : /W3 ;
flags msvc.compile CFLAGS <warnings>off : /W0 ;
flags msvc.compile CFLAGS <warnings>all : /W4 ;
flags msvc.compile CFLAGS <warnings-as-errors>on : /WX ;

flags msvc.compile C++FLAGS <exception-handling>on/<asynch-exceptions>off/<extern-c-nothrow>off : /EHs ;
flags msvc.compile C++FLAGS <exception-handling>on/<asynch-exceptions>off/<extern-c-nothrow>on : /EHsc ;
flags msvc.compile C++FLAGS <exception-handling>on/<asynch-exceptions>on/<extern-c-nothrow>off : /EHa ;
flags msvc.compile C++FLAGS <exception-handling>on/<asynch-exceptions>on/<extern-c-nothrow>on : /EHac ;

flags msvc.compile CFLAGS <rtti>on : /GR ;
flags msvc.compile CFLAGS <runtime-debugging>off/<runtime-link>shared : /MD ;
flags msvc.compile CFLAGS <runtime-debugging>on/<runtime-link>shared : /MDd ;

flags msvc.compile CFLAGS <runtime-debugging>off/<runtime-link>static/<threading>single : /ML ;
flags msvc.compile CFLAGS <runtime-debugging>on/<runtime-link>static/<threading>single : /MLd ;
flags msvc.compile CFLAGS <runtime-debugging>off/<runtime-link>static/<threading>multi : /MT ;
flags msvc.compile CFLAGS <runtime-debugging>on/<runtime-link>static/<threading>multi : /MTd ;

flags msvc.compile USER_CFLAGS <cflags> : ;
flags msvc.compile.c++ USER_CFLAGS <cxxflags> : ;

flags msvc.compile PDB_CFLAG <debug-symbols>on/<debug-store>database : /Fd ; # not used yet

# CPU architecture and general windows version:
flags msvc.compile CFLAGS $(cpu-arch-i386) : /DWIN32 /DX86 /D_X86_ ;
flags msvc.compile CFLAGS $(cpu-arch-ia64) : /DWIN64 /DIA64 /D_IA64_ ;
flags msvc.compile CFLAGS $(cpu-arch-amd64) : /DWIN64 /DAMD64 /D_AMD64_ ;
#FRA ADDON
flags msvc.compile CFLAGS $(cpu-arch-arm) : /DBOOST_USE_WINDOWS_H /DWINCE /DARM /D_ARM_ /D_M_ARM /D_WIN32_WCE=0x420 /DUNDER_CE /DWIN32_PLATFORM_PSPC /DWINCE /D_UNICODE /DUNICODE /DTLS_OUT_OF_INDEXES=0xffffffff ;
#END
flags msvc.compile CFLAGS $(cpu-arch-sh) : /DWINCE ;
flags msvc.compile CFLAGS $(cpu-arch-mips) : /DWINCE ;

flags msvc.compile DEFINES <define> ;
flags msvc.compile UNDEFS <undef> ;
flags msvc.compile INCLUDES <include> ;

flags msvc.compile PCH_SOURCE <pch-source> ;
flags msvc.compile PCH_HEADER <pch>on : <pch-header> ;
flags msvc.compile PCH_FILE <pch>on : <pch-file> ;

rule compile.c ( targets + : sources * : properties * )
{
    DEPENDS $(<) : [ on $(<) return $(PCH_HEADER) ] ;
    DEPENDS $(<) : [ on $(<) return $(PCH_FILE) ] ;
}

rule compile.c++ ( targets + : sources * : properties * )
{
    DEPENDS $(<) : [ on $(<) return $(PCH_HEADER) ] ;
    DEPENDS $(<) : [ on $(<) return $(PCH_FILE) ] ;
}

rule compile.pch ( targets + : sources * : properties * )
{
    DEPENDS $(<) : [ on $(<) return $(PCH_SOURCE) ] ;
}

# The actions differ only by explicit selection of input language
actions compile.c bind PCH_HEADER PCH_FILE
{
    $(.CC) /Zm800 -nologo -TC -U$(UNDEFS) $(CFLAGS) $(USER_CFLAGS) @"@($(<[1]:W).rsp:E=$(nl)"$(>)" $(nl)-D$(DEFINES) $(nl)"-I$(INCLUDES)")" -c -Fo"$(<[1]:W)" -Yu"$(PCH_HEADER:D=)" -Fp"$(PCH_FILE:W)"
}

actions compile.c++ bind PCH_HEADER PCH_FILE
{
    echo using the following compiler options (action compile.c++):
    echo $(C++FLAGS)
    echo $(CFLAGS)
    echo end
    
    $(.CC) /Zm800 -nologo -TP -U$(UNDEFS) $(CFLAGS) $(C++FLAGS) $(USER_CFLAGS) @"@($(<[1]:W).rsp:E=$(nl)"$(>)" $(nl)-D$(DEFINES) $(nl)"-I$(INCLUDES)")" -c -Fo"$(<[1]:W)" -Yu"$(PCH_HEADER:D=)" -Fp"$(PCH_FILE:W)"
}

actions compile.pch bind PCH_SOURCE
{
    $(.CC) /Zm800 -nologo -TP -U$(UNDEFS) $(CFLAGS) $(C++FLAGS) $(USER_CFLAGS) @"@($(<[1]:W).rsp:E=$(nl)"$(PCH_SOURCE:W)" $(nl)-D$(DEFINES) $(nl)"-I$(INCLUDES)")" -c -Fo"$(<[1]:W)" /Yc"$(>[1]:D=)" -Yl__bjam_pch_symbol -Fp"$(<[2]:W)"
    
}

actions compile.rc
{
    $(.RC) -l 0x409 -U$(UNDEFS) -D$(DEFINES) -I"$(INCLUDES)" -fo "$(<:W)" "$(>:W)"
}

TOUCH_FILE = [ midl.file-touch-command ] ;

actions compile.idl
{
    $(.IDL) /nologo @"@($(<[1]:W).rsp:E=$(nl)"$(>:W)" $(nl)-D$(DEFINES) $(nl)"-I$(INCLUDES)" $(nl)-U$(UNDEFS) $(nl)$(MIDLFLAGS) $(nl)/tlb "$(<[1]:W)" $(nl)/h "$(<[2]:W)" $(nl)/iid "$(<[3]:W)" $(nl)/proxy "$(<[4]:W)" $(nl)/dlldata "$(<[5]:W)")"
    $(TOUCH_FILE) "$(<[4]:W)"
    $(TOUCH_FILE) "$(<[5]:W)"
}

# Declare flags and action for the assembler

flags msvc.compile.asm USER_ASMFLAGS <asmflags> : ;

#
# for the assembler the following options are turned on by default:
#
# -coff generate COFF format object file (compatible with cl.exe output)
# -Zp4 align structures to 4 bytes
# -Cp preserve case of user identifiers
# -Cx preserve case in publics, externs

flags msvc.compile ASMFLAGS <alignment>1 : /Zp1 ;
flags msvc.compile ASMFLAGS <alignment>2 : /Zp2 ;
flags msvc.compile ASMFLAGS <alignment>4 : /Zp4 ;
flags msvc.compile ASMFLAGS <alignment>8 : /Zp8 ;
flags msvc.compile ASMFLAGS <alignment>16 : /Zp16 ;

actions compile.asm
{
    
    $(.ASM) -nologo -c -coff -Cp -Cx $(ASMFLAGS) $(USER_ASMFLAGS) -Fo "$(<:W)" "$(>:W)"
    
}

# Declare flags and action for linking
flags msvc.link PDB_LINKFLAG <debug-symbols>on/<debug-store>database : /PDB: ; # not used yet
flags msvc.link LINKFLAGS <debug-symbols>on : /DEBUG ;

flags msvc.link LINKFLAGS <debug-symbols>off : /RELEASE ;

flags msvc.link DEF_FILE <def-file> ;
# The linker disables the default optimizations when using /DEBUG. Whe have
# to enable them manually for release builds with debug symbols.
flags msvc LINKFLAGS <debug-symbols>on/<runtime-debugging>off : /OPT:REF,ICF ;

#FRA ADDON
flags msvc LINKFLAGS <user-interface>console : /subsystem:console ;
#END
flags msvc LINKFLAGS <user-interface>gui : /subsystem:windows ;
flags msvc LINKFLAGS <user-interface>wince : /subsystem:windowsce ;
flags msvc LINKFLAGS <user-interface>native : /subsystem:native ;
flags msvc LINKFLAGS <user-interface>auto : /subsystem:posix ;

flags msvc LINKFLAGS <main-target-type>LIB/<link>shared : /DLL ;

flags msvc LINKFLAGS <main-target-type>LIB/<link>shared/<resource-only>yes : /noentry ;

# CPU architecture:
flags msvc LINKFLAGS $(cpu-arch-i386) : -machine:x86 ;
flags msvc LINKFLAGS $(cpu-arch-ia64) : -machine:ia64 ;
flags msvc LINKFLAGS $(cpu-arch-amd64) : -machine:amd64 ;
#FRA ADDON
flags msvc LINKFLAGS $(cpu-arch-arm) : -machine:arm ccrtrtti.lib ;
#END
flags msvc LINKFLAGS $(cpu-arch-mips) : -machine:mips ;
flags msvc LINKFLAGS <architecture>sh3 : -machine:sh3 ;
flags msvc LINKFLAGS <architecture>sh3dsp : -machine:sh3dsp ;
flags msvc LINKFLAGS <architecture>sh4 : -machine:sh4 ;
flags msvc LINKFLAGS <architecture>sh5 : -machine:sh5 ;
 

flags msvc.link USER_LINKFLAGS <linkflags> ;
flags msvc.link LINKPATH <library-path> ;

flags msvc.link FINDLIBS_ST <find-static-library> ;
flags msvc.link FINDLIBS_SA <find-shared-library> ;
flags msvc.link LIBRARY_OPTION <toolset>msvc : "" : unchecked ;
flags msvc.link LIBRARIES_MENTIONED_BY_FILE : <library-file> ;

rule link.dll ( targets + : sources * : properties * )
{
    DEPENDS $(<) : [ on $(<) return $(DEF_FILE) ] ;
}

rule link.resource-dll ( targets + : sources * : properties * )
{
    DEPENDS $(<) : [ on $(<) return $(DEF_FILE) ] ;
}

# Declare action for creating static libraries
# If library exists, remove it before adding files. See
# http://article.gmane.org/gmane.comp.lib.boost.build/4241
# for rationale.
if [ os.name ] in NT
{
    # The 'DEL' command would issue a message to stdout
    # if the file does not exist, so need a check.
    actions archive
    {
        if exist "$(<[1])" DEL "$(<[1])"
        $(.LD) /lib /NOLOGO /out:"$(<[1])" @"@($(<[1]:W).rsp:E=$(nl)"$(>)" $(nl)$(LIBRARIES_MENTIONED_BY_FILE) $(nl)"$(LIBRARY_OPTION)$(FINDLIBS_ST:S=.lib)" $(nl)"$(LIBRARY_OPTION)$(FINDLIBS_SA:S=.lib)")"
    }
}
else
{
    actions archive
    {
        $(RM) "$(<[1])"
        $(.LD) /lib /NOLOGO /out:"$(<[1])" @"@($(<[1]:W).rsp:E=$(nl)"$(>)" $(nl)$(LIBRARIES_MENTIONED_BY_FILE) $(nl)"$(LIBRARY_OPTION)$(FINDLIBS_ST:S=.lib)" $(nl)"$(LIBRARY_OPTION)$(FINDLIBS_SA:S=.lib)")"
    }
}
        
# incremental linking a DLL causes no end of problems: if the
# actual exports don't change, the import .lib file is never
# updated. Therefore, the .lib is always out-of-date and gets
# rebuilt every time. I'm not sure that incremental linking is
# such a great idea in general, but in this case I'm sure we
# don't want it.

# Windows Manifests is a new way to specify dependencies
# on managed DotNet assemblies and Windows native DLLs. The
# manifests are embedded as resourses and are useful in
# any PE targets (both DLL and EXE)

actions link bind DEF_FILE
{
    
    $(.LD) /NOLOGO $(LINKFLAGS) /out:"$(<[1]:W)" /INCREMENTAL:NO /LIBPATH:"$(LINKPATH:W)" $(USER_LINKFLAGS) @"@($(<[1]:W).rsp:E=$(nl)"$(>)" $(nl)$(LIBRARIES_MENTIONED_BY_FILE) $(nl)"$(LIBRARY_OPTION)$(FINDLIBS_ST:S=.lib)" $(nl)"$(LIBRARY_OPTION)$(FINDLIBS_SA:S=.lib)")"
    
    $(MANIFEST)$(<[1]).manifest $(OUTPUTRESOURCE)$(<[1]);1
}

actions link.dll bind DEF_FILE
{
   $(.LD) /NOLOGO $(LINKFLAGS) /out:"$(<[1]:W)" /INCREMENTAL:NO /IMPLIB:"$(<[2]:W)" /LIBPATH:"$(LINKPATH:W)" /def:$(DEF_FILE) $(USER_LINKFLAGS) @"@($(<[1]:W).rsp:E=$(nl)"$(>)" $(nl)$(LIBRARIES_MENTIONED_BY_FILE) $(nl)"$(LIBRARY_OPTION)$(FINDLIBS_ST:S=.lib)" $(nl)"$(LIBRARY_OPTION)$(FINDLIBS_SA:S=.lib)")"
   $(MANIFEST)$(<[1]).manifest $(OUTPUTRESOURCE)$(<[1]);2
}
actions link.resource-dll bind DEF_FILE
{
    $(.LD) /NOLOGO $(LINKFLAGS) /out:"$(<[1]:W)" /INCREMENTAL:NO /IMPLIB:"$(<[2]:W)" /LIBPATH:"$(LINKPATH:W)" /def:$(DEF_FILE) $(USER_LINKFLAGS) @"@($(<[1]:W).rsp:E=$(nl)"$(>)" $(nl)$(LIBRARIES_MENTIONED_BY_FILE) $(nl)"$(LIBRARY_OPTION)$(FINDLIBS_ST:S=.lib)" $(nl)"$(LIBRARY_OPTION)$(FINDLIBS_SA:S=.lib)")"
    $(MANIFEST)$(<[1]).manifest $(OUTPUTRESOURCE)$(<[1]);2
    
}

actions compile.mc
{
    $(.MC) $(MCFLAGS) -h "$(<[1]:DW)" -r "$(<[2]:DW)" "$(>:W)"
}

#
# Autodetection code
# detects versions listed as '.known-versions' using registry, environment
# and checking default paths. Supports both native Windows and Cygwin.
#

.ProgramFiles = [ path.make [ common.get-program-files-dir ] ] ;

.known-versions = 8.0 8.0express 7.1 7.1toolkit 7.0 6.0 ;

# Version aliases
.version-alias-6 = 6.0 ;
.version-alias-7 = 7.0 ;
.version-alias-8 = 8.0 ;
 
# Name of the registry key that contains Visual C++ installation path
# (relative to "HKEY_LOCAL_MACHINE\SOFTWARE\\Microsoft"
.version-6.0-reg = "VisualStudio\\6.0\\Setup\\Microsoft Visual C++" ;
.version-7.0-reg = "VisualStudio\\7.0\\Setup\\VC" ;
.version-7.1-reg = "VisualStudio\\7.1\\Setup\\VC" ;
.version-8.0-reg = "VisualStudio\\8.0\\Setup\\VC" ;
.version-8.0express-reg = "VCExpress\\8.0\\Setup\\VC" ;

# Visual C++ Toolkit 2003 do not store its installation path in the registry.
# The environment variable 'VCToolkitInstallDir' and the default installation
# path will be checked instead.
.version-7.1toolkit-path = "Microsoft Visual C++ Toolkit 2003" "bin" ;
.version-7.1toolkit-env = VCToolkitInstallDir ;

# Path to the folder containing "cl.exe" relative to the value of the corresponding
# environment variable
.version-7.1toolkit-envpath = "bin" ;

# Validates given path, registers found configuration and prints debug information
# about it.
local rule register-configuration ( version : path ? )
{
    if $(path)
    {
        local command = [ GLOB $(path) : cl.exe ] ;

        if $(command)
        {
            if $(.debug-configuration)
            {
                ECHO "notice: msvc-$(version) detected, command: '$(command)'" ;
            }

            $(.versions).register $(version) ;
            $(.versions).set $(version) : options : <command>$(command) ;
        }
    }
}

if [ os.name ] in NT CYGWIN
{
    # Get installation paths from the registry

    for local i in $(.known-versions)
    {
        if $(.version-$(i)-reg)
        {
            local vc-path = [ W32_GETREG
                "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"$(.version-$(i)-reg)
                : "ProductDir" ] ;
            
            if $(vc-path)
            {
                vc-path = [ path.native [ path.join [ path.make-NT $(vc-path) ] "bin" ] ] ;
                register-configuration $(i) : $(vc-path) ;
            }
        }
    }
}

# Check environment and default installation paths

for local i in $(.known-versions)
{
    if ! $(i) in [ $(.versions).all ]
    {
        register-configuration $(i) : [ default-path $(i) ] ;
    }
}


Boost-Build list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk