203 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			203 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| 
								 | 
							
								# Copyright Rene Rivera 2015
							 | 
						||
| 
								 | 
							
								# Distributed under the Boost Software License, Version 1.0.
							 | 
						||
| 
								 | 
							
								# (See accompanying file LICENSE_1_0.txt or copy at
							 | 
						||
| 
								 | 
							
								# http://www.boost.org/LICENSE_1_0.txt)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Defines rules that provide requirements based on checking
							 | 
						||
| 
								 | 
							
								# conditions using Boost Predef definitions and version numbers.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import modules ;
							 | 
						||
| 
								 | 
							
								import project ;
							 | 
						||
| 
								 | 
							
								import feature ;
							 | 
						||
| 
								 | 
							
								import string ;
							 | 
						||
| 
								 | 
							
								import toolset ;
							 | 
						||
| 
								 | 
							
								import modules ;
							 | 
						||
| 
								 | 
							
								import path ;
							 | 
						||
| 
								 | 
							
								import "class" : new ;
							 | 
						||
| 
								 | 
							
								import regex ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Create a project for our targets.
							 | 
						||
| 
								 | 
							
								project.extension predef check ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Feature to pass check expressions to check programs.
							 | 
						||
| 
								 | 
							
								feature.feature predef-expression : : free ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Checks the expressions and when used evaluates to the true-properties
							 | 
						||
| 
								 | 
							
								# if the expressions are all true. Otherwise evaluates to the
							 | 
						||
| 
								 | 
							
								# false-properties.
							 | 
						||
| 
								 | 
							
								rule check ( expressions + : language ? : true-properties * : false-properties * )
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    # Default to C++ on the check context.
							 | 
						||
| 
								 | 
							
								    language ?= cpp ;
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    local project_target = [ project.target $(__name__) ] ;
							 | 
						||
| 
								 | 
							
									project.push-current $(project_target) ;
							 | 
						||
| 
								 | 
							
								    local terms ;
							 | 
						||
| 
								 | 
							
								    local result ;
							 | 
						||
| 
								 | 
							
								    for expression in $(expressions)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if $(expression:L) in "and" "or"
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            terms += $(expression:L) ;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            # Create the check run if we don't have one yet.
							 | 
						||
| 
								 | 
							
								            local key = [ MD5 "$(language)::$(expression)" ] ;
							 | 
						||
| 
								 | 
							
								            if ! ( $(key) in $(_checks_) )
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                _checks_ += $(key) ;
							 | 
						||
| 
								 | 
							
								                _message_(/check/predef//predef_check_cc_$(key)) = $(expression) ;
							 | 
						||
| 
								 | 
							
								                check_target $(language) $(key) : [ change_term_to_def $(expression) ] ;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            
							 | 
						||
| 
								 | 
							
								            terms += /check/predef//predef_check_cc_$(key) ;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    local instance = [ new check-expression-evaluator
							 | 
						||
| 
								 | 
							
								        $(terms) : $(true-properties) : $(false-properties) ] ;
							 | 
						||
| 
								 | 
							
								    result = <conditional>@$(instance).check ;
							 | 
						||
| 
								 | 
							
								    project.pop-current ;
							 | 
						||
| 
								 | 
							
								    return $(result) ;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Checks the expressions and when used evaluates to <build>no
							 | 
						||
| 
								 | 
							
								# if the expressions are all false. Otherwise evaluates to the
							 | 
						||
| 
								 | 
							
								# nothing.
							 | 
						||
| 
								 | 
							
								rule require ( expressions + : language ? )
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    return [ check $(expressions) : $(language) : : <build>no ] ;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#############################################################################
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.c.ext = c ;
							 | 
						||
| 
								 | 
							
								.cpp.ext = cpp ;
							 | 
						||
| 
								 | 
							
								.objc.ext = m ;
							 | 
						||
| 
								 | 
							
								.objcpp.ext = mm ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Check targets. Each needs to be compiled for different languages
							 | 
						||
| 
								 | 
							
								# even though they are all the same source code.
							 | 
						||
| 
								 | 
							
								local rule check_target ( language key : requirements * )
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    # Need to use absolute paths because we don't know the
							 | 
						||
| 
								 | 
							
								    # context of the invocation which affects where the paths
							 | 
						||
