predef.jam 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. # Copyright Rene Rivera 2015
  2. # Distributed under the Boost Software License, Version 1.0.
  3. # (See accompanying file LICENSE_1_0.txt or copy at
  4. # http://www.boost.org/LICENSE_1_0.txt)
  5. # Defines rules that provide requirements based on checking
  6. # conditions using Boost Predef definitions and version numbers.
  7. import modules ;
  8. import project ;
  9. import feature ;
  10. import string ;
  11. import toolset ;
  12. import modules ;
  13. import path ;
  14. import "class" : new ;
  15. import regex ;
  16. # Create a project for our targets.
  17. project.extension predef check ;
  18. # Feature to pass check expressions to check programs.
  19. feature.feature predef-expression : : free ;
  20. # Checks the expressions and when used evaluates to the true-properties
  21. # if the expressions are all true. Otherwise evaluates to the
  22. # false-properties.
  23. rule check ( expressions + : language ? : true-properties * : false-properties * )
  24. {
  25. # Default to C++ on the check context.
  26. language ?= cpp ;
  27. local project_target = [ project.target $(__name__) ] ;
  28. project.push-current $(project_target) ;
  29. local terms ;
  30. local result ;
  31. for expression in $(expressions)
  32. {
  33. if $(expression:L) in "and" "or"
  34. {
  35. terms += $(expression:L) ;
  36. }
  37. else
  38. {
  39. # Create the check run if we don't have one yet.
  40. local key = [ MD5 "$(language)::$(expression)" ] ;
  41. if ! ( $(key) in $(_checks_) )
  42. {
  43. _checks_ += $(key) ;
  44. _message_(/check/predef//predef_check_cc_$(key)) = $(expression) ;
  45. check_target $(language) $(key) : [ change_term_to_def $(expression) ] ;
  46. }
  47. terms += /check/predef//predef_check_cc_$(key) ;
  48. }
  49. }
  50. local instance = [ new check-expression-evaluator
  51. $(terms) : $(true-properties) : $(false-properties) ] ;
  52. result = <conditional>@$(instance).check ;
  53. project.pop-current ;
  54. return $(result) ;
  55. }
  56. # Checks the expressions and when used evaluates to <build>no
  57. # if the expressions are all false. Otherwise evaluates to the
  58. # nothing.
  59. rule require ( expressions + : language ? )
  60. {
  61. return [ check $(expressions) : $(language) : : <build>no ] ;
  62. }
  63. #############################################################################
  64. .c.ext = c ;
  65. .cpp.ext = cpp ;
  66. .objc.ext = m ;
  67. .objcpp.ext = mm ;
  68. # Check targets. Each needs to be compiled for different languages
  69. # even though they are all the same source code.
  70. local rule check_target ( language key : requirements * )
  71. {
  72. # Need to use absolute paths because we don't know the
  73. # context of the invocation which affects where the paths
  74. # originate from.
  75. local predef_jam
  76. = [ modules.binding $(__name__) ] ;
  77. local source_path
  78. = $(predef_jam:D)/predef_check_cc_as_$(language).$(.$(language).ext) ;
  79. local include_path
  80. = $(predef_jam:D)/../../include $(BOOST_ROOT) ;
  81. obj predef_check_cc_$(key)
  82. : $(source_path)
  83. : <include>$(include_path) $(requirements) ;
  84. explicit predef_check_cc_$(key) ;
  85. return predef_check_cc_$(key) ;
  86. }
  87. local rule change_term_to_def ( term )
  88. {
  89. local parts = [ regex.split $(term) " " ] ;
  90. if $(parts[3])
  91. {
  92. local version_number = [ regex.split $(parts[3]) "[.]" ] ;
  93. if ! $(version_number[2]) { version_number += "0" ; }
  94. if ! $(version_number[3]) { version_number += "0" ; }
  95. parts = $(parts[1-2]) BOOST_VERSION_NUMBER($(version_number:J=",")) ;
  96. }
  97. return <define>CHECK=\"$(parts:J=" ")\" ;
  98. }
  99. class check-expression-evaluator
  100. {
  101. import configure ;
  102. rule __init__ ( expression + : true-properties * : false-properties * )
  103. {
  104. self.expression = $(expression) ;
  105. self.true-properties = $(true-properties) ;
  106. self.false-properties = $(false-properties) ;
  107. }
  108. rule check ( properties * )
  109. {
  110. local to-eval ;
  111. local tokens = "and" "or" ;
  112. # Go through the expression and: eval the target values,
  113. # and normalize to a full expression.
  114. for local term in $(self.expression)
  115. {
  116. if ! ( $(term:L) in $(tokens) )
  117. {
  118. # A value is a target reference that will evan to "true"
  119. # or "false".
  120. if $(to-eval[-1]:L) && ! ( $(to-eval[-1]:L) in $(tokens) )
  121. {
  122. # Default to "and" operation.
  123. to-eval += "and" ;
  124. }
  125. local message = [ modules.peek predef : _message_($(term)) ] ;
  126. if [ configure.builds $(term) : $(properties) : $(message) ]
  127. {
  128. to-eval += "true" ;
  129. }
  130. else
  131. {
  132. to-eval += "false" ;
  133. }
  134. }
  135. else
  136. {
  137. to-eval += $(term) ;
  138. }
  139. }
  140. # Eval full the expression.
  141. local eval-result = [ eval $(to-eval) ] ;
  142. # And resolve true/false properties.
  143. if $(eval-result) = "true"
  144. {
  145. return $(self.true-properties) ;
  146. }
  147. else
  148. {
  149. return $(self.false-properties) ;
  150. }
  151. }
  152. rule eval ( e * )
  153. {
  154. local r ;
  155. if $(e[1]) && $(e[2]) && $(e[3])
  156. {
  157. if $(e[2]) = "and"
  158. {
  159. if $(e[1]) = "true" && $(e[3]) = "true"
  160. {
  161. r = [ eval "true" $(e[4-]) ] ;
  162. }
  163. else
  164. {
  165. r = [ eval "false" $(e[4-]) ] ;
  166. }
  167. }
  168. else if $(e[2]) = "or"
  169. {
  170. if $(e[1]) = "true" || $(e[3]) = "true"
  171. {
  172. r = [ eval "true" $(e[4-]) ] ;
  173. }
  174. else
  175. {
  176. r = [ eval "false" $(e[4-]) ] ;
  177. }
  178. }
  179. }
  180. else
  181. {
  182. r = $(e[1]) ;
  183. }
  184. return $(r) ;
  185. }
  186. }