diff --git a/check/predef.jam b/check/predef.jam index 0638703..795c333 100644 --- a/check/predef.jam +++ b/check/predef.jam @@ -13,6 +13,7 @@ import string ; import toolset ; import modules ; import path ; +import "class" : new ; # Create a project for our targets. project.extension predef check ; @@ -54,35 +55,42 @@ rule check ( expressions + : language ? : true-properties * : false-properties * local project_target = [ project.target $(__name__) ] ; project.push-current $(project_target) ; + local terms ; local result ; for expression in $(expressions) { - # The check program to use. - local exe_target = [ $(_check_exe_($(language))).name ] ; - exe_target = /check/predef//$(exe_target) ; - - # Create the check run if we don't have one yet. - local key = [ MD5 $(language)::$(expression) ] ; - if ! ( $(key) in $(_checks_) ) + if $(expression:L) in "and" "or" { - _checks_ += $(key) ; - make - $(key).txt : - $(exe_target) : - @$(__name__).predef_check_action : - $(expression) ; - explicit - $(key).txt ; + terms += $(expression:L) ; + } + else + { + # The check program to use. + local exe_target = [ $(_check_exe_($(language))).name ] ; + exe_target = /check/predef//$(exe_target) ; + + # 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//$(key).txt) = $(expression) ; + make + $(key).txt : + $(exe_target) : + @$(__name__).predef_check_action : + $(expression) ; + explicit + $(key).txt ; + } + + terms += /check/predef//$(key).txt ; } - - local check_target = [ check-target-builds - /check/predef//$(key).txt $(expression) - : $(true-properties) - : $(false-properties) ] ; - - result += $(check_target) ; } - project.pop-current ; + local instance = [ new check-expression-evaluator + $(terms) : $(true-properties) : $(false-properties) ] ; + result = @$(instance).check ; + project.pop-current ; return $(result) ; } @@ -104,3 +112,95 @@ actions predef_check_action bind PREDEF_CHECK_EXPRESSION { $(>) "$(PREDEF_CHECK_EXPRESSION)" > $(<) } + +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) ; + } +} diff --git a/test/build.jam b/test/build.jam index 28e1473..b760f90 100755 --- a/test/build.jam +++ b/test/build.jam @@ -4,7 +4,7 @@ # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) -import ../check/predef : require : predef-require ; +import ../check/predef : require check : predef-require predef-check ; local predef-include-root ; local predef-dependency ; @@ -57,4 +57,5 @@ test-suite predef : [ run make.cpp ] [ compile macos_endian.c : [ predef-require "BOOST_OS_MACOS" : cpp ] ] [ compile macos_vs_bsd.c : [ predef-require "BOOST_OS_MACOS" : cpp ] ] + #[ run check_value.cpp : : : [ predef-check "BOOST_COMP_CLANG >= 4.0" "BOOST_OS_MACOS == 0" : : -DCHECK_VALUE=true : -DCHECK_VALUE=false ] ] ; diff --git a/test/check_value.cpp b/test/check_value.cpp new file mode 100644 index 0000000..86bed68 --- /dev/null +++ b/test/check_value.cpp @@ -0,0 +1,26 @@ +/* +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) +*/ + +/* + * Simple program that just prints out the externally + * defined CHECK_VALUE def. It's used to test the check + * program and the related BB support. + */ + +#include +#include +#include + +#ifndef CHECK_VALUE +#define CHECK_VALUE "undefined" +#endif + +int main(int argc, const char ** argv) +{ + std::cout << "CHECK_VALUE == " << CHECK_VALUE << "\n" ; + return 0; +}