| 
								 | 
							
								    # originate from.
							 | 
						||
| 
								 | 
							
								    local predef_jam
							 | 
						||
| 
								 | 
							
								        = [ modules.binding $(__name__) ] ;
							 | 
						||
| 
								 | 
							
								    local source_path
							 | 
						||
| 
								 | 
							
								        = $(predef_jam:D)/predef_check_cc_as_$(language).$(.$(language).ext) ;
							 | 
						||
| 
								 | 
							
								    local include_path
							 | 
						||
| 
								 | 
							
								        = $(predef_jam:D)/../../include $(BOOST_ROOT) ;
							 | 
						||
| 
								 | 
							
								    obj predef_check_cc_$(key)
							 | 
						||
| 
								 | 
							
								        : $(source_path)
							 | 
						||
| 
								 | 
							
								        : <include>$(include_path) $(requirements) ;
							 | 
						||
| 
								 | 
							
								    explicit predef_check_cc_$(key) ;
							 | 
						||
| 
								 | 
							
								    return predef_check_cc_$(key) ;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								local rule change_term_to_def ( term )
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    local parts = [ regex.split $(term) " " ] ;
							 | 
						||
| 
								 | 
							
								    if $(parts[3])
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        local version_number = [ regex.split $(parts[3]) "[.]" ] ;
							 | 
						||
| 
								 | 
							
								        if ! $(version_number[2]) { version_number += "0" ; }
							 | 
						||
| 
								 | 
							
								        if ! $(version_number[3]) { version_number += "0" ; }
							 | 
						||
| 
								 | 
							
								        parts = $(parts[1-2]) BOOST_VERSION_NUMBER($(version_number:J=",")) ;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return <define>CHECK=\"$(parts:J=" ")\" ;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class check-expression-evaluator
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    import configure ;
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    rule __init__ ( expression + : true-properties * : false-properties * )
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        self.expression = $(expression) ;
							 | 
						||
| 
								 | 
							
								        self.true-properties = $(true-properties) ;
							 | 
						||
| 
								 | 
							
								        self.false-properties = $(false-properties) ;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    rule check ( properties * )
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        local to-eval ;
							 | 
						||
| 
								 | 
							
								        local tokens = "and" "or" ;
							 | 
						||
| 
								 | 
							
								        # Go through the expression and: eval the target values,
							 | 
						||
| 
								 | 
							
								        # and normalize to a full expression.
							 | 
						||
| 
								 | 
							
								        for local term in $(self.expression)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if ! ( $(term:L) in $(tokens) )
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                # A value is a target reference that will evan to "true"
							 | 
						||
| 
								 | 
							
								                # or "false".
							 | 
						||
| 
								 | 
							
								                if $(to-eval[-1]:L) && ! ( $(to-eval[-1]:L) in $(tokens) )
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    # Default to "and" operation.
							 | 
						||
| 
								 | 
							
								                    to-eval += "and" ;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                local message = [ modules.peek predef : _message_($(term)) ] ;
							 | 
						||
| 
								 | 
							
								                if [ configure.builds $(term) : $(properties) : $(message) ]
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    to-eval += "true" ;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                else
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    to-eval += "false" ;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                to-eval += $(term) ;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        # Eval full the expression.
							 | 
						||
| 
								 | 
							
								        local eval-result = [ eval $(to-eval) ] ;
							 | 
						||
| 
								 | 
							
								        # And resolve true/false properties.
							 | 
						||
| 
								 | 
							
								        if $(eval-result) = "true"
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return $(self.true-properties) ;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return $(self.false-properties) ;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    rule eval ( e * )
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        local r ;
							 | 
						||
| 
								 | 
							
								        if $(e[1]) && $(e[2]) && $(e[3])
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if $(e[2]) = "and"
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                if $(e[1]) = "true" && $(e[3]) = "true"
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    r = [ eval "true" $(e[4-]) ] ;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                else
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    r = [ eval "false" $(e[4-]) ] ;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else if $(e[2]) = "or"
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                if $(e[1]) = "true" || $(e[3]) = "true"
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    r = [ eval "true" $(e[4-]) ] ;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                else
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    r = [ eval "false" $(e[4-]) ] ;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            r = $(e[1]) ;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return $(r) ;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 |