]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/src/build/property-set.jam
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / boost / tools / build / src / build / property-set.jam
1 # Copyright 2003 Dave Abrahams
2 # Copyright 2003, 2004, 2005, 2006 Vladimir Prus
3 # Distributed under the Boost Software License, Version 1.0.
4 # (See accompanying file LICENSE_1_0.txt or copy at
5 # http://www.boost.org/LICENSE_1_0.txt)
6
7 import "class" : new ;
8 import feature ;
9 import path ;
10 import project ;
11 import property ;
12 import sequence ;
13 import set ;
14 import option ;
15
16 # Class for storing a set of properties.
17 #
18 # There is 1<->1 correspondence between identity and value. No two instances
19 # of the class are equal. To maintain this property, the 'property-set.create'
20 # rule should be used to create new instances. Instances are immutable.
21 #
22 # Each property is classified with regard to its effect on build results.
23 # Incidental properties have no effect on build results, from B2's
24 # point of view. Others are either free, or non-free and we refer to non-free
25 # ones as 'base'. Each property belongs to exactly one of those categories.
26 #
27 # It is possible to get a list of properties belonging to each category as
28 # well as a list of properties with a specific attribute.
29 #
30 # Several operations, like and refine and as-path are provided. They all use
31 # caching whenever possible.
32 #
33 class property-set
34 {
35 import errors ;
36 import feature ;
37 import modules ;
38 import path ;
39 import property ;
40 import property-set ;
41 import set ;
42
43 rule __init__ ( raw-properties * )
44 {
45 self.raw = $(raw-properties) ;
46
47 for local p in $(raw-properties)
48 {
49 if ! $(p:G)
50 {
51 errors.error "Invalid property: '$(p)'" ;
52 }
53 }
54 }
55
56 # Returns Jam list of stored properties.
57 #
58 rule raw ( )
59 {
60 return $(self.raw) ;
61 }
62
63 rule str ( )
64 {
65 return "[" $(self.raw) "]" ;
66 }
67
68 # Returns properties that are neither incidental nor free.
69 #
70 rule base ( )
71 {
72 if ! $(self.base-initialized)
73 {
74 init-base ;
75 }
76 return $(self.base) ;
77 }
78
79 # Returns free properties which are not incidental.
80 #
81 rule free ( )
82 {
83 if ! $(self.base-initialized)
84 {
85 init-base ;
86 }
87 return $(self.free) ;
88 }
89
90 # Returns relevant base properties. This is used for computing
91 # target paths, so it must return the expanded set of relevant
92 # properties.
93 #
94 rule base-relevant ( )
95 {
96 if ! $(self.relevant-initialized)
97 {
98 init-relevant ;
99 }
100 return $(self.base-relevant) ;
101 }
102
103 # Returns all properties marked as relevant by features-ps
104 # Does not attempt to expand features-ps in any way, as
105 # this matches what virtual-target.register needs.
106 #
107 rule relevant ( features-ps )
108 {
109 if ! $(self.relevant.$(features-ps))
110 {
111 local result ;
112 local features = [ $(features-ps).get <relevant> ] ;
113 features = <$(features)> ;
114 local ignore-relevance = [ modules.peek
115 property-set : .ignore-relevance ] ;
116 for local p in $(self.raw)
117 {
118 if $(ignore-relevance) || $(p:G) in $(features)
119 {
120 local att = [ feature.attributes $(p:G) ] ;
121 if ! ( incidental in $(att) )
122 {
123 result += $(p) ;
124 }
125 }
126 }
127 self.relevant.$(features-ps) = [ property-set.create $(result) ] ;
128 }
129 return $(self.relevant.$(features-ps)) ;
130 }
131
132 # Returns dependency properties.
133 #
134 rule dependency ( )
135 {
136 if ! $(self.dependency-initialized)
137 {
138 init-dependency ;
139 }
140 return $(self.dependency) ;
141 }
142
143 rule non-dependency ( )
144 {
145 if ! $(self.dependency-initialized)
146 {
147 init-dependency ;
148 }
149 return $(self.non-dependency) ;
150 }
151
152 rule conditional ( )
153 {
154 if ! $(self.conditional-initialized)
155 {
156 init-conditional ;
157 }
158 return $(self.conditional) ;
159 }
160
161 rule non-conditional ( )
162 {
163 if ! $(self.conditional-initialized)
164 {
165 init-conditional ;
166 }
167 return $(self.non-conditional) ;
168 }
169
170 # Returns incidental properties.
171 #
172 rule incidental ( )
173 {
174 if ! $(self.base-initialized)
175 {
176 init-base ;
177 }
178 return $(self.incidental) ;
179 }
180
181 rule refine ( ps )
182 {
183 if ! $(self.refined.$(ps))
184 {
185 local r = [ property.refine $(self.raw) : [ $(ps).raw ] ] ;
186 if $(r[1]) != "@error"
187 {
188 self.refined.$(ps) = [ property-set.create $(r) ] ;
189 }
190 else
191 {
192 self.refined.$(ps) = $(r) ;
193 }
194 }
195 return $(self.refined.$(ps)) ;
196 }
197
198 rule expand ( )
199 {
200 if ! $(self.expanded)
201 {
202 self.expanded = [ property-set.create [ feature.expand $(self.raw) ]
203 ] ;
204 }
205 return $(self.expanded) ;
206 }
207
208 rule expand-composites ( )
209 {
210 if ! $(self.composites)
211 {
212 self.composites = [ property-set.create
213 [ feature.expand-composites $(self.raw) ] ] ;
214 }
215 return $(self.composites) ;
216 }
217
218 rule evaluate-conditionals ( context ? )
219 {
220 context ?= $(__name__) ;
221 if ! $(self.evaluated.$(context))
222 {
223 self.evaluated.$(context) = [ property-set.create
224 [ property.evaluate-conditionals-in-context $(self.raw) : [
225 $(context).raw ] ] ] ;
226 }
227 return $(self.evaluated.$(context)) ;
228 }
229
230 rule propagated ( )
231 {
232 if ! $(self.propagated-ps)
233 {
234 local result ;
235 for local p in $(self.raw)
236 {
237 if propagated in [ feature.attributes $(p:G) ]
238 {
239 result += $(p) ;
240 }
241 }
242 self.propagated-ps = [ property-set.create $(result) ] ;
243 }
244 return $(self.propagated-ps) ;
245 }
246
247 rule add-defaults ( )
248 {
249 if ! $(self.defaults)
250 {
251 self.defaults = [ property-set.create
252 [ feature.add-defaults $(self.raw) ] ] ;
253 }
254 return $(self.defaults) ;
255 }
256
257 rule as-path ( )
258 {
259 if ! $(self.as-path)
260 {
261 self.as-path = [ property.as-path [ base-relevant ] ] ;
262 }
263 return $(self.as-path) ;
264 }
265
266 # Computes the path to be used for a target with the given properties.
267 # Returns a list of
268 # - the computed path
269 # - if the path is relative to the build directory, a value of 'true'.
270 #
271 rule target-path ( )
272 {
273 if ! $(self.target-path)
274 {
275 # The <location> feature can be used to explicitly change the
276 # location of generated targets.
277 local l = [ get <location> ] ;
278 if $(l)
279 {
280 self.target-path = $(l) ;
281 }
282 else
283 {
284 local p = [ property-set.hash-maybe [ as-path ] ] ;
285
286 # A real ugly hack. Boost regression test system requires
287 # specific target paths, and it seems that changing it to handle
288 # other directory layout is really hard. For that reason, we
289 # teach V2 to do the things regression system requires. The
290 # value of '<location-prefix>' is prepended to the path.
291 local prefix = [ get <location-prefix> ] ;
292 if $(prefix)
293 {
294 self.target-path = [ path.join $(prefix) $(p) ] ;
295 }
296 else
297 {
298 self.target-path = $(p) ;
299 }
300 if ! $(self.target-path)
301 {
302 self.target-path = . ;
303 }
304 # The path is relative to build dir.
305 self.target-path += true ;
306 }
307 }
308 return $(self.target-path) ;
309 }
310
311 rule add ( ps )
312 {
313 if ! $(self.added.$(ps))
314 {
315 self.added.$(ps) = [ property-set.create $(self.raw) [ $(ps).raw ] ]
316 ;
317 }
318 return $(self.added.$(ps)) ;
319 }
320
321 rule add-raw ( properties * )
322 {
323 return [ add [ property-set.create $(properties) ] ] ;
324 }
325
326 # Returns all values of 'feature'.
327 #
328 rule get ( feature )
329 {
330 if ! $(self.map-built)
331 {
332 # For each feature, create a member var and assign all values to it.
333 # Since all regular member vars start with 'self', there will be no
334 # conflicts between names.
335 self.map-built = true ;
336 for local v in $(self.raw)
337 {
338 $(v:G) += $(v:G=) ;
339 }
340 }
341 return $($(feature)) ;
342 }
343
344 # Returns true if the property-set contains all the
345 # specified properties.
346 #
347 rule contains-raw ( properties * )
348 {
349 if $(properties) in $(self.raw)
350 {
351 return true ;
352 }
353 }
354
355 # Returns true if the property-set has values for
356 # all the specified features
357 #
358 rule contains-features ( features * )
359 {
360 if $(features) in $(self.raw:G)
361 {
362 return true ;
363 }
364 }
365
366 # private
367
368 rule init-base ( )
369 {
370 for local p in $(self.raw)
371 {
372 local att = [ feature.attributes $(p:G) ] ;
373 # A feature can be both incidental and free, in which case we add it
374 # to incidental.
375 if incidental in $(att)
376 {
377 self.incidental += $(p) ;
378 }
379 else if free in $(att)
380 {
381 self.free += $(p) ;
382 }
383 else
384 {
385 self.base += $(p) ;
386 }
387 }
388 self.base-initialized = true ;
389 }
390
391 rule init-relevant ( )
392 {
393 local relevant-features = [ get <relevant> ] ;
394 relevant-features = [ feature.expand-relevant $(relevant-features) ] ;
395 relevant-features = <$(relevant-features)> ;
396 ignore-relevance = [ modules.peek property-set : .ignore-relevance ] ;
397 for local p in $(self.raw)
398 {
399 if $(ignore-relevance) || $(p:G) in $(relevant-features)
400 {
401 local att = [ feature.attributes $(p:G) ] ;
402 if ! ( incidental in $(att) )
403 {
404 self.relevant += $(p) ;
405 if ! ( free in $(att) )
406 {
407 self.base-relevant += $(p) ;
408 }
409 }
410 }
411 }
412 self.relevant-initialized = true ;
413 }
414
415 rule init-dependency ( )
416 {
417 for local p in $(self.raw)
418 {
419 if dependency in [ feature.attributes $(p:G) ]
420 {
421 self.dependency += $(p) ;
422 }
423 else
424 {
425 self.non-dependency += $(p) ;
426 }
427 }
428 self.dependency-initialized = true ;
429 }
430
431 rule init-conditional ( )
432 {
433 for local p in $(self.raw)
434 {
435 # TODO: Note that non-conditional properties may contain colon (':')
436 # characters as well, e.g. free or indirect properties. Indirect
437 # properties for example contain a full Jamfile path in their value
438 # which on Windows file systems contains ':' as the drive separator.
439 if ( [ MATCH "(:)" : $(p:G=) ] && ! ( free in [ feature.attributes $(p:G) ] ) ) || $(p:G) = <conditional>
440 {
441 self.conditional += $(p) ;
442 }
443 else
444 {
445 self.non-conditional += $(p) ;
446 }
447 }
448 self.conditional-initialized = true ;
449 }
450 }
451
452 # This is a temporary measure to help users work around
453 # any problems. Remove it once we've verified that
454 # everything works.
455 if --ignore-relevance in [ modules.peek : ARGV ]
456 {
457 .ignore-relevance = true ;
458 }
459
460 # Creates a new 'property-set' instance for the given raw properties or returns
461 # an already existing ones.
462 #
463 rule create ( raw-properties * )
464 {
465 raw-properties = [ sequence.unique
466 [ sequence.insertion-sort $(raw-properties) ] ] ;
467
468 local key = $(raw-properties:J=-:E=) ;
469
470 if ! $(.ps.$(key))
471 {
472 .ps.$(key) = [ new property-set $(raw-properties) ] ;
473 }
474 return $(.ps.$(key)) ;
475 }
476 NATIVE_RULE property-set : create ;
477
478 if [ HAS_NATIVE_RULE class@property-set : get : 1 ]
479 {
480 NATIVE_RULE class@property-set : get ;
481 }
482
483 if [ HAS_NATIVE_RULE class@property-set : contains-features : 1 ]
484 {
485 NATIVE_RULE class@property-set : contains-features ;
486 }
487
488 # Creates a new 'property-set' instance after checking that all properties are
489 # valid and converting implicit properties into gristed form.
490 #
491 rule create-with-validation ( raw-properties * )
492 {
493 property.validate $(raw-properties) ;
494 return [ create [ property.make $(raw-properties) ] ] ;
495 }
496
497
498 # Creates a property-set from the input given by the user, in the context of
499 # 'jamfile-module' at 'location'.
500 #
501 rule create-from-user-input ( raw-properties * : jamfile-module location )
502 {
503 local project-id = [ project.attribute $(jamfile-module) id ] ;
504 project-id ?= [ path.root $(location) [ path.pwd ] ] ;
505 return [ property-set.create [ property.translate $(raw-properties)
506 : $(project-id) : $(location) : $(jamfile-module) ] ] ;
507 }
508
509
510 # Refines requirements with requirements provided by the user. Specially handles
511 # "-<property>value" syntax in specification to remove given requirements.
512 # - parent-requirements -- property-set object with requirements to refine.
513 # - specification -- string list of requirements provided by the user.
514 # - project-module -- module to which context indirect features will be
515 # bound.
516 # - location -- path to which path features are relative.
517 #
518 rule refine-from-user-input ( parent-requirements : specification * :
519 project-module : location )
520 {
521 if ! $(specification)
522 {
523 return $(parent-requirements) ;
524 }
525 else
526 {
527 local add-requirements ;
528 local remove-requirements ;
529
530 for local r in $(specification)
531 {
532 local m = [ MATCH "^-(.*)" : $(r) ] ;
533 if $(m)
534 {
535 remove-requirements += $(m) ;
536 }
537 else
538 {
539 add-requirements += $(r) ;
540 }
541 }
542
543 if $(remove-requirements)
544 {
545 # Need to create a property set, so that path features and indirect
546 # features are translated just like they are in project
547 # requirements.
548 local ps = [ property-set.create-from-user-input
549 $(remove-requirements) : $(project-module) $(location) ] ;
550
551 parent-requirements = [ property-set.create
552 [ set.difference [ $(parent-requirements).raw ]
553 : [ $(ps).raw ] ] ] ;
554 specification = $(add-requirements) ;
555 }
556
557 local requirements = [ property-set.create-from-user-input
558 $(specification) : $(project-module) $(location) ] ;
559
560 return [ $(parent-requirements).refine $(requirements) ] ;
561 }
562 }
563
564
565 # Returns a property-set with an empty set of properties.
566 #
567 rule empty ( )
568 {
569 if ! $(.empty)
570 {
571 .empty = [ create ] ;
572 }
573 return $(.empty) ;
574 }
575
576
577 if [ option.get hash : : yes ] = yes
578 {
579 rule hash-maybe ( path ? )
580 {
581 path ?= "" ;
582 return [ MD5 $(path) ] ;
583 }
584 }
585 else
586 {
587 rule hash-maybe ( path ? )
588 {
589 return $(path) ;
590 }
591 }