|
|
@@ -0,0 +1,202 @@ |
|
|
# 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 ; |
|
|
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[3]) { 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) ; |
|
|
} |
|
|
} |