Imported Upstream version 1.51.0
[platform/upstream/boost.git] / tools / build / v2 / build / build_request.py
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
10 import b2.build.feature
11 feature = b2.build.feature
12
13 from b2.util.utility import *
14 import b2.build.property_set as property_set
15
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.
19     """
20     # First make all features and subfeatures explicit
21     expanded_property_sets = [ps.expand_subfeatures() for ps in property_sets]
22     
23     # Now combine all of the expanded property_sets
24     product = __x_product (expanded_property_sets)
25     
26     return [property_set.create(p) for p in product]
27
28
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.
32     """
33     x_product_seen = set()
34     return __x_product_aux (property_sets, x_product_seen)[0]
35
36 def __x_product_aux (property_sets, seen_features):
37     """Returns non-conflicting combinations of property sets.
38
39     property_sets is a list of PropertySet instances. seen_features is a set of Property
40     instances.
41
42     Returns a tuple of:
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      
46     """
47     if not property_sets:
48         return ([], set())
49
50     properties = property_sets[0].all()
51
52     these_features = set()
53     for p in property_sets[0].non_free():
54         these_features.add(p.feature())
55
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:
59     #
60     # <a>1/<b>1 c<1>/<b>1
61     #
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:
66
67         (inner_result, inner_seen) = __x_product_aux(property_sets[1:], seen_features)
68         return (inner_result, inner_seen | these_features)
69
70     else:
71
72         result = []
73         (inner_result, inner_seen) = __x_product_aux(property_sets[1:], seen_features | these_features)
74         if inner_result:
75             for inner in inner_result:
76                 result.append(properties + inner)
77         else:
78             result.append(properties)
79         
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)
85
86         return (result, inner_seen | these_features)
87
88     
89
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):
94         return 1
95     else:
96         split = v.split("-")
97         if feature.is_implicit_value(split[0]):
98             return 1
99
100     return 0
101
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."""
107
108     targets = []
109     properties = []
110
111     for e in command_line:
112         if e[0] != "-":
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)
117             else:
118                 targets.append(e)
119
120     return [targets, properties]
121  
122 # Converts one element of command line build request specification into
123 # internal form.
124 def convert_command_line_element(e):
125
126     result = None
127     parts = e.split("/")
128     for p in parts:
129         m = p.split("=")
130         if len(m) > 1:
131             feature = m[0]
132             values = m[1].split(",")
133             lresult = [("<%s>%s" % (feature, v)) for v in values]
134         else:
135             lresult = p.split(",")
136             
137         if p.find('-') == -1:
138             # FIXME: first port property.validate
139             # property.validate cannot handle subfeatures,
140             # so we avoid the check here.
141             #for p in lresult:
142             #    property.validate(p)
143             pass
144
145         if not result:
146             result = lresult
147         else:
148             result = [e1 + "/" + e2 for e1 in result for e2 in lresult]
149
150     return [property_set.create(b2.build.feature.split(r)) for r in result]
151
152 ### 
153 ### rule __test__ ( )
154 ### {
155 ###     import assert feature ;
156 ###     
157 ###     feature.prepare-test build-request-test-temp ;
158 ###     
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 ;
163 ### 
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 ;
167 ### 
168 ###     feature variant : debug release : implicit composite ;
169 ###     feature inlining : on off ;
170 ###     feature "include" : : free ;
171 ### 
172 ###     feature stdlib : native stlport : implicit ;
173 ### 
174 ###     feature runtime-link : dynamic static : symmetric ;
175 ### 
176 ### 
177 ###     local r ;
178 ### 
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 ;
182 ### 
183 ###     try ;
184 ###     {
185 ### 
186 ###         build-request.from-command-line bjam gcc/debug runtime-link=dynamic/static ;
187 ###     }
188 ###     catch \"static\" is not a value of an implicit feature ;
189 ### 
190 ### 
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 ;
194 ### 
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 ;
198 ### 
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 ;
203 ### 
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 ;
208 ### 
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 ;
212 ### 
213 ###     feature.finish-test build-request-test-temp ;
214 ### }
215 ### 
216 ###