]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/src/build/feature.jam
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / tools / build / src / build / feature.jam
1 # Copyright 2001, 2002, 2003 Dave Abrahams
2 # Copyright 2002, 2006 Rene Rivera
3 # Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus
4 # Distributed under the Boost Software License, Version 1.0.
5 # (See accompanying file LICENSE_1_0.txt or copy at
6 # http://www.boost.org/LICENSE_1_0.txt)
7
8 import assert : * ;
9 import "class" : * ;
10 import indirect ;
11 import modules ;
12 import regex ;
13 import sequence ;
14 import set ;
15 import utility ;
16
17
18 local rule setup ( )
19 {
20 .all-attributes =
21 implicit
22 composite
23 optional
24 symmetric
25 free
26 incidental
27 path
28 dependency
29 propagated
30 link-incompatible
31 subfeature
32 order-sensitive
33 hidden
34 ;
35
36 .all-features = ;
37 .all-subfeatures = ;
38 .all-top-features = ; # non-subfeatures
39 .all-implicit-values = ;
40 }
41 setup ;
42
43
44 # Prepare a fresh space to test in by moving all global variable settings into
45 # the given temporary module and erasing them here.
46 #
47 rule prepare-test ( temp-module )
48 {
49 DELETE_MODULE $(temp-module) ;
50
51 # Transfer globals to temp-module.
52 for local v in [ VARNAMES feature ]
53 {
54 if [ MATCH (\\.) : $(v) ]
55 {
56 modules.poke $(temp-module) : $(v) : $($(v)) ;
57 $(v) = ;
58 }
59 }
60 setup ;
61 }
62
63
64 # Clear out all global variables and recover all variables from the given
65 # temporary module.
66 #
67 rule finish-test ( temp-module )
68 {
69 # Clear globals.
70 for local v in [ VARNAMES feature ]
71 {
72 if [ MATCH (\\.) : $(v) ]
73 {
74 $(v) = ;
75 }
76 }
77
78 for local v in [ VARNAMES $(temp-module) ]
79 {
80 $(v) = [ modules.peek $(temp-module) : $(v) ] ;
81 }
82 DELETE_MODULE $(temp-module) ;
83 }
84
85
86 # Transform features by bracketing any elements which are not already bracketed
87 # by "<>".
88 #
89 local rule grist ( features * )
90 {
91 local empty = "" ;
92 return $(empty:G=$(features)) ;
93 }
94
95
96 # Declare a new feature with the given name, values, and attributes.
97 #
98 rule feature (
99 name # Feature name.
100 : values * # Allowable values - may be extended later using feature.extend.
101 : attributes * # Feature attributes (e.g. implicit, free, propagated...).
102 )
103 {
104 name = [ grist $(name) ] ;
105
106 local error ;
107
108 # Check for any unknown attributes.
109 if ! ( $(attributes) in $(.all-attributes) )
110 {
111 error = unknown "attributes:"
112 [ set.difference $(attributes) : $(.all-attributes) ] ;
113 }
114 else if $(name) in $(.all-features)
115 {
116 error = feature already "defined:" ;
117 }
118 else if implicit in $(attributes) && free in $(attributes)
119 {
120 error = free features cannot also be implicit ;
121 }
122 else if free in $(attributes) && propagated in $(attributes)
123 {
124 error = free features cannot be propagated ;
125 }
126 else
127 {
128 local m = [ MATCH (.*=.*) : $(values) ] ;
129 if $(m[1])
130 {
131 error = "feature value may not contain '='" ;
132 }
133 }
134
135 if $(error)
136 {
137 import errors ;
138 errors.error $(error)
139 : "in" feature "declaration:"
140 : feature [ errors.lol->list $(1) : $(2) : $(3) ] ;
141 }
142
143 $(name).values ?= ;
144 $(name).attributes = $(attributes) ;
145 $(name).subfeatures ?= ;
146 $(attributes).features += $(name) ;
147
148 .all-features += $(name) ;
149 if subfeature in $(attributes)
150 {
151 .all-subfeatures += $(name) ;
152 }
153 else
154 {
155 .all-top-features += $(name) ;
156 }
157 extend $(name) : $(values) ;
158 }
159
160
161 # Sets the default value of the given feature, overriding any previous default.
162 #
163 rule set-default ( feature : value )
164 {
165 local f = [ grist $(feature) ] ;
166 local a = $($(f).attributes) ;
167 local bad-attribute = ;
168 if free in $(a)
169 {
170 bad-attribute = free ;
171 }
172 else if optional in $(a)
173 {
174 bad-attribute = optional ;
175 }
176 if $(bad-attribute)
177 {
178 import errors ;
179 errors.error $(bad-attribute) property $(f) cannot have a default. ;
180 }
181 if ! $(value) in $($(f).values)
182 {
183 import errors ;
184 errors.error The specified default value, '$(value)' is invalid :
185 allowed values "are:" $($(f).values) ;
186 }
187 $(f).default = $(value) ;
188 }
189
190
191 # Returns the default property values for the given features.
192 #
193 rule defaults ( features * )
194 {
195 local result ;
196 for local f in $(features)
197 {
198 local gf = $(:E=:G=$(f)) ;
199 local a = $($(gf).attributes) ;
200 if ( free in $(a) ) || ( optional in $(a) )
201 {
202 }
203 else
204 {
205 result += $(gf)$($(gf).default) ;
206 }
207 }
208 return $(result) ;
209 }
210
211
212 # Returns true iff all 'names' elements are valid features.
213 #
214 rule valid ( names + )
215 {
216 if $(names) in $(.all-features)
217 {
218 return true ;
219 }
220 }
221
222
223 # Returns the attributes of the given feature.
224 #
225 rule attributes ( feature )
226 {
227 return $($(feature).attributes) ;
228 }
229
230
231 # Returns the values of the given feature.
232 #
233 rule values ( feature )
234 {
235 return $($(:E=:G=$(feature)).values) ;
236 }
237
238
239 # Returns true iff 'value-string' is a value-string of an implicit feature.
240 #
241 rule is-implicit-value ( value-string )
242 {
243 local v = [ regex.split $(value-string) - ] ;
244 local failed ;
245 if ! $(v[1]) in $(.all-implicit-values)
246 {
247 failed = true ;
248 }
249 else
250 {
251 local feature = $($(v[1]).implicit-feature) ;
252 for local subvalue in $(v[2-])
253 {
254 if ! [ find-implied-subfeature $(feature) $(subvalue) : $(v[1]) ]
255 {
256 failed = true ;
257 }
258 }
259 }
260
261 if ! $(failed)
262 {
263 return true ;
264 }
265 }
266
267
268 # Returns the implicit feature associated with the given implicit value.
269 #
270 rule implied-feature ( implicit-value )
271 {
272 local components = [ regex.split $(implicit-value) "-" ] ;
273 local feature = $($(components[1]).implicit-feature) ;
274 if ! $(feature)
275 {
276 import errors ;
277 errors.error \"$(implicit-value)\" is not an implicit feature value ;
278 feature = "" ; # Keep testing happy; it expects a result.
279 }
280 return $(feature) ;
281 }
282
283
284 local rule find-implied-subfeature ( feature subvalue : value-string ? )
285 {
286 # Feature should be of the form <feature-name>.
287 if $(feature) != $(feature:G)
288 {
289 import errors ;
290 errors.error invalid feature $(feature) ;
291 }
292 value-string += "" ;
293 return $($(feature)$(value-string)<>$(subvalue).subfeature) ;
294 }
295
296
297 # Given a feature and a value of one of its subfeatures, find the name of the
298 # subfeature. If value-string is supplied, looks for implied subfeatures that
299 # are specific to that value of feature
300 #
301 rule implied-subfeature (
302 feature # The main feature name.
303 subvalue # The value of one of its subfeatures.
304 : value-string ? # The value of the main feature.
305 )
306 {
307 local subfeature = [ find-implied-subfeature $(feature) $(subvalue)
308 : $(value-string) ] ;
309 if ! $(subfeature)
310 {
311 value-string ?= "" ;
312 import errors ;
313 errors.error \"$(subvalue)\" is not a known subfeature value of
314 $(feature)$(value-string) ;
315 }
316 return $(subfeature) ;
317 }
318
319
320 # Generate an error if the feature is unknown.
321 #
322 local rule validate-feature ( feature )
323 {
324 if ! $(feature) in $(.all-features)
325 {
326 import errors ;
327 errors.error unknown feature \"$(feature)\" ;
328 }
329 }
330
331
332 # Given a feature and its value or just a value corresponding to an implicit
333 # feature, returns a property set consisting of all component subfeatures and
334 # their values. For example all the following calls:
335 #
336 # expand-subfeatures-aux <toolset>gcc-2.95.2-linux-x86
337 # expand-subfeatures-aux gcc-2.95.2-linux-x86
338 #
339 # return:
340 #
341 # <toolset>gcc <toolset-version>2.95.2 <toolset-os>linux <toolset-cpu>x86
342 #
343 local rule expand-subfeatures-aux (
344 feature ? # Feature name or empty if value corresponds to an
345 # implicit property.
346 : value # Feature value.
347 : dont-validate ? # If set, no value string validation will be done.
348 )
349 {
350 if $(feature)
351 {
352 feature = $(feature) ;
353 }
354
355 if ! $(feature)
356 {
357 feature = [ implied-feature $(value) ] ;
358 }
359 else
360 {
361 validate-feature $(feature) ;
362 }
363 if ! $(dont-validate)
364 {
365 validate-value-string $(feature) $(value) ;
366 }
367
368 local components = [ regex.split $(value) "-" ] ;
369
370 # Get the top-level feature's value.
371 local value = $(components[1]:G=) ;
372
373 local result = $(components[1]:G=$(feature)) ;
374
375 for local subvalue in $(components[2-])
376 {
377 local subfeature = [ find-implied-subfeature $(feature) $(subvalue) :
378 $(value) ] ;
379
380 # If no subfeature was found reconstitute the value string and use that.
381 if ! $(subfeature)
382 {
383 result = $(components:J=-) ;
384 result = $(result:G=$(feature)) ;
385 break ;
386 }
387 else
388 {
389 local f = [ MATCH ^<(.*)>$ : $(feature) ] ;
390 result += $(subvalue:G=$(f)-$(subfeature)) ;
391 }
392 }
393
394 return $(result) ;
395 }
396
397
398 # Make all elements of properties corresponding to implicit features explicit,
399 # and express all subfeature values as separate properties in their own right.
400 # For example, all of the following properties
401 #
402 # gcc-2.95.2-linux-x86
403 # <toolset>gcc-2.95.2-linux-x86
404 #
405 # might expand to
406 #
407 # <toolset>gcc <toolset-version>2.95.2 <toolset-os>linux <toolset-cpu>x86
408 #
409 rule expand-subfeatures (
410 properties * # Property set with elements of the form
411 # <feature>value-string or just value-string in the case
412 # of implicit features.
413 : dont-validate ?
414 )
415 {
416 local result ;
417 for local p in $(properties)
418 {
419 # Don't expand subfeatures in subfeatures
420 if ! [ MATCH "(:)" : $(p:G) ]
421 {
422 result += [ expand-subfeatures-aux $(p:G) : $(p:G=) : $(dont-validate) ] ;
423 }
424 else
425 {
426 result += $(p) ;
427 }
428 }
429 return $(result) ;
430 }
431
432
433 # Helper for extend, below. Handles the feature case.
434 #
435 local rule extend-feature ( feature : values * )
436 {
437 feature = [ grist $(feature) ] ;
438 validate-feature $(feature) ;
439 if implicit in $($(feature).attributes)
440 {
441 for local v in $(values)
442 {
443 if $($(v).implicit-feature)
444 {
445 import errors ;
446 errors.error $(v) is already associated with the
447 \"$($(v).implicit-feature)\" feature ;
448 }
449 $(v).implicit-feature = $(feature) ;
450 }
451
452 .all-implicit-values += $(values) ;
453 }
454 if ! $($(feature).values)
455 {
456 # This is the first value specified for this feature so make it be the
457 # default.
458 $(feature).default = $(values[1]) ;
459 }
460 $(feature).values += $(values) ;
461 }
462
463
464 # Checks that value-string is a valid value-string for the given feature.
465 #
466 rule validate-value-string ( feature value-string )
467 {
468 if ! (
469 free in $($(feature).attributes)
470 || ( $(value-string) in $(feature).values )
471 )
472 {
473 local values = $(value-string) ;
474
475 if $($(feature).subfeatures)
476 {
477 if ! $(value-string) in $($(feature).values)
478 $($(feature).subfeatures)
479 {
480 values = [ regex.split $(value-string) - ] ;
481 }
482 }
483
484 if ! ( $(values[1]) in $($(feature).values) ) &&
485
486 # An empty value is allowed for optional features.
487 ( $(values[1]) || ! ( optional in $($(feature).attributes) ) )
488 {
489 import errors ;
490 errors.error \"$(values[1])\" is not a known value of feature
491 $(feature) : legal "values:" \"$($(feature).values)\" ;
492 }
493
494 for local v in $(values[2-])
495 {
496 # This will validate any subfeature values in value-string.
497 implied-subfeature $(feature) $(v) : $(values[1]) ;
498 }
499 }
500 }
501
502
503 # A helper that computes:
504 # * name(s) of module-local variable(s) used to record the correspondence
505 # between subvalue(s) and a subfeature
506 # * value of that variable when such a subfeature/subvalue has been defined and
507 # returns a list consisting of the latter followed by the former.
508 #
509 local rule subvalue-var (
510 feature # Main feature name.
511 value-string ? # If supplied, specifies a specific value of the main
512 # feature for which the subfeature values are valid.
513 : subfeature # Subfeature name.
514 : subvalues * # Subfeature values.
515 )
516 {
517 feature = [ grist $(feature) ] ;
518 validate-feature $(feature) ;
519 if $(value-string)
520 {
521 validate-value-string $(feature) $(value-string) ;
522 }
523
524 local subfeature-name = [ get-subfeature-name $(subfeature) $(value-string) ] ;
525
526 return $(subfeature-name)
527 $(feature)$(value-string:E="")<>$(subvalues).subfeature ;
528 }
529
530
531 # Extends the given subfeature with the subvalues. If the optional value-string
532 # is provided, the subvalues are only valid for the given value of the feature.
533 # Thus, you could say that <target-platform>mingw is specific to
534 # <toolset>gcc-2.95.2 as follows:
535 #
536 # extend-subfeature toolset gcc-2.95.2 : target-platform : mingw ;
537 #
538 rule extend-subfeature (
539 feature # The feature whose subfeature is being extended.
540
541 value-string ? # If supplied, specifies a specific value of the main
542 # feature for which the new subfeature values are valid.
543
544 : subfeature # Subfeature name.
545 : subvalues * # Additional subfeature values.
546 )
547 {
548 local subfeature-vars = [ subvalue-var $(feature) $(value-string)
549 : $(subfeature) : $(subvalues) ] ;
550
551 local f = [ utility.ungrist [ grist $(feature) ] ] ;
552 extend $(f)-$(subfeature-vars[1]) : $(subvalues) ;
553
554 # Provide a way to get from the given feature or property and subfeature
555 # value to the subfeature name.
556 $(subfeature-vars[2-]) = $(subfeature-vars[1]) ;
557 }
558
559
560 # Returns true iff the subvalues are valid for the feature. When the optional
561 # value-string is provided, returns true iff the subvalues are valid for the
562 # given value of the feature.
563 #
564 rule is-subvalue ( feature : value-string ? : subfeature : subvalue )
565 {
566 local subfeature-vars = [ subvalue-var $(feature) $(value-string)
567 : $(subfeature) : $(subvalue) ] ;
568
569 if $($(subfeature-vars[2])) = $(subfeature-vars[1])
570 {
571 return true ;
572 }
573 }
574
575
576 # Can be called three ways:
577 #
578 # 1. extend feature : values *
579 # 2. extend <feature> subfeature : values *
580 # 3. extend <feature>value-string subfeature : values *
581 #
582 # * Form 1 adds the given values to the given feature.
583 # * Forms 2 and 3 add subfeature values to the given feature.
584 # * Form 3 adds the subfeature values as specific to the given property
585 # value-string.
586 #
587 rule extend ( feature-or-property subfeature ? : values * )
588 {
589 local feature ; # If a property was specified this is its feature.
590 local value-string ; # E.g., the gcc-2.95-2 part of <toolset>gcc-2.95.2.
591
592 # If a property was specified.
593 if $(feature-or-property:G) && $(feature-or-property:G=)
594 {
595 # Extract the feature and value-string, if any.
596 feature = $(feature-or-property:G) ;
597 value-string = $(feature-or-property:G=) ;
598 }
599 else
600 {
601 feature = [ grist $(feature-or-property) ] ;
602 }
603
604 # Dispatch to the appropriate handler.
605 if $(subfeature)
606 {
607 extend-subfeature $(feature) $(value-string) : $(subfeature)
608 : $(values) ;
609 }
610 else
611 {
612 # If no subfeature was specified, we do not expect to see a
613 # value-string.
614 if $(value-string)
615 {
616 import errors ;
617 errors.error can only specify a property as the first argument when
618 extending a subfeature
619 : "usage:"
620 : " extend" feature ":" values...
621 : " | extend" <feature>value-string subfeature ":" values... ;
622 }
623
624 extend-feature $(feature) : $(values) ;
625 }
626 }
627
628
629 local rule get-subfeature-name ( subfeature value-string ? )
630 {
631 local prefix = "$(value-string):" ;
632 return $(prefix:E="")$(subfeature) ;
633 }
634
635
636 # Declares a subfeature.
637 #
638 rule subfeature (
639 feature # Root feature that is not a subfeature.
640 value-string ? # A value-string specifying which feature or subfeature
641 # values this subfeature is specific to, if any.
642 : subfeature # The name of the subfeature being declared.
643 : subvalues * # The allowed values of this subfeature.
644 : attributes * # The attributes of the subfeature.
645 )
646 {
647 feature = [ grist $(feature) ] ;
648 validate-feature $(feature) ;
649
650 # Add grist to the subfeature name if a value-string was supplied.
651 local subfeature-name = [ get-subfeature-name $(subfeature) $(value-string) ] ;
652
653 if $(subfeature-name) in $($(feature).subfeatures)
654 {
655 import errors ;
656 errors.error \"$(subfeature)\" already declared as a subfeature of
657 \"$(feature)\" "specific to "$(value-string) ;
658 }
659 $(feature).subfeatures += $(subfeature-name) ;
660
661 # First declare the subfeature as a feature in its own right.
662 local f = [ utility.ungrist $(feature) ] ;
663 feature $(f)-$(subfeature-name) : $(subvalues) : $(attributes) subfeature ;
664
665 # Features and subfeatures are always relevant as a group
666 .feature-dependencies.$(f) += $(f)-$(subfeature-name) ;
667 .feature-dependencies.$(f)-$(subfeature-name) += $(f) ;
668
669 # Now make sure the subfeature values are known.
670 extend-subfeature $(feature) $(value-string) : $(subfeature) : $(subvalues) ;
671 }
672
673
674 # Set components of the given composite property.
675 #
676 rule compose ( composite-property : component-properties * )
677 {
678 local feature = $(composite-property:G) ;
679 if ! ( composite in [ attributes $(feature) ] )
680 {
681 import errors ;
682 errors.error "$(feature)" is not a composite feature ;
683 }
684
685 $(composite-property).components ?= ;
686 if $($(composite-property).components)
687 {
688 import errors ;
689 errors.error components of "$(composite-property)" already "set:"
690 $($(composite-property).components) ;
691 }
692
693 if $(composite-property) in $(component-properties)
694 {
695 import errors ;
696 errors.error composite property "$(composite-property)" cannot have itself as a component ;
697 }
698 $(composite-property).components = $(component-properties) ;
699
700 # A composite feature is relevant if any composed feature is relevant
701 local component-features = [ sequence.transform utility.ungrist : $(component-properties:G) ] ;
702 .feature-dependencies.$(component-features) += [ utility.ungrist $(feature) ] ;
703 }
704
705
706 local rule expand-composite ( property )
707 {
708 return $(property)
709 [ sequence.transform expand-composite : $($(property).components) ] ;
710 }
711
712
713 # Return all values of the given feature specified by the given property set.
714 #
715 rule get-values ( feature : properties * )
716 {
717 local result ;
718
719 feature = $(:E=:G=$(feature)) ; # Add <> if necessary.
720 for local p in $(properties)
721 {
722 if $(p:G) = $(feature)
723 {
724 # Use MATCH instead of :G= to get the value, in order to preserve
725 # the value intact instead of having bjam treat it as a decomposable
726 # path.
727 result += [ MATCH ">(.*)" : $(p) ] ;
728 }
729 }
730 return $(result) ;
731 }
732
733
734 rule free-features ( )
735 {
736 return $(free.features) ;
737 }
738
739
740 # Expand all composite properties in the set so that all components are
741 # explicitly expressed.
742 #
743 rule expand-composites ( properties * )
744 {
745 local explicit-features = $(properties:G) ;
746 local result ;
747
748 # Now expand composite features.
749 for local p in $(properties)
750 {
751 local expanded = [ expand-composite $(p) ] ;
752
753 for local x in $(expanded)
754 {
755 if ! $(x) in $(result)
756 {
757 local f = $(x:G) ;
758
759 if $(f) in $(free.features)
760 {
761 result += $(x) ;
762 }
763 else if ! $(x) in $(properties) # x is the result of expansion
764 {
765 if ! $(f) in $(explicit-features) # not explicitly-specified
766 {
767 if $(f) in $(result:G)
768 {
769 import errors ;
770 errors.error expansions of composite features result
771 in conflicting values for $(f)
772 : "values:" [ get-values $(f) : $(result) ] $(x:G=)
773 : one contributing composite property was $(p) ;
774 }
775 else
776 {
777 result += $(x) ;
778 }
779 }
780 }
781 else if $(f) in $(result:G)
782 {
783 import errors ;
784 errors.error explicitly-specified values of non-free feature
785 $(f) conflict :
786 "existing values:" [ get-values $(f) : $(properties) ] :
787 "value from expanding " $(p) ":" $(x:G=) ;
788 }
789 else
790 {
791 result += $(x) ;
792 }
793 }
794 }
795 }
796 return $(result) ;
797 }
798
799
800 # Return true iff f is an ordinary subfeature of the parent-property's feature,
801 # or if f is a subfeature of the parent-property's feature specific to the
802 # parent-property's value.
803 #
804 local rule is-subfeature-of ( parent-property f )
805 {
806 if subfeature in $($(f).attributes)
807 {
808 local specific-subfeature = [ MATCH <(.*):(.*)> : $(f) ] ;
809 if $(specific-subfeature)
810 {
811 # The feature has the form <topfeature-topvalue:subfeature>, e.g.
812 # <toolset-msvc:version>.
813 local feature-value = [ split-top-feature $(specific-subfeature[1])
814 ] ;
815 if <$(feature-value[1])>$(feature-value[2]) = $(parent-property)
816 {
817 return true ;
818 }
819 }
820 else
821 {
822 # The feature has the form <topfeature-subfeature>, e.g.
823 # <toolset-version>
824 local top-sub = [ split-top-feature [ utility.ungrist $(f) ] ] ;
825 if $(top-sub[2]) && <$(top-sub[1])> = $(parent-property:G)
826 {
827 return true ;
828 }
829 }
830 }
831 }
832
833
834 # As for is-subfeature-of but for subproperties.
835 #
836 local rule is-subproperty-of ( parent-property p )
837 {
838 return [ is-subfeature-of $(parent-property) $(p:G) ] ;
839 }
840
841
842 # Given a property, return the subset of features consisting of all ordinary
843 # subfeatures of the property's feature, and all specific subfeatures of the
844 # property's feature which are conditional on the property's value.
845 #
846 local rule select-subfeatures ( parent-property : features * )
847 {
848 return [ sequence.filter is-subfeature-of $(parent-property) : $(features) ] ;
849 }
850
851
852 # As for select-subfeatures but for subproperties.
853 #
854 local rule select-subproperties ( parent-property : properties * )
855 {
856 return [ sequence.filter is-subproperty-of $(parent-property) : $(properties) ] ;
857 }
858
859
860 # Given a property set which may consist of composite and implicit properties
861 # and combined subfeature values, returns an expanded, normalized property set
862 # with all implicit features expressed explicitly, all subfeature values
863 # individually expressed, and all components of composite properties expanded.
864 # Non-free features directly expressed in the input properties cause any values
865 # of those features due to composite feature expansion to be dropped. If two
866 # values of a given non-free feature are directly expressed in the input, an
867 # error is issued.
868 #
869 rule expand ( properties * )
870 {
871 local expanded = [ expand-subfeatures $(properties) ] ;
872 return [ expand-composites $(expanded) ] ;
873 }
874
875
876 # Helper rule for minimize. Returns true iff property's feature is present in
877 # the contents of the variable named by feature-set-var.
878 #
879 local rule in-features ( feature-set-var property )
880 {
881 if $(property:G) in $($(feature-set-var))
882 {
883 return true ;
884 }
885 }
886
887
888 # Helper rule for minimize. Returns the list with the same properties, but with
889 # all subfeatures moved to the end of the list.
890 #
891 local rule move-subfeatures-to-the-end ( properties * )
892 {
893 local x1 ;
894 local x2 ;
895 for local p in $(properties)
896 {
897 if subfeature in $($(p:G).attributes)
898 {
899 x2 += $(p) ;
900 }
901 else
902 {
903 x1 += $(p) ;
904 }
905 }
906 return $(x1) $(x2) ;
907 }
908
909
910 # Given an expanded property set, eliminate all redundancy: properties that are
911 # elements of other (composite) properties in the set will be eliminated.
912 # Non-symmetric properties equal to default values will be eliminated unless
913 # they override a value from some composite property. Implicit properties will
914 # be expressed without feature grist, and sub-property values will be expressed
915 # as elements joined to the corresponding main property.
916 #
917 rule minimize ( properties * )
918 {
919 # Precondition checking
920 local implicits = [ set.intersection $(p:G=) : $(p:G) ] ;
921 if $(implicits)
922 {
923 import errors ;
924 errors.error minimize requires an expanded property set, but
925 \"$(implicits[1])\" appears to be the value of an un-expanded
926 implicit feature ;
927 }
928
929 # Remove properties implied by composite features.
930 local components = $($(properties).components) ;
931 local x = [ set.difference $(properties) : $(components) ] ;
932
933 # Handle subfeatures and implicit features.
934 x = [ move-subfeatures-to-the-end $(x) ] ;
935 local result ;
936 while $(x)
937 {
938 local p fullp = $(x[1]) ;
939 local f = $(p:G) ;
940 local v = $(p:G=) ;
941
942 # Eliminate features in implicit properties.
943 if implicit in [ attributes $(f) ]
944 {
945 p = $(v) ;
946 }
947
948 # Locate all subproperties of $(x[1]) in the property set.
949 local subproperties = [ select-subproperties $(fullp) : $(x) ] ;
950 if $(subproperties)
951 {
952 # Reconstitute the joined property name.
953 local sorted = [ sequence.insertion-sort $(subproperties) ] ;
954 result += $(p)-$(sorted:G="":J=-) ;
955
956 x = [ set.difference $(x[2-]) : $(subproperties) ] ;
957 }
958 else
959 {
960 # Eliminate properties whose value is equal to feature's default,
961 # which are not symmetric and which do not contradict values implied
962 # by composite properties.
963
964 # Since all component properties of composites in the set have been
965 # eliminated, any remaining property whose feature is the same as a
966 # component of a composite in the set must have a non-redundant
967 # value.
968 if $(fullp) != [ defaults $(f) ]
969 || symmetric in [ attributes $(f) ]
970 || $(fullp:G) in $(components:G)
971 {
972 result += $(p) ;
973 }
974
975 x = $(x[2-]) ;
976 }
977 }
978 return $(result) ;
979 }
980
981
982 # Combine all subproperties into their parent properties
983 #
984 # Requires: for every subproperty, there is a parent property. All features are
985 # explicitly expressed.
986 #
987 # This rule probably should not be needed, but build-request.expand-no-defaults
988 # is being abused for unintended purposes and it needs help.
989 #
990 rule compress-subproperties ( properties * )
991 {
992 local all-subs ;
993 local matched-subs ;
994 local result ;
995
996 for local p in $(properties)
997 {
998 if ! $(p:G)
999 {
1000 # Expecting fully-gristed properties.
1001 assert.variable-not-empty "p:G" ;
1002 }
1003
1004 if ! subfeature in $($(p:G).attributes)
1005 {
1006 local subs = [ sequence.insertion-sort
1007 [ sequence.filter is-subproperty-of $(p) : $(properties) ] ] ;
1008
1009 matched-subs += $(subs) ;
1010
1011 local subvalues = -$(subs:G=:J=-) ;
1012 subvalues ?= "" ;
1013 result += $(p)$(subvalues) ;
1014 }
1015 else
1016 {
1017 all-subs += $(p) ;
1018 }
1019 }
1020 assert.result true : set.equal $(all-subs) : $(matched-subs) ;
1021 return $(result) ;
1022 }
1023
1024
1025 # Given an ungristed string, finds the longest prefix which is a top-level
1026 # feature name followed by a dash, and return a pair consisting of the parts
1027 # before and after that dash. More interesting than a simple split because
1028 # feature names may contain dashes.
1029 #
1030 local rule split-top-feature ( feature-plus )
1031 {
1032 local e = [ regex.split $(feature-plus) - ] ;
1033 local f = $(e[1]) ;
1034 local v ;
1035 while $(e)
1036 {
1037 if <$(f)> in $(.all-top-features)
1038 {
1039 v = $(f) $(e[2-]:J=-) ;
1040 }
1041 e = $(e[2-]) ;
1042 f = $(f)-$(e[1]) ;
1043 }
1044 return $(v) ;
1045 }
1046
1047
1048 # Given a set of properties, add default values for features not represented in
1049 # the set.
1050 #
1051 # properties must be fully expanded and must not contain conditionals.
1052 #
1053 # Note: if there's an ordinary feature F1 and a composite feature F2 which
1054 # includes some value for F1 and both feature have default values then the
1055 # default value of F1 will be added (as opposed to the value in F2). This might
1056 # not be the right idea, e.g. consider:
1057 #
1058 # feature variant : debug ... ;
1059 # <variant>debug : .... <runtime-debugging>on
1060 # feature <runtime-debugging> : off on ;
1061 #
1062 # Here, when adding default for an empty property set, we'll get
1063 #
1064 # <variant>debug <runtime_debugging>off
1065 #
1066 # and that's kind of strange.
1067 #
1068 rule add-defaults ( properties * )
1069 {
1070 for local v in $(properties:G=)
1071 {
1072 if $(v) in $(properties)
1073 {
1074 import errors ;
1075 errors.error add-defaults requires explicitly specified features,
1076 but \"$(v)\" appears to be the value of an un-expanded implicit
1077 feature ;
1078 }
1079 }
1080 local missing-top = [ set.difference $(.all-top-features) : $(properties:G) ] ;
1081 local more = [ defaults $(missing-top) ] ;
1082
1083 # This is similar to property.refine, except that it
1084 # does not remove subfeatures, because we might be adding
1085 # the default value of a subfeature.
1086 local to-remove ;
1087 for local f in $(properties:G)
1088 {
1089 if ! free in [ attributes $(f) ]
1090 {
1091 to-remove += $(f) ;
1092 }
1093 }
1094
1095 local worklist = $(properties) $(more) ;
1096 local expanded-from-composite ;
1097 local to-expand = $(more) ;
1098 while $(worklist)
1099 {
1100 # Add defaults for subfeatures of features which are present.
1101 for local p in $(worklist)
1102 {
1103 local s = $($(p:G).subfeatures) ;
1104 local f = [ utility.ungrist $(p:G) ] ;
1105 local missing-subs = [ set.difference <$(f)-$(s)> : $(properties:G) ] ;
1106 local sd = [ defaults [ select-subfeatures $(p) : $(missing-subs) ] ] ;
1107 to-expand += $(sd) ;
1108 }
1109 worklist = ;
1110
1111 # Expand subfeatures of newly added properties
1112 for local m in [ sequence.transform expand-composite : $(to-expand) ]
1113 {
1114 if ! $(m:G) in $(to-remove)
1115 {
1116 local att = [ attributes $(m:G) ] ;
1117 if $(m:G) in $(expanded-from-composite) &&
1118 ! free in $(att) &&
1119 ! $(m) in $(more)
1120 {
1121 import errors ;
1122 errors.error "default values for $(p:G) conflict" ;
1123 }
1124 if ! $(m) in $(to-expand)
1125 {
1126 expanded-from-composite += $(m:G) ;
1127 }
1128 more += $(m) ;
1129 if ! subfeature in $(att) && ! free in $(att)
1130 {
1131 worklist += $(m) ;
1132 }
1133 }
1134 }
1135 to-expand = ;
1136 }
1137
1138 return [ sequence.unique $(properties) $(more) ] ;
1139 }
1140
1141
1142 # Given a property-set of the form
1143 # v1/v2/...vN-1/<fN>vN/<fN+1>vN+1/...<fM>vM
1144 #
1145 # Returns
1146 # v1 v2 ... vN-1 <fN>vN <fN+1>vN+1 ... <fM>vM
1147 #
1148 # Note that vN...vM may contain slashes. This needs to be resilient to the
1149 # substitution of backslashes for slashes, since Jam, unbidden, sometimes swaps
1150 # slash direction on NT.
1151 #
1152 rule split ( property-set )
1153 {
1154 local pieces = [ regex.split $(property-set) "[\\/]" ] ;
1155 local result ;
1156
1157 for local x in $(pieces)
1158 {
1159 if ( ! $(x:G) ) && $(result[-1]:G)
1160 {
1161 result = $(result[1--2]) $(result[-1])/$(x) ;
1162 }
1163 else
1164 {
1165 result += $(x) ;
1166 }
1167 }
1168
1169 return $(result) ;
1170 }
1171
1172 # Returns all the features that also must be relevant when these features are relevant
1173 rule expand-relevant ( features * )
1174 {
1175 local conditional ;
1176 local result ;
1177 for f in $(features)
1178 {
1179 # This looks like a conditional, even though it isn't really.
1180 # (Free features can never be used in conditionals)
1181 local split = [ MATCH "^(.*):<relevant>(.*)$" : $(f) ] ;
1182 if $(split)
1183 {
1184 local-dependencies.$(split[1]) += $(split[2]) ;
1185 conditional += local-dependencies.$(split[1]) ;
1186 }
1187 else
1188 {
1189 result += $(f) ;
1190 }
1191 }
1192 local queue = $(result) ;
1193 while $(queue)
1194 {
1195 local added = [ set.difference
1196 $(.feature-dependencies.$(queue))
1197 $(local-dependencies.$(queue))
1198 : $(result) ] ;
1199 result += $(added) ;
1200 queue = $(added) ;
1201 }
1202 # Clean up local map
1203 $(conditional) = ;
1204 return $(result) ;
1205 }
1206
1207
1208 # Tests of module feature.
1209 #
1210 rule __test__ ( )
1211 {
1212 # Use a fresh copy of the feature module.
1213 prepare-test feature-test-temp ;
1214
1215 import assert ;
1216 import errors : try catch ;
1217
1218 # These are local rules and so must be explicitly reimported into the
1219 # testing module.
1220 import feature : extend-feature validate-feature select-subfeatures ;
1221
1222 feature toolset : gcc : implicit ;
1223 feature define : : free ;
1224 feature runtime-link : dynamic static : symmetric ;
1225 feature optimization : on off ;
1226 feature variant : debug release profile : implicit composite symmetric ;
1227 feature stdlib : native stlport ;
1228 feature magic : : free ;
1229
1230 compose <variant>debug : <define>_DEBUG <optimization>off ;
1231 compose <variant>release : <define>NDEBUG <optimization>on ;
1232
1233 assert.result dynamic static : values <runtime-link> ;
1234 assert.result dynamic static : values runtime-link ;
1235
1236 try ;
1237 {
1238 compose <variant>profile : <variant>profile ;
1239 }
1240 catch composite property <variant>profile cannot have itself as a component ;
1241
1242 extend-feature toolset : msvc metrowerks ;
1243 subfeature toolset gcc : version : 2.95.2 2.95.3 2.95.4 3.0 3.0.1 3.0.2 ;
1244
1245 assert.true is-subvalue toolset : gcc : version : 2.95.3 ;
1246 assert.false is-subvalue toolset : gcc : version : 1.1 ;
1247
1248 assert.false is-subvalue toolset : msvc : version : 2.95.3 ;
1249 assert.false is-subvalue toolset : : version : yabba ;
1250
1251 feature yabba ;
1252 subfeature yabba : version : dabba ;
1253 assert.true is-subvalue yabba : : version : dabba ;
1254
1255 subfeature toolset gcc : platform : linux cygwin : optional ;
1256
1257 assert.result <toolset-gcc:version>
1258 : select-subfeatures <toolset>gcc
1259 : <toolset-gcc:version>
1260 <toolset-msvc:version>
1261 <toolset-version>
1262 <stdlib> ;
1263
1264 subfeature stdlib : version : 3 4 : optional ;
1265
1266 assert.result <stdlib-version>
1267 : select-subfeatures <stdlib>native
1268 : <toolset-gcc:version>
1269 <toolset-msvc:version>
1270 <toolset-version>
1271 <stdlib-version> ;
1272
1273 assert.result <toolset>gcc <toolset-gcc:version>3.0.1
1274 : expand-subfeatures <toolset>gcc-3.0.1 ;
1275
1276 assert.result <toolset>gcc <toolset-gcc:version>3.0.1 <toolset-gcc:platform>linux
1277 : expand-subfeatures <toolset>gcc-3.0.1-linux ;
1278
1279 assert.result <toolset>gcc <toolset-gcc:version>3.0.1
1280 : expand <toolset>gcc <toolset-gcc:version>3.0.1 ;
1281
1282 assert.result <define>foo=x-y
1283 : expand-subfeatures <define>foo=x-y ;
1284
1285 assert.result <define>minus=-
1286 : expand-subfeatures <define>minus=- ;
1287
1288 assert.result <toolset>gcc <toolset-gcc:version>3.0.1
1289 : expand-subfeatures gcc-3.0.1 ;
1290
1291 assert.result a c e
1292 : get-values <x> : <x>a <y>b <x>c <y>d <x>e ;
1293
1294 assert.result <toolset>gcc <toolset-gcc:version>3.0.1
1295 <variant>debug <define>_DEBUG <optimization>on
1296 : expand gcc-3.0.1 debug <optimization>on ;
1297
1298 assert.result <variant>debug <define>_DEBUG <optimization>on
1299 : expand debug <optimization>on ;
1300
1301 assert.result <optimization>on <variant>debug <define>_DEBUG
1302 : expand <optimization>on debug ;
1303
1304 assert.result <runtime-link>dynamic <optimization>on
1305 : defaults <runtime-link> <define> <optimization> ;
1306
1307 # Make sure defaults is resilient to missing grist.
1308 assert.result <runtime-link>dynamic <optimization>on
1309 : defaults runtime-link define optimization ;
1310
1311 feature dummy : dummy1 dummy2 ;
1312 subfeature dummy : subdummy : x y z : optional ;
1313
1314 feature fu : fu1 fu2 : optional ;
1315 subfeature fu : subfu : x y z : optional ;
1316 subfeature fu : subfu2 : q r s ;
1317
1318 assert.result optional : attributes <fu> ;
1319
1320 assert.result [ SORT <define>_DEBUG <runtime-link>static
1321 <define>foobar <optimization>on
1322 <toolset>gcc <variant>debug <stdlib>native
1323 <dummy>dummy1 <toolset-gcc:version>2.95.2 ]
1324 : add-defaults <runtime-link>static <define>foobar <optimization>on ;
1325
1326 assert.result [ SORT <define>_DEBUG <runtime-link>static
1327 <define>foobar <optimization>on
1328 <fu>fu1 <toolset>gcc <variant>debug
1329 <stdlib>native <dummy>dummy1 <fu-subfu2>q <toolset-gcc:version>2.95.2 ]
1330 : add-defaults <runtime-link>static <define>foobar <optimization>on
1331 <fu>fu1 ;
1332
1333 feature f0 : f0-0 f0-1 ;
1334 feature f1 : f1-0 f1-1 ;
1335
1336 assert.true valid <f0> ;
1337 assert.true valid <f1> ;
1338 assert.true valid <f0> <f1> ;
1339
1340 set-default <runtime-link> : static ;
1341 assert.result <runtime-link>static : defaults <runtime-link> ;
1342
1343 assert.result gcc-3.0.1 debug <optimization>on
1344 : minimize [ expand gcc-3.0.1 debug <optimization>on <stdlib>native ] ;
1345
1346 assert.result gcc-3.0.1 debug <runtime-link>dynamic
1347 : minimize
1348 [ expand gcc-3.0.1 debug <optimization>off <runtime-link>dynamic ] ;
1349
1350 assert.result gcc-3.0.1 debug
1351 : minimize [ expand gcc-3.0.1 debug <optimization>off ] ;
1352
1353 assert.result debug <optimization>on
1354 : minimize [ expand debug <optimization>on ] ;
1355
1356 assert.result gcc-3.0
1357 : minimize <toolset>gcc <toolset-gcc:version>3.0 ;
1358
1359 assert.result gcc-3.0
1360 : minimize <toolset-gcc:version>3.0 <toolset>gcc ;
1361
1362 assert.result <x>y/z <a>b/c <d>e/f
1363 : split <x>y/z/<a>b/c/<d>e/f ;
1364
1365 assert.result <x>y/z <a>b/c <d>e/f
1366 : split <x>y\\z\\<a>b\\c\\<d>e\\f ;
1367
1368 assert.result a b c <d>e/f/g <h>i/j/k
1369 : split a/b/c/<d>e/f/g/<h>i/j/k ;
1370
1371 assert.result a b c <d>e/f/g <h>i/j/k
1372 : split a\\b\\c\\<d>e\\f\\g\\<h>i\\j\\k ;
1373
1374 # Test error checking.
1375
1376 try ;
1377 {
1378 expand release <optimization>off <optimization>on ;
1379 }
1380 catch explicitly-specified values of non-free feature <optimization> conflict ;
1381
1382 try ;
1383 {
1384 validate-feature <foobar> ;
1385 }
1386 catch unknown feature ;
1387
1388 validate-value-string <toolset> gcc ;
1389 validate-value-string <toolset> gcc-3.0.1 ;
1390
1391 try ;
1392 {
1393 validate-value-string <toolset> digital_mars ;
1394 }
1395 catch \"digital_mars\" is not a known value of <toolset> ;
1396
1397 try ;
1398 {
1399 feature foobar : : baz ;
1400 }
1401 catch unknown "attributes:" baz ;
1402
1403 feature feature1 ;
1404 try ;
1405 {
1406 feature feature1 ;
1407 }
1408 catch feature already "defined:" ;
1409
1410 try ;
1411 {
1412 feature feature2 : : free implicit ;
1413 }
1414 catch free features cannot also be implicit ;
1415
1416 try ;
1417 {
1418 feature feature3 : : free propagated ;
1419 }
1420 catch free features cannot be propagated ;
1421
1422 try ;
1423 {
1424 implied-feature lackluster ;
1425 }
1426 catch \"lackluster\" is not an implicit feature value ;
1427
1428 try ;
1429 {
1430 implied-subfeature <toolset> 3.0.1 ;
1431 }
1432 catch \"3.0.1\" is not a known subfeature value of <toolset> ;
1433
1434 try ;
1435 {
1436 implied-subfeature <toolset> not-a-version : gcc ;
1437 }
1438 catch \"not-a-version\" is not a known subfeature value of <toolset>gcc ;
1439
1440 # Leave a clean copy of the features module behind.
1441 finish-test feature-test-temp ;
1442 }