1 # Status: being ported by Vladimir Prus
2 # TODO: need to re-compare with mainline of .jam
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.
10 import b2.build.feature
11 feature = b2.build.feature
13 from b2.util.utility import *
14 import b2.build.property_set as property_set
16 def expand_no_defaults (property_sets):
17 """ Expand the given build request by combining all property_sets which don't
18 specify conflicting non-free features.
20 # First make all features and subfeatures explicit
21 expanded_property_sets = [ps.expand_subfeatures() for ps in property_sets]
23 # Now combine all of the expanded property_sets
24 product = __x_product (expanded_property_sets)
26 return [property_set.create(p) for p in product]
29 def __x_product (property_sets):
30 """ Return the cross-product of all elements of property_sets, less any
31 that would contain conflicting values for single-valued features.
33 x_product_seen = set()
34 return __x_product_aux (property_sets, x_product_seen)[0]
36 def __x_product_aux (property_sets, seen_features):
37 """Returns non-conflicting combinations of property sets.
39 property_sets is a list of PropertySet instances. seen_features is a set of Property
43 - list of lists of Property instances, such that within each list, no two Property instance
44 have the same feature, and no Property is for feature in seen_features.
45 - set of features we saw in property_sets
50 properties = property_sets[0].all()
52 these_features = set()
53 for p in property_sets[0].non_free():
54 these_features.add(p.feature())
56 # Note: the algorithm as implemented here, as in original Jam code, appears to
57 # detect conflicts based on features, not properties. For example, if command
58 # line build request say:
62 # It will decide that those two property sets conflict, because they both specify
63 # a value for 'b' and will not try building "<a>1 <c1> <b1>", but rather two
64 # different property sets. This is a topic for future fixing, maybe.
65 if these_features & seen_features:
67 (inner_result, inner_seen) = __x_product_aux(property_sets[1:], seen_features)
68 return (inner_result, inner_seen | these_features)
73 (inner_result, inner_seen) = __x_product_aux(property_sets[1:], seen_features | these_features)
75 for inner in inner_result:
76 result.append(properties + inner)
78 result.append(properties)
80 if inner_seen & these_features:
81 # Some of elements in property_sets[1:] conflict with elements of property_sets[0],
82 # Try again, this time omitting elements of property_sets[0]
83 (inner_result2, inner_seen2) = __x_product_aux(property_sets[1:], seen_features)
84 result.extend(inner_result2)
86 return (result, inner_seen | these_features)
90 def looks_like_implicit_value(v):
91 """Returns true if 'v' is either implicit value, or
92 the part before the first '-' symbol is implicit value."""
93 if feature.is_implicit_value(v):
97 if feature.is_implicit_value(split[0]):
102 def from_command_line(command_line):
103 """Takes the command line tokens (such as taken from ARGV rule)
104 and constructs build request from it. Returns a list of two
105 lists. First is the set of targets specified in the command line,
106 and second is the set of requested build properties."""
111 for e in command_line:
113 # Build request spec either has "=" in it, or completely
114 # consists of implicit feature values.
115 if e.find("=") != -1 or looks_like_implicit_value(e.split("/")[0]):
116 properties += convert_command_line_element(e)
120 return [targets, properties]
122 # Converts one element of command line build request specification into
124 def convert_command_line_element(e):
132 values = m[1].split(",")
133 lresult = [("<%s>%s" % (feature, v)) for v in values]
135 lresult = p.split(",")
137 if p.find('-') == -1:
138 # FIXME: first port property.validate
139 # property.validate cannot handle subfeatures,
140 # so we avoid the check here.
142 # property.validate(p)
148 result = [e1 + "/" + e2 for e1 in result for e2 in lresult]
150 return [property_set.create(b2.build.feature.split(r)) for r in result]
153 ### rule __test__ ( )
155 ### import assert feature ;
157 ### feature.prepare-test build-request-test-temp ;
159 ### import build-request ;
160 ### import build-request : expand_no_defaults : build-request.expand_no_defaults ;
161 ### import errors : try catch ;
162 ### import feature : feature subfeature ;
164 ### feature toolset : gcc msvc borland : implicit ;
165 ### subfeature toolset gcc : version : 2.95.2 2.95.3 2.95.4
166 ### 3.0 3.0.1 3.0.2 : optional ;
168 ### feature variant : debug release : implicit composite ;
169 ### feature inlining : on off ;
170 ### feature "include" : : free ;
172 ### feature stdlib : native stlport : implicit ;
174 ### feature runtime-link : dynamic static : symmetric ;
179 ### r = [ build-request.from-command-line bjam debug runtime-link=dynamic ] ;
180 ### assert.equal [ $(r).get-at 1 ] : ;
181 ### assert.equal [ $(r).get-at 2 ] : debug <runtime-link>dynamic ;
186 ### build-request.from-command-line bjam gcc/debug runtime-link=dynamic/static ;
188 ### catch \"static\" is not a value of an implicit feature ;
191 ### r = [ build-request.from-command-line bjam -d2 --debug debug target runtime-link=dynamic ] ;
192 ### assert.equal [ $(r).get-at 1 ] : target ;
193 ### assert.equal [ $(r).get-at 2 ] : debug <runtime-link>dynamic ;
195 ### r = [ build-request.from-command-line bjam debug runtime-link=dynamic,static ] ;
196 ### assert.equal [ $(r).get-at 1 ] : ;
197 ### assert.equal [ $(r).get-at 2 ] : debug <runtime-link>dynamic <runtime-link>static ;
199 ### r = [ build-request.from-command-line bjam debug gcc/runtime-link=dynamic,static ] ;
200 ### assert.equal [ $(r).get-at 1 ] : ;
201 ### assert.equal [ $(r).get-at 2 ] : debug gcc/<runtime-link>dynamic
202 ### gcc/<runtime-link>static ;
204 ### r = [ build-request.from-command-line bjam msvc gcc,borland/runtime-link=static ] ;
205 ### assert.equal [ $(r).get-at 1 ] : ;
206 ### assert.equal [ $(r).get-at 2 ] : msvc gcc/<runtime-link>static
207 ### borland/<runtime-link>static ;
209 ### r = [ build-request.from-command-line bjam gcc-3.0 ] ;
210 ### assert.equal [ $(r).get-at 1 ] : ;
211 ### assert.equal [ $(r).get-at 2 ] : gcc-3.0 ;
213 ### feature.finish-test build-request-test-temp ;