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

📄 toolset.jam

📁 C++的一个好库。。。现在很流行
💻 JAM
字号:
#  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.

#  Support for toolset definition.

import feature ;
import numbers ;
import errors : error ;
import property ;
import path ;
import generators ;
import set : difference ;
import regex ;
import sequence ;

.flag-no = 1 ;

# Initializes an additional toolset-like module.
# First load 'toolset-module' and then calls its 'init'
# rule with trailing arguments
rule using ( toolset-module : * )
{
    import $(toolset-module) ;
    if ! $(.$(toolset-module)-init-callled)
    {        
        $(toolset-module)-init-callled = true ;
        $(toolset-module).init $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
    }    
}

# Expands subfeatures in each property sets.
# e.g
# <toolset>gcc-3.2
# will be converted to
# <toolset>gcc/<toolset-version>3.2
local rule normalize-condition ( property-sets * )
{
    local result ;
    for local p in $(property-sets)
    {
        local split = [ feature.split $(p) ] ;
        local expanded = [ feature.expand-subfeatures [ feature.split $(p) ] ] ;
        result += $(expanded:J=/) ;
    }
    return $(result) ;
}


# Specifies the flags (variables) that must be set on targets under certain
# conditions, described by arguments.
rule flags ( rule-or-module   # If contains dot, should be a rule name.
                              # The flags will be applied when that rule is
                              # used to set up build actions.
                              #
                              # If does not contain dot, should be a module name.
                              # The flags will be applied for all rules in that
                              # module.
                              # If module for rule is different from the calling
                              # module, an error is issued.
    
             variable-name    # Variable that should be set on target
             condition * :    # A condition when this flag should be applied.
                              # Should be set of property sets. If one of
                              # those property sets is contained in build
                              # properties, the flag will be used.
                              # Implied values are not allowed:
                              # "<toolset>gcc" should be used, not just
                              # "gcc". Subfeatures, like in "<toolset>gcc-3.2"
                              # are allowed. If left empty, the flag will
                              # always used.


             values * :       # The value to add to variable. If <feature>
                              # is specified, then the value of 'feature' 
                              # will be added.
             unchecked ?      # If value 'unchecked' is passed, will not test
                              # that flags are set for the calling module.
          )
{
    local module_ = [ MATCH "([^.]*).*" : $(rule-or-module) ] ;
    local caller = [ CALLER_MODULE ] ;
    if $(unchecked) != unchecked && $(module_) != $(caller)
    {
        errors.error "Module $(caller) attempted to set flags for module $(module_)" ;
    }
    
    if $(condition) && ! $(condition:G=)
    {
        # We have condition in the form '<feature>', that is, without
        # value. That's a previous syntax:
        #
        #   flags gcc.link RPATH <dll-path> ;
        # for compatibility, convert it to
        #   flags gcc.link RPATH : <dll-path> ;                
        values = $(condition) ;
        condition = ;
    }
    
    if $(condition)
    {
        property.validate-property-sets $(condition) ;
        condition = [ normalize-condition $(condition) ] ;
    }
    
    add-flag $(rule-or-module) : $(variable-name)
      : $(condition) : $(values) ;
}

# Adds new flag setting with the specified values
# Does no checking
local rule add-flag ( rule-or-module :
    variable-name : condition * : values * )
{
    .$(rule-or-module).flags += $(.flag-no) ;

    # Store all flags for a module
    local module_ = [ MATCH "([^.]*).*" : $(rule-or-module) ] ;    
    .module-flags.$(module_) += $(.flag-no) ;
    # Store flag-no -> rule-or-module mapping
    .rule-or-module.$(.flag-no) = $(rule-or-module) ;

    .$(rule-or-module).variable.$(.flag-no) += $(variable-name) ;
    .$(rule-or-module).values.$(.flag-no) += $(values) ;
    .$(rule-or-module).condition.$(.flag-no) += $(condition) ;            
                   
    .flag-no = [ numbers.increment $(.flag-no) ] ;
}
    

# Returns the first element of 'property-sets' which is a subset of
# 'properties', or an empty list if no such element exists.
rule find-property-subset ( property-sets * : properties * )
{
    local result ;
    for local s in $(property-sets)
    {
        if ! $(result)
        {
            if [ feature.split $(s) ] in $(properties)
            {
                result = $(s) ;
            }
        }
    }
    return $(result) ;
}

rule handle-flag-value ( value * : properties * )
{
    local result ;
    if $(value:G)
    {
        local matches = [ property.select $(value) : $(properties) ] ;
        for local p in $(matches)
        {
            local att = [ feature.attributes $(p:G) ] ;
            if dependency in $(att)
            {
                # the value of a dependency feature is a target
                # and must be actualized
                result += [ $(p:G=).actualize ] ;
            }                
            else if path in $(att) || free in $(att)
            {
                local values ;
                # Treat features with && in the value
                # specially -- each &&-separated element is considered
                # separate value. This is needed to handle searched
                # libraries, which must be in specific order.                    
                if ! [ MATCH (&&) : $(p:G=) ]
                {
                    values = $(p:G=) ;
                }
                else                      
                {
                    values = [ regex.split $(p:G=) "&&" ] ;
                }
                if path in $(att)
                {                                            
                        result += [ sequence.transform path.native : $(values) ] ;
                }
                else
                {
                    result += $(values) ;
                }                    
            }    
            else 
            {
                result += $(p:G=) ;
            }
        }        
    }
    else
    {
        result += $(value) ;
    }      
    return $(result) ;
}

