1# Status: being ported by Vladimir Prus 2# TODO: need to re-compare with mainline of .jam 3# Base revision: 40480 4# 5# (C) Copyright David Abrahams 2002. Permission to copy, use, modify, sell and 6# distribute this software is granted provided this copyright notice appears in 7# all copies. This software is provided "as is" without express or implied 8# warranty, and with no claim as to its suitability for any purpose. 9 10import b2.build.feature 11feature = b2.build.feature 12 13from b2.util.utility import * 14from b2.util import is_iterable_typed 15import b2.build.property_set as property_set 16 17def expand_no_defaults (property_sets): 18 """ Expand the given build request by combining all property_sets which don't 19 specify conflicting non-free features. 20 """ 21 assert is_iterable_typed(property_sets, property_set.PropertySet) 22 # First make all features and subfeatures explicit 23 expanded_property_sets = [ps.expand_subfeatures() for ps in property_sets] 24 25 # Now combine all of the expanded property_sets 26 product = __x_product (expanded_property_sets) 27 28 return [property_set.create(p) for p in product] 29 30 31def __x_product (property_sets): 32 """ Return the cross-product of all elements of property_sets, less any 33 that would contain conflicting values for single-valued features. 34 """ 35 assert is_iterable_typed(property_sets, property_set.PropertySet) 36 x_product_seen = set() 37 return __x_product_aux (property_sets, x_product_seen)[0] 38 39def __x_product_aux (property_sets, seen_features): 40 """Returns non-conflicting combinations of property sets. 41 42 property_sets is a list of PropertySet instances. seen_features is a set of Property 43 instances. 44 45 Returns a tuple of: 46 - list of lists of Property instances, such that within each list, no two Property instance 47 have the same feature, and no Property is for feature in seen_features. 48 - set of features we saw in property_sets 49 """ 50 assert is_iterable_typed(property_sets, property_set.PropertySet) 51 assert isinstance(seen_features, set) 52 if not property_sets: 53 return ([], set()) 54 55 properties = property_sets[0].all() 56 57 these_features = set() 58 for p in property_sets[0].non_free(): 59 these_features.add(p.feature) 60 61 # Note: the algorithm as implemented here, as in original Jam code, appears to 62 # detect conflicts based on features, not properties. For example, if command 63 # line build request say: 64 # 65 # <a>1/<b>1 c<1>/<b>1 66 # 67 # It will decide that those two property sets conflict, because they both specify 68 # a value for 'b' and will not try building "<a>1 <c1> <b1>", but rather two 69 # different property sets. This is a topic for future fixing, maybe. 70 if these_features & seen_features: 71 72 (inner_result, inner_seen) = __x_product_aux(property_sets[1:], seen_features) 73 return (inner_result, inner_seen | these_features) 74 75 else: 76 77 result = [] 78 (inner_result, inner_seen) = __x_product_aux(property_sets[1:], seen_features | these_features) 79 if inner_result: 80 for inner in inner_result: 81 result.append(properties + inner) 82 else: 83 result.append(properties) 84 85 if inner_seen & these_features: 86 # Some of elements in property_sets[1:] conflict with elements of property_sets[0], 87 # Try again, this time omitting elements of property_sets[0] 88 (inner_result2, inner_seen2) = __x_product_aux(property_sets[1:], seen_features) 89 result.extend(inner_result2) 90 91 return (result, inner_seen | these_features) 92 93 94 95def looks_like_implicit_value(v): 96 """Returns true if 'v' is either implicit value, or 97 the part before the first '-' symbol is implicit value.""" 98 assert isinstance(v, basestring) 99 if feature.is_implicit_value(v): 100 return 1 101 else: 102 split = v.split("-") 103 if feature.is_implicit_value(split[0]): 104 return 1 105 106 return 0 107 108def from_command_line(command_line): 109 """Takes the command line tokens (such as taken from ARGV rule) 110 and constructs build request from it. Returns a list of two 111 lists. First is the set of targets specified in the command line, 112 and second is the set of requested build properties.""" 113 assert is_iterable_typed(command_line, basestring) 114 targets = [] 115 properties = [] 116 117 for e in command_line: 118 if e[:1] != "-": 119 # Build request spec either has "=" in it, or completely 120 # consists of implicit feature values. 121 if e.find("=") != -1 or looks_like_implicit_value(e.split("/")[0]): 122 properties.append(e) 123 elif e: 124 targets.append(e) 125 126 return [targets, properties] 127 128# Converts one element of command line build request specification into 129# internal form. 130def convert_command_line_element(e): 131 assert isinstance(e, basestring) 132 result = None 133 parts = e.split("/") 134 for p in parts: 135 m = p.split("=") 136 if len(m) > 1: 137 feature = m[0] 138 values = m[1].split(",") 139 lresult = [("<%s>%s" % (feature, v)) for v in values] 140 else: 141 lresult = p.split(",") 142 143 if p.find('-') == -1: 144 # FIXME: first port property.validate 145 # property.validate cannot handle subfeatures, 146 # so we avoid the check here. 147 #for p in lresult: 148 # property.validate(p) 149 pass 150 151 if not result: 152 result = lresult 153 else: 154 result = [e1 + "/" + e2 for e1 in result for e2 in lresult] 155 156 return [property_set.create(b2.build.feature.split(r)) for r in result] 157 158### 159### rule __test__ ( ) 160### { 161### import assert feature ; 162### 163### feature.prepare-test build-request-test-temp ; 164### 165### import build-request ; 166### import build-request : expand_no_defaults : build-request.expand_no_defaults ; 167### import errors : try catch ; 168### import feature : feature subfeature ; 169### 170### feature toolset : gcc msvc borland : implicit ; 171### subfeature toolset gcc : version : 2.95.2 2.95.3 2.95.4 172### 3.0 3.0.1 3.0.2 : optional ; 173### 174### feature variant : debug release : implicit composite ; 175### feature inlining : on off ; 176### feature "include" : : free ; 177### 178### feature stdlib : native stlport : implicit ; 179### 180### feature runtime-link : dynamic static : symmetric ; 181### 182### 183### local r ; 184### 185### r = [ build-request.from-command-line bjam debug runtime-link=dynamic ] ; 186### assert.equal [ $(r).get-at 1 ] : ; 187### assert.equal [ $(r).get-at 2 ] : debug <runtime-link>dynamic ; 188### 189### try ; 190### { 191### 192### build-request.from-command-line bjam gcc/debug runtime-link=dynamic/static ; 193### } 194### catch \"static\" is not a value of an implicit feature ; 195### 196### 197### r = [ build-request.from-command-line bjam -d2 --debug debug target runtime-link=dynamic ] ; 198### assert.equal [ $(r).get-at 1 ] : target ; 199### assert.equal [ $(r).get-at 2 ] : debug <runtime-link>dynamic ; 200### 201### r = [ build-request.from-command-line bjam debug runtime-link=dynamic,static ] ; 202### assert.equal [ $(r).get-at 1 ] : ; 203### assert.equal [ $(r).get-at 2 ] : debug <runtime-link>dynamic <runtime-link>static ; 204### 205### r = [ build-request.from-command-line bjam debug gcc/runtime-link=dynamic,static ] ; 206### assert.equal [ $(r).get-at 1 ] : ; 207### assert.equal [ $(r).get-at 2 ] : debug gcc/<runtime-link>dynamic 208### gcc/<runtime-link>static ; 209### 210### r = [ build-request.from-command-line bjam msvc gcc,borland/runtime-link=static ] ; 211### assert.equal [ $(r).get-at 1 ] : ; 212### assert.equal [ $(r).get-at 2 ] : msvc gcc/<runtime-link>static 213### borland/<runtime-link>static ; 214### 215### r = [ build-request.from-command-line bjam gcc-3.0 ] ; 216### assert.equal [ $(r).get-at 1 ] : ; 217### assert.equal [ $(r).get-at 2 ] : gcc-3.0 ; 218### 219### feature.finish-test build-request-test-temp ; 220### } 221### 222### 223