mirror of
https://github.com/boostorg/predef.git
synced 2026-01-27 01:12:22 +01:00
was just not implemented and only really worked for the require checks as those are ok with duplicate properties. Now full and/or expression parsing an evaluation is implemented.
207 lines
6.0 KiB
Plaintext
207 lines
6.0 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 ;
|
|
|
|
# Create a project for our targets.
|
|
project.extension predef check ;
|
|
|
|
# Feature to pass check expressions to check programs.
|
|
feature.feature predef-expression : : free ;
|
|
|
|
# Check programs. Each needs to be compiled for different languages
|
|
# even though they are all the same source code.
|
|
local rule check_target ( language : ext )
|
|
{
|
|
# 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_as_$(language).$(ext) ;
|
|
local include_path
|
|
= $(predef_jam:D)/../include ;
|
|
_check_exe_($(language)) = [
|
|
exe predef_check_as_$(language)
|
|
: $(source_path)
|
|
: <include>$(include_path) ] ;
|
|
explicit predef_check_as_$(language) ;
|
|
}
|
|
check_target c : c ;
|
|
check_target cpp : cpp ;
|
|
check_target objc : m ;
|
|
check_target objcpp : mm ;
|
|
|
|
# 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
|
|
{
|
|
# 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 :
|
|
<predef-expression>$(expression) ;
|
|
explicit
|
|
$(key).txt ;
|
|
}
|
|
|
|
terms += /check/predef//$(key).txt ;
|
|
}
|
|
}
|
|
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 ] ;
|
|
}
|
|
|
|
rule predef_check_action ( targets + : sources + : props * )
|
|
{
|
|
PREDEF_CHECK_EXPRESSION on $(targets)
|
|
= [ feature.get-values <predef-expression> : $(props) ] ;
|
|
}
|
|
|
|
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) ;
|
|
}
|
|
}
|