# Given a rule name and a property set, returns a list of interleaved
# variables names and values which must be set on targets for that
# rule/property-set combination. 
rule set-target-variables-aux ( rule-or-module : property-set )
{
    local result ;
    properties = [ $(property-set).raw ] ;
    for local f in $(.$(rule-or-module).flags) 
    {
        local variable = $(.$(rule-or-module).variable.$(f)) ;
        local condition = $(.$(rule-or-module).condition.$(f)) ;
        local values = $(.$(rule-or-module).values.$(f)) ;

        
        if ! $(condition) ||
          [ find-property-subset $(condition) : $(properties) ]
        {
            local processed ;
            for local v in $(values)
            {                
                # The value might be <feature-name> so needs special
                # treatment.
                processed += [ 
                  handle-flag-value $(v) : $(properties) ] ;
            }
            for local r in $(processed)
            {                        
                result += $(variable) $(r) ;
            }            
        }
    }
    
    # strip away last dot separated part and recurse.
    local next = [ MATCH ^(.+)\\.([^\\.])* : $(rule-or-module) ] ;
    if $(next)
    {
        result += [
          set-target-variables-aux $(next[1]) : $(property-set) ] ;        
    }        
    return $(result) ;    
}


rule set-target-variables ( rule-or-module targets + : property-set )
{     
    properties = [ $(property-set).raw ] ;
    local key = $(rule-or-module).$(property-set) ;
    local settings = $(.stv.$(key)) ;
    if ! $(settings)
    {
        settings = [ 
          set-target-variables-aux $(rule-or-module) : $(property-set) ] ;

        if ! $(settings)
        {
            settings = none ;
        }
        .stv.$(key) = $(settings) ;
    }
        
    if $(settings) != none
    {
        while $(settings)
        {
            # Here, $(settings[1]) is the name of variable to assign
            # and $(settings[2]) is the value.
            
            $(settings[1]) on $(targets) += $(settings[2]) ;
            settings = $(settings[3-]) ;
        }    
    }
}

.toolsets += $(toolset) ;

# Registers a new toolset
rule register ( toolset )
{
    feature.extend toolset : $(toolset) ;
    .toolsets += $(toolset) ;
}

# Make toolset 'toolset', defined in a module of the same name,
# inherit from 'base'
# 1. The 'init' rule from 'base' is imported into 'toolset' with full
#    name. Another 'init' is called, which forwards to the base one.
# 2. All generators from 'base' are cloned. The ids are adjusted and 
#    <toolset> property in requires is adjusted too
# 3. All flags are inherited
# 4. All rules are imported.
rule inherit ( toolset : base )
{
    import $(base) ;
    
    inherit-generators $(toolset) : $(base) ;
    inherit-flags $(toolset) : $(base) ;
    inherit-rules $(toolset) : $(base) ;
}

rule inherit-generators ( toolset properties * : base : generators-to-ignore * )
{
    properties ?= <toolset>$(toolset) ;
    local base-generators = [ generators.generators-for-toolset $(base) ] ;
    for local g in $(base-generators)
    {
        local id = [ $(g).id ] ;
        
        if ! $(id) in $(generators-to-ignore)
        {            
            # Some generator names have multiple periods in their name, so
            # $(id:B=$(toolset)) doesn't generate the right new-id name.
            # e.g. if id = gcc.compile.c++, $(id:B=darwin) = darwin.c++,
            # which is not what we want. Manually parse the base and suffix
            # (if there's a better way to do this, I'd love to see it.)
            # See also register in module generators.
            local base = $(id) ;
            local suffix = "" ;
            while $(base:S)
            {
                suffix = $(base:S)$(suffix) ;
                base = $(base:B) ;
            }
            local new-id = $(toolset)$(suffix) ;

            generators.register [ $(g).clone $(new-id) : $(properties) ] ;
        }        
    }    
}

# properties listed in prohibited-properties won't
# be inherited. Note that <debug-symbols>on and
# <debug-symbols>off are two different properties
rule inherit-flags ( toolset : base : prohibited-properties * )
{
    for local f in $(.module-flags.$(base))
    {        
        local rule-or-module = $(.rule-or-module.$(f)) ; 
        if [ set.difference
                $(.$(rule-or-module).condition.$(f)) :
                $(prohibited-properties)
           ] || ! $(.$(rule-or-module).condition.$(f))
        {
            local rule_ = [ MATCH "[^.]*\.(.*)" : $(rule-or-module) ] ;
            local new-rule-or-module ;
            if $(rule_)
            {
                new-rule-or-module = $(toolset).$(rule_) ;
            }
            else
            {
                new-rule-or-module = $(toolset) ;
            }
                                        
            add-flag
               $(new-rule-or-module)
               : $(.$(rule-or-module).variable.$(f)) 
               : $(.$(rule-or-module).condition.$(f))              
               : $(.$(rule-or-module).values.$(f))
               ;
        }
    }            
}

rule inherit-rules ( toolset : base )
{
    # It appears that "action" creates local rule... 
    local base-generators = [ generators.generators-for-toolset $(base) ] ;
    local rules ;
    for local g in $(base-generators)
    {
        local id = [ MATCH "[^.]*\.(.*)" : [ $(g).id ] ] ;
        rules += $(id) ;
    }    
    IMPORT $(base) : $(rules) : $(toolset) : $(rules) ;
    # Import the rules to the global scope
    IMPORT $(toolset) : $(rules) : : $(toolset).$(rules) ;
}



local rule __test__ ( )
{
    import assert ;
    local p = <b>0 <c>1 <d>2 <e>3 <f>4 ;
    assert.result <c>1/<d>2/<e>3 : find-property-subset <c>1/<d>2/<e>3 <a>0/<b>0/<c>1 <d>2/<e>5 <a>9 : $(p) ;
    assert.result : find-property-subset <a>0/<b>0/<c>9/<d>9/<e>5 <a>9 : $(p) ;
}

⌨️ 快捷键说明

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