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