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