• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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