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