⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 generators.jam

📁 boost库提供标准的C++ API 配合dev c++使用,功能更加强大
💻 JAM
📖 第 1 页 / 共 3 页
字号:
        }        
    }    
}



local rule try-one-generator ( project name ? : generator multiple ? : 
    target-type : property-set : sources * )
{
    local targets =
      [ $(generator).run $(project) $(name)
                       : $(property-set)
                       : $(sources)
                       : $(multiple)
      ] ;

    # Generated targets that are of required types
    local result ;
    # Generated target of other types.
    local extra ;

    base-to-derived-type-conversion $(targets) : $(target-type) 
        : result extra ;
            
    # Now try to convert extra targets 
    # 'construct' will to its best to return only requested
    # target types, so if we receive any extra from that call,
    # we don't try to do anything about them.
    local extra2 ;
    if $(multiple) 
    {
        for local e in $(extra) 
        {
            local try2 = [ construct-types $(project) $(name) 
                                         : $(target-type)
                                         :
                                         : $(property-set)
                                         : $(e) ] ;
    
            result += $(try2) ;
        }    
    }
    else
    {
        extra2 = $(extra) ;
    }
    generators.dout [ indent ] "  generator" [ $(generator).id ] " spawned " ;
    generators.dout [ indent ] " " $(result) -- $(extra2) ; 
    return $(result) $(extra2) ;                     
}

rule construct-types ( project name ? : target-types + : multiple ? : 
    property-set : sources + )
{
    local result ;
    local matched-types ; 
    for local t in $(target-types)
    {
        local r = [ construct $(project) $(name) : $(t) $(multiple) : $(property-set) :
          $(sources) ] ;
        if $(r)
        {
            result += $(r) ;
            matched-types += $(t) ;
        }
    }
    # TODO: have to introduce parameter controlling if
    # several types can be matches and add appropriate
    # checks 

    # TODO: need to review the documentation for
    # 'construct' to see if it should return $(source) even
    # if nothing can be done with it. Currents docs seem to
    # imply that, contrary to the behaviour.
    if $(result)
    {
        return $(result) ;
    }
    else
    {
        return $(sources) ;
    }
}

# Ensures all 'targets' have types. If this is not so, exists with 
# error.
local rule ensure-type ( targets * )
{
    for local t in $(targets)
    {
        if ! [ $(t).type ]
        {
            errors.error "target" [ $(t).str ] "has no type" ;
        }        
    }    
}

    
# Returns generators which can be used to construct target of specified type
# with specified properties. Uses the following algorithm:
# - iterates over requested target-type and all it's bases (in the order returned bt
#   type.all-bases.
# - for each type find all generators that generate that type and which requirements
#   are satisfied by properties.
# - if the set of generators is not empty, returns that set.
#
# Note: this algorithm explicitly ignores generators for base classes if there's
# at least one generator for requested target-type.
local rule find-viable-generators ( target-type : property-set )
{
    # Select generators that can create the required target type.
    local viable-generators = ;
    local generator-rank = ;

    import type ;
    # Try all-type generators first. Assume they have
    # quite specific requirements.
    local t = * [ type.all-bases $(target-type) ] ;
    
    generators.dout  [ indent ] find-viable-generators target-type= $(target-type) 
      property-set= [ $(property-set).as-path ]
          ;
    
    while $(t[1])
    {
        generators.dout  [ indent ] "trying type" $(t[1]) ;
        for local g in $(.generators.$(t[1]))
        {
            generators.dout [ indent ] "trying generator" [ $(g).id ] "(" [ $(g).source-types ] -> [ $(g).target-types ] ")" ;
            
            # Avoid trying the same generator twice on different levels.
            if ! $(g) in $(.active-generators) 
            {       
                local m = [ $(g).match-rank $(property-set) ] ;
                if $(m) 
                {
                    generators.dout [ indent ] "  matched with rank" $(m) ;
                    viable-generators += $(g) ;
                    generator-rank += $(m) ;
                    t = ;
                }                                    
            }            
        }
        t = $(t[2-]) ;
    }
    
    return [ sequence.select-highest-ranked $(viable-generators) : $(generator-rank) ] ;        
}
    
# Given a vector of vectors, of of them represents results of running some 
# generator, returns the 'best' result, it it exists. Otherwise, exit with
# and error. Result is returned as plain jam list.
local rule select-dependency-graph ( options )
{
    if [ $(options).size ] = 0
    {
        return ;
    }
    else if [ $(options).size ] = 1
    {
        return [ $(options).get-at 1 ] ;
    }
    else
    {
        # We have several alternatives and need to check if they
        # are the same. 
        
        for local r in [ $(options).get ] 
        {
            normalize-target-list $(r) ;
            generators.dout $(r) ;
        }
        
        local f = [ $(options).at 1 ] ;
        local mismatch ;
        for local r in [ $(results).get ] 
        {
            if ! [ utility.equal $(r) $(f) ] 
            {
                mismatch = true ;
            }
        }

        if ! $(mismatch)
        {
            return [ $(f).get ] ;
        }
        else 
        {                        
            error [ $(options).size ] "possible generations for "
                   $(target-types) "Can't handle this now." ;
        }            
    }                        
}
    
.construct-stack = ;

# Attempt to construct the target by looking at transformation cache.
local rule construct-with-caching (
   project name ? : target-type multiple ? : property-set : sources * )
{     
    local result ;
    # Caching is only possible when we're not computing cacheable transformation
    # already, when there's only one source which has no action -- i.e. source file,
    # and name of target is not specified.
    if ! $(.caching) && ! $(sources[2]) && $(sources[1]) && ! $(name)      
       && ! [ $(sources[1]).action ] 
    {
        local .caching = true ;
        
        local t = $(sources[1]) ;            
                    
        local signature = [ sequence.join [ $(t).type ] $(target-type) $(property-set) : - ] ;
            
        # Get a transformation template from cache or create it.
        local cresult ;
        if $(.transformation.cache.$(signature))
        {
            cresult = $(.transformation.cache.$(signature)) ;
        }
        else 
        {                            
            local ut = [ new file-target % : [ $(t).type ] : "no project" ] ;            
            cresult = [ construct $(project) : $(target-type) $(multiple) 
              : $(property-set) : $(ut) ] ;
            .transformation.cache.$(signature) = $(cresult) ;                
        }
                                    
        # Substitute the real source name in the transformation template.
        if $(cresult)
        {                
            generators.dout [ indent ] "*** putting to cache?" ;
            for local c in $(cresult)
            {
                local cc = [ virtual-target.clone-template $(c) : $(t) : $(project) ] ;
                generators.dout [ indent ] "*** cloning " $(c) ;
                generators.dout [ indent ] "*** cloned" $(cc) --- $(cc) ;
                result += $(cc) ;
            }
        }    
    }
    return $(result) ;
}

# Attempts to construct target by finding viable generators, running them
# and selecting the dependency graph
local rule construct-without-caching (
   project name ? : target-type multiple ? : property-set : sources * )
{
    viable-generators = [ find-viable-generators $(target-type) : $(property-set) ] ;
                    
    local results = [ new vector ] ;
    
    generators.dout [ indent ] "*** " [ sequence.length $(viable-generators) ] 
      " viable generators" ;
    
    for local g in $(viable-generators)
    {
        # This variable will be restored on exit from this scope.
        local .active-generators = $(g) $(.active-generators) ;
        
        local r = [ try-one-generator $(project) $(name) : $(g) $(multiple) : $(target-type) :
          $(property-set) : $(sources) ] ;
        
        if $(r)
        {
            $(results).push-back [ new vector $(r) ] ;
        }
    }
    
    return [ select-dependency-graph $(results) ] ;
}       
    
        
# Attempts to create target of 'target-type' with 'properties'
# from 'sources'. The 'sources' are treated as a collection of
# *possible* ingridients -- i.e. it is not required to consume
# them all. If 'multiple' is true, the rule is allowed to return
# several targets of 'target-type'.          
#
#
# Returns a list of target. When this invocation is first instance of
# 'construct' in stack, returns only targets of requested 'target-type',
# otherwise, returns also unused sources and additionally generated
# targets.    
#
# Does not return target which are not of 'allowed-type' or of type derived from
# it. If 'allowed-type' is not specified, it's defaulted to 'target-type'.
# See lib-target-class for use case of this.
rule construct ( project name ? : target-type multiple ? : property-set * : sources * 
   : allowed-type * )
{
    allowed-type ?= $(target-type) ;
    if (.construct-stack)
    {
        ensure-type $(sources) ;
    }
    
    .construct-stack += 1 ;

    increase-indent ;
    
    local m ;
    if $(multiple)
    {
        m = "(may return multiple targets)" ;
    }
    generators.dout [ indent ] "*** construct" $(target-type) $(m) ;
    
    for local s in $(sources)
    {
        generators.dout [ indent ] "    from" $(s) ;
    }
    generators.dout [ indent ] "    properties:" [ $(property-set).raw ] ;        
               
    local result = [ construct-with-caching $(project) $(name)  
      : $(target-type) $(multiple) : $(property-set) : $(sources) ] ;
    
    if ! $(result)  {
        result = [ construct-without-caching $(project) $(name)  
      : $(target-type) $(multiple) : $(property-set) : $(sources) ] ;
    }
                    
    decrease-indent ;
        
    .construct-stack = $(.construct-stack[2-]) ;

    if ! $(.construct-stack) && $(allowed-type) != * # This is first invocation in stack
    {
        local result2 ;
        for local t in $(result)
        {
            local type = [ $(t).type ] ; 
            assert.nonempty-variable type ;
            assert.nonempty-variable target-type ;
            
            # Return only targets of the requested type, unless 'return-all'
            # is specified. If we don't do this, then all targets calling
            # 'construct' will get unused target returned, which will break
            # checking for unused sources a bit harder.
            if $(type) = $(target-type) || [ type.is-derived $(type) $(allowed-type) ]
            {
                  result2 += $(t) ;
            }
        }                
        return $(result2) ;
    } 
    else
    {                            
        return $(result) ;        
    }        
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -