]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/src/build/property.jam
bump version to 18.2.4-pve3
[ceph.git] / ceph / src / boost / tools / build / src / build / property.jam
1 # Copyright 2001, 2002, 2003 Dave Abrahams
2 # Copyright 2006 Rene Rivera
3 # Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus
4 # Copyright 2020 Nikita Kniazev
5 # Distributed under the Boost Software License, Version 1.0.
6 # (See accompanying file LICENSE.txt or copy at
7 # https://www.bfgroup.xyz/b2/LICENSE.txt)
8
9 import feature ;
10 import indirect ;
11 import path ;
12 import regex ;
13 import string ;
14 import sequence ;
15 import set ;
16 import utility ;
17
18
19 # Refines 'properties' by overriding any non-free and non-conditional properties
20 # for which a different value is specified in 'requirements'. Returns the
21 # resulting list of properties.
22 #
23 rule refine ( properties * : requirements * )
24 {
25 local result ;
26 local unset ;
27
28 # Collect all non-free features in requirements
29 for local r in $(requirements)
30 {
31 # Do not consider conditional requirements.
32 if ! [ MATCH "(:<)" : $(r:G=) ] && ! free in [ feature.attributes $(r:G) ]
33 {
34 if ! $(r) in $(properties)
35 {
36 # Kill subfeatures of properties that we're changing
37 local sub = [ modules.peek feature : $(r:G).subfeatures ] ;
38 if $(sub)
39 {
40 # non-specific subfeatures are still valid
41 sub = [ MATCH "(.*:.*)" : $(sub) ] ;
42 local name = [ utility.ungrist $(r:G) ] ;
43 unset += <$(name)-$(sub)> ;
44 }
45 }
46 unset += $(r:G) ;
47 }
48 }
49
50 # Remove properties that are overridden by requirements
51 for local p in $(properties)
52 {
53 if [ MATCH "(:<)" : $(p:G=) ] || ! $(p:G) in $(unset)
54 {
55 result += $(p) ;
56 }
57 }
58
59 return [ sequence.unique $(result) $(requirements) ] ;
60 }
61
62
63 # Removes all conditional properties whose conditions are not met. For those
64 # with met conditions, removes the condition. Properties in conditions are
65 # looked up in 'context'.
66 #
67 rule evaluate-conditionals-in-context ( properties * : context * )
68 {
69 # Import here to avoid cyclic dependency
70 import project ;
71
72 local result ;
73 while $(properties)
74 {
75 local conditionals ;
76 local indirect ;
77 for local p in $(properties)
78 {
79 if [ MATCH "(:<)" : $(p) ] && ! free in [ feature.attributes $(p:G) ]
80 {
81 conditionals += $(p) ;
82 }
83 else if $(p:G) = <conditional>
84 {
85 indirect += $(p) ;
86 }
87 else
88 {
89 result += $(p) ;
90 }
91 }
92
93 properties = ;
94 for local p in $(conditionals)
95 {
96 # Separate condition and property.
97 local s = [ MATCH "^(.*):(<.*)" : $(p) ] ;
98 # Split condition into individual properties.
99 local condition = [ regex.split $(s[1]) "," ] ;
100 # Evaluate condition.
101 if ! [ MATCH ^(!).* : $(condition:G=) ]
102 {
103 # Only positive checks
104 if $(condition) in $(context)
105 {
106 properties += $(s[2]) ;
107 }
108 }
109 else
110 {
111 # Have negative checks
112 local fail ;
113 for local c in $(condition)
114 {
115 local c = [ MATCH ^(!)?(.*) : $(c) ] ;
116 # It is XOR: $(c[1]) = "!" ^ $(c[2]) in $(context)
117 if $(c[1]) = "!" && $(c[2]) in $(context) || $(c[1]) != "!" && ! ( $(c[2]) in $(context) )
118 {
119 fail = true ;
120 break ;
121 }
122 }
123 if ! $(fail)
124 {
125 properties += $(s[2]) ;
126 }
127 }
128 }
129 for local i in [ MATCH "^@(.*)" : $(indirect:G=) ]
130 {
131 # If the rule was set in a project module, translate paths
132 # relative to that project's location.
133 local m = [ indirect.get-module $(i) ] ;
134 local p = [ project.target $(m) : allow-missing ] ;
135 local new = [ indirect.call $(i) $(context) ] ;
136 if $(p) && [ $(p).location ]
137 {
138 local location = [ $(p).location ] ;
139 local project-id = [ project.attribute $(m) id ] ;
140 project-id ?= [ path.root $(location) [ path.pwd ] ] ;
141 properties +=
142 [ translate $(new) : $(project-id) : $(location) : $(m) ] ;
143 }
144 else
145 {
146 properties += $(new) ;
147 }
148 }
149 }
150 return $(result) ;
151 }
152
153
154 # Returns <relevant> properties indicating how the conditionals in
155 # properties affect feature relevance. If the optional argument cond
156 # is passed, it is treated as extra conditions for all properties.
157 #
158 rule evaluate-conditional-relevance ( properties * : cond * )
159 {
160 cond = [ sequence.transform utility.ungrist : $(cond:G) ] ;
161 local result ;
162 for local p in $(properties)
163 {
164 # Separate condition and property.
165 local s = [ MATCH "^(.*):(<.*)" : $(p) ] ;
166 if ! $(s) || free in [ feature.attributes $(p:G) ]
167 {
168 local value = [ utility.ungrist $(p:G) ] ;
169 result += <relevant>$(value):<relevant>$(cond) ;
170 }
171 else
172 {
173 local condition = [ regex.split $(s[1]) "," ] ;
174 condition = [ MATCH "^!?(.*)" : $(condition) ] ;
175 condition = [ sequence.transform utility.ungrist : $(condition:G) ] $(cond) ;
176 local value = [ utility.ungrist $(s[2]:G) ] ;
177 result += <relevant>$(value):<relevant>$(condition) ;
178 }
179 }
180 return [ sequence.unique $(result) ] ;
181 }
182
183
184 rule expand-subfeatures-in-conditions ( properties * )
185 {
186 local result ;
187 for local p in $(properties)
188 {
189 local s = [ MATCH "^(.*):(<.*)" : $(p) ] ;
190 if ! $(s)
191 {
192 result += $(p) ;
193 }
194 else
195 {
196 local condition = $(s[1]) ;
197 local value = $(s[2]) ;
198 # Condition might include several elements.
199 condition = [ regex.split $(condition) "," ] ;
200 local e ;
201 for local c in $(condition)
202 {
203 # It is common for a condition to include a toolset or
204 # subfeatures that have not been defined. In that case we want
205 # the condition to simply 'never be satisfied' and validation
206 # would only produce a spurious error so we prevent it by
207 # passing 'true' as the second parameter.
208 e += [ feature.expand-subfeatures $(c) : true ] ;
209 }
210 if $(e) = $(condition)
211 {
212 # (todo)
213 # This is just an optimization and possibly a premature one at
214 # that.
215 # (todo) (12.07.2008.) (Jurko)
216 result += $(p) ;
217 }
218 else
219 {
220 result += "$(e:J=,):$(value)" ;
221 }
222 }
223 }
224 return $(result) ;
225 }
226
227
228 # Helper for as-path, below. Orders properties with the implicit ones first, and
229 # within the two sections in alphabetical order of feature name.
230 #
231 local rule path-order ( x y )
232 {
233 if $(y:G) && ! $(x:G)
234 {
235 return true ;
236 }
237 else if $(x:G) && ! $(y:G)
238 {
239 return ;
240 }
241 else
242 {
243 if ! $(x:G)
244 {
245 x = [ feature.expand-subfeatures $(x) ] ;
246 y = [ feature.expand-subfeatures $(y) ] ;
247 }
248
249 if $(x[1]) < $(y[1])
250 {
251 return true ;
252 }
253 }
254 }
255
256
257 local rule abbreviate-dashed ( string )
258 {
259 local r ;
260 for local part in [ regex.split $(string) - ]
261 {
262 r += [ string.abbreviate $(part) ] ;
263 }
264 return $(r:J=-) ;
265 }
266
267
268 local rule identity ( string )
269 {
270 return $(string) ;
271 }
272
273
274 if --abbreviate-paths in [ modules.peek : ARGV ]
275 {
276 .abbrev = abbreviate-dashed ;
277 }
278 else
279 {
280 .abbrev = identity ;
281 }
282
283
284 # Returns a path representing the given expanded property set.
285 #
286 rule as-path ( properties * )
287 {
288 local entry = .result.$(properties:J=-) ;
289
290 if ! $($(entry))
291 {
292 # Trim redundancy.
293 properties = [ feature.minimize $(properties) ] ;
294
295 # Sort according to path-order.
296 properties = [ sequence.insertion-sort $(properties) : path-order ] ;
297
298 local components ;
299 for local p in $(properties)
300 {
301 if ! hidden in [ feature.attributes $(p:G) ]
302 {
303 if $(p:G)
304 {
305 local f = [ utility.ungrist $(p:G) ] ;
306 p = $(f)-$(p:G=) ;
307 }
308 components += [ $(.abbrev) $(p) ] ;
309 }
310 }
311
312 $(entry) = $(components:J=/) ;
313 }
314
315 return $($(entry)) ;
316 }
317
318
319 # Exit with error if property is not valid.
320 #
321 local rule validate1 ( property )
322 {
323 local msg ;
324 if $(property:G)
325 {
326 local feature = $(property:G) ;
327 local value = $(property:G=) ;
328
329 if ! [ feature.valid $(feature) ]
330 {
331 # Ungrist for better error messages.
332 feature = [ utility.ungrist $(property:G) ] ;
333 msg = "unknown feature '$(feature)'" ;
334 }
335 else if $(value) && ! free in [ feature.attributes $(feature) ]
336 {
337 feature.validate-value-string $(feature) $(value) ;
338 }
339 else if ! ( $(value) || ( optional in [ feature.attributes $(feature) ] ) )
340 {
341 # Ungrist for better error messages.
342 feature = [ utility.ungrist $(property:G) ] ;
343 msg = "No value specified for feature '$(feature)'" ;
344 }
345 }
346 else
347 {
348 local feature = [ feature.implied-feature $(property) ] ;
349 feature.validate-value-string $(feature) $(property) ;
350 }
351 if $(msg)
352 {
353 import errors ;
354 errors.error "Invalid property "'$(property:J=" ")'": "$(msg:J=" "). ;
355 }
356 }
357
358
359 rule validate ( properties * )
360 {
361 for local p in $(properties)
362 {
363 validate1 $(p) ;
364 }
365 }
366
367
368 rule validate-property-sets ( property-sets * )
369 {
370 for local s in $(property-sets)
371 {
372 validate [ feature.split $(s) ] ;
373 }
374 }
375
376
377 # Expands any implicit property values in the given property 'specification' so
378 # they explicitly state their feature.
379 #
380 rule make ( specification * )
381 {
382 local result ;
383 for local e in $(specification)
384 {
385 if $(e:G)
386 {
387 result += $(e) ;
388 }
389 else if [ feature.is-implicit-value $(e) ]
390 {
391 local feature = [ feature.implied-feature $(e) ] ;
392 result += $(feature)$(e) ;
393 }
394 else
395 {
396 import errors ;
397 errors.error "'$(e)' is not a valid property specification" ;
398 }
399 }
400 return $(result) ;
401 }
402
403
404 # Returns a property set containing all the elements in 'properties' that do not
405 # have their attributes listed in 'attributes'.
406 #
407 rule remove ( attributes + : properties * )
408 {
409 local result ;
410 for local e in $(properties)
411 {
412 if ! [ set.intersection $(attributes) : [ feature.attributes $(e:G) ] ]
413 {
414 result += $(e) ;
415 }
416 }
417 return $(result) ;
418 }
419
420
421 # Returns a property set containing all the elements in 'properties' that have
422 # their attributes listed in 'attributes'.
423 #
424 rule take ( attributes + : properties * )
425 {
426 local result ;
427 for local e in $(properties)
428 {
429 if [ set.intersection $(attributes) : [ feature.attributes $(e:G) ] ]
430 {
431 result += $(e) ;
432 }
433 }
434 return $(result) ;
435 }
436
437
438 # Selects properties corresponding to any of the given features.
439 #
440 rule select ( features * : properties * )
441 {
442 local result ;
443
444 # Add any missing angle brackets.
445 local empty = "" ;
446 features = $(empty:G=$(features)) ;
447
448 for local p in $(properties)
449 {
450 if $(p:G) in $(features)
451 {
452 result += $(p) ;
453 }
454 }
455 return $(result) ;
456 }
457
458
459 # Returns a modified version of properties with all values of the given feature
460 # replaced by the given value. If 'value' is empty the feature will be removed.
461 #
462 rule change ( properties * : feature value ? )
463 {
464 local result ;
465 for local p in $(properties)
466 {
467 if $(p:G) = $(feature)
468 {
469 result += $(value:G=$(feature)) ;
470 }
471 else
472 {
473 result += $(p) ;
474 }
475 }
476 return $(result) ;
477 }
478
479
480 # If 'property' is a conditional property, returns the condition and the
481 # property. E.g. <variant>debug,<toolset>gcc:<inlining>full will become
482 # <variant>debug,<toolset>gcc <inlining>full. Otherwise, returns an empty
483 # string.
484 #
485 rule split-conditional ( property )
486 {
487 return [ MATCH "^(.+):(<.+)" : $(property) ] ;
488 }
489
490
491 rule translate-path-value ( value : path )
492 {
493 local t ;
494 for local v in [ regex.split $(value) "&&" ]
495 {
496 t += [ path.root [ path.make $(v) ] $(path) ] ;
497 }
498 return $(t:TJ="&&") ;
499 }
500
501 rule translate-dependency-value ( value : project-id : project-location )
502 {
503 local split-target = [ regex.match ^(.*)//(.*) : $(value) ] ;
504 if $(split-target)
505 {
506 local rooted = [ path.root [ path.make $(split-target[1]) ]
507 [ path.root $(project-location) [ path.pwd ] ] ] ;
508 return $(rooted)//$(split-target[2]) ;
509 }
510 else if [ path.is-rooted $(value) ]
511 {
512 return $(value) ;
513 }
514 else
515 {
516 return $(project-id)//$(value) ;
517 }
518 }
519
520 rule translate-indirect-value ( rulename : context-module )
521 {
522 if [ MATCH "^([^%]*)%([^%]+)$" : $(rulename) ]
523 {
524 # Rule is already in the 'indirect-rule' format.
525 return @$(rulename) ;
526 }
527 else
528 {
529 local v ;
530 if ! [ MATCH "([.])" : $(rulename) ]
531 {
532 # This is an unqualified rule name. The user might want to
533 # set flags on this rule name and toolset.flag
534 # auto-qualifies it. Need to do the same here so flag
535 # setting works. We can arrange for toolset.flag to *not*
536 # auto-qualify the argument but then two rules defined in
537 # two Jamfiles would conflict.
538 rulename = $(context-module).$(rulename) ;
539 }
540 v = [ indirect.make $(rulename) : $(context-module) ] ;
541 return @$(v) ;
542 }
543
544 }
545
546 # Equivalent to a calling all of:
547 # translate-path
548 # translate-indirect
549 # translate-dependency
550 # expand-subfeatures-in-conditions
551 # make
552 #
553 rule translate ( properties * : project-id : project-location : context-module )
554 {
555 local translate-path-rule = [ MATCH "^<translate-path>[@](.*)$" : "$(properties)" ] ;
556 local result ;
557 for local p in $(properties)
558 {
559 local split = [ split-conditional $(p) ] ;
560 local condition property ;
561
562 if $(split)
563 {
564 condition = $(split[1]) ;
565 property = $(split[2]) ;
566
567 local e ;
568 for local c in [ regex.split $(condition) "," ]
569 {
570 # strip negation for expansion and readd after
571 c = [ MATCH "^(!)?(.*)" : $(c) ] ;
572 local expanded = [ feature.expand-subfeatures $(c[2]) : true ] ;
573 e += $(c[1])$(expanded) ;
574 }
575
576 condition = "$(e:J=,):" ;
577 }
578 else
579 {
580 property = $(p) ;
581 }
582
583 local feature = $(property:G) ;
584 if ! $(feature)
585 {
586 if [ feature.is-implicit-value $(property) ]
587 {
588 feature = [ feature.implied-feature $(property) ] ;
589 result += $(condition:E=)$(feature)$(property) ;
590 }
591 else
592 {
593 import errors ;
594 errors.error "'$(property)' is not a valid property specification" ;
595 }
596 } else {
597 local attributes = [ feature.attributes $(feature) ] ;
598 local value ;
599 # Only free features should be translated
600 if free in $(attributes)
601 {
602 if path in $(attributes)
603 {
604 if $(translate-path-rule)
605 {
606 value = [ $(translate-path-rule) $(feature) $(property:G=) : $(properties) : $(project-id) : $(project-location) ] ;
607 }
608 if ! $(value)
609 {
610 value = [ translate-path-value $(property:G=) : $(project-location) ] ;
611 }
612 result += $(condition:E=)$(feature)$(value) ;
613 }
614 else if dependency in $(attributes)
615 {
616 value = [ translate-dependency-value $(property:G=) : $(project-id) : $(project-location) ] ;
617 result += $(condition:E=)$(feature)$(value) ;
618 }
619 else
620 {
621 local m = [ MATCH ^@(.+) : $(property:G=) ] ;
622 if $(m)
623 {
624 value = [ translate-indirect-value $(m) : $(context-module) ] ;
625 result += $(condition:E=)$(feature)$(value) ;
626 }
627 else
628 {
629 result += $(condition:E=)$(property) ;
630 }
631 }
632 }
633 else
634 {
635 result += $(condition:E=)$(property) ;
636 }
637 }
638 }
639 return $(result) ;
640 }
641
642 # Interpret all path properties in 'properties' as relative to 'path'. The
643 # property values are assumed to be in system-specific form, and will be
644 # translated into normalized form.
645 #
646 rule translate-paths ( properties * : path )
647 {
648 local result ;
649 for local p in $(properties)
650 {
651 local split = [ split-conditional $(p) ] ;
652 local condition = "" ;
653 if $(split)
654 {
655 condition = "$(split[1]):" ;
656 p = $(split[2]) ;
657 }
658
659 if path in [ feature.attributes $(p:G) ]
660 {
661 local values = [ regex.split $(p:TG=) "&&" ] ;
662 local t ;
663 for local v in $(values)
664 {
665 t += [ path.root [ path.make $(v) ] $(path) ] ;
666 }
667 t = $(t:J="&&") ;
668 result += $(condition)$(t:TG=$(p:G)) ;
669 }
670 else
671 {
672 result += $(condition)$(p) ;
673 }
674 }
675 return $(result) ;
676 }
677
678
679 # Assumes that all feature values that start with '@' are names of rules, used
680 # in 'context-module'. Such rules can be either local to the module or global.
681 # Converts such values into 'indirect-rule' format (see indirect.jam), so they
682 # can be called from other modules. Does nothing for such values that are
683 # already in the 'indirect-rule' format.
684 #
685 rule translate-indirect ( specification * : context-module )
686 {
687 local result ;
688 for local p in $(specification)
689 {
690 local m = [ MATCH ^@(.+) : $(p:G=) ] ;
691 if $(m)
692 {
693 local v ;
694 if [ MATCH "^([^%]*)%([^%]+)$" : $(m) ]
695 {
696 # Rule is already in the 'indirect-rule' format.
697 v = $(m) ;
698 }
699 else
700 {
701 if ! [ MATCH "([.])" : $(m) ]
702 {
703 # This is an unqualified rule name. The user might want to
704 # set flags on this rule name and toolset.flag
705 # auto-qualifies it. Need to do the same here so flag
706 # setting works. We can arrange for toolset.flag to *not*
707 # auto-qualify the argument but then two rules defined in
708 # two Jamfiles would conflict.
709 m = $(context-module).$(m) ;
710 }
711 v = [ indirect.make $(m) : $(context-module) ] ;
712 }
713
714 v = @$(v) ;
715 result += $(v:G=$(p:G)) ;
716 }
717 else
718 {
719 result += $(p) ;
720 }
721 }
722 return $(result) ;
723 }
724
725
726 # Binds all dependency properties in a list relative to the given project.
727 # Targets with absolute paths will be left unchanged and targets which have a
728 # project specified will have the path to the project interpreted relative to
729 # the specified location.
730 #
731 rule translate-dependencies ( specification * : project-id : location )
732 {
733 local result ;
734 for local p in $(specification)
735 {
736 local split = [ split-conditional $(p) ] ;
737 local condition = "" ;
738 if $(split)
739 {
740 condition = "$(split[1]):" ;
741 p = $(split[2]) ;
742 }
743 if dependency in [ feature.attributes $(p:G) ]
744 {
745 local split-target = [ regex.match ^(.*)//(.*) : $(p:G=) ] ;
746 if $(split-target)
747 {
748 local rooted = [ path.root [ path.make $(split-target[1]) ]
749 [ path.root $(location) [ path.pwd ] ] ] ;
750 result += $(condition)$(p:G)$(rooted)//$(split-target[2]) ;
751 }
752 else if [ path.is-rooted $(p:G=) ]
753 {
754 result += $(condition)$(p) ;
755 }
756 else
757 {
758 result += $(condition)$(p:G)$(project-id)//$(p:G=) ;
759 }
760 }
761 else
762 {
763 result += $(condition)$(p) ;
764 }
765 }
766 return $(result) ;
767 }
768
769
770 # Class maintaining a property set -> string mapping.
771 #
772 class property-map
773 {
774 import numbers ;
775 import sequence ;
776
777 rule __init__ ( )
778 {
779 self.next-flag = 1 ;
780 }
781
782 # Associate 'value' with 'properties'.
783 #
784 rule insert ( properties * : value )
785 {
786 self.all-flags += self.$(self.next-flag) ;
787 self.$(self.next-flag) = $(value) $(properties) ;
788
789 self.next-flag = [ numbers.increment $(self.next-flag) ] ;
790 }
791
792 # Returns the value associated with 'properties' or any subset of it. If
793 # more than one subset has a value assigned to it, returns the value for the
794 # longest subset, if it is unique.
795 #
796 rule find ( property-set )
797 {
798 # First find all matches.
799 local matches ;
800 local match-ranks ;
801 for local i in $(self.all-flags)
802 {
803 local list = $($(i)) ;
804 if [ $(property-set).contains-raw $(list[2-]) ]
805 {
806 matches += $(list[1]) ;
807 match-ranks += [ sequence.length $(list) ] ;
808 }
809 }
810 local best = [ sequence.select-highest-ranked $(matches)
811 : $(match-ranks) ] ;
812 if $(best[2])
813 {
814 import errors : error : errors.error ;
815 properties = [ $(property-set).raw ] ;
816 errors.error "Ambiguous key $(properties:J= :E=)" ;
817 }
818 return $(best) ;
819 }
820
821 # Returns the value associated with 'properties'. If 'value' parameter is
822 # given, replaces the found value.
823 #
824 rule find-replace ( properties * : value ? )
825 {
826 # First find all matches.
827 local matches ;
828 local match-ranks ;
829 for local i in $(self.all-flags)
830 {
831 if $($(i)[2-]) in $(properties)
832 {
833 matches += $(i) ;
834 match-ranks += [ sequence.length $($(i)) ] ;
835 }
836 }
837 local best = [ sequence.select-highest-ranked $(matches)
838 : $(match-ranks) ] ;
839 if $(best[2])
840 {
841 import errors : error : errors.error ;
842 errors.error "Ambiguous key $(properties:J= :E=)" ;
843 }
844 local original = $($(best)[1]) ;
845 if $(value)-is-set
846 {
847 $(best) = $(value) $($(best)[2-]) ;
848 }
849 return $(original) ;
850 }
851 }
852
853
854 rule __test__ ( )
855 {
856 import assert ;
857 import "class" : new ;
858 import errors : try catch ;
859 import feature ;
860
861 # Local rules must be explicitly re-imported.
862 import property : path-order abbreviate-dashed ;
863
864 feature.prepare-test property-test-temp ;
865
866 feature.feature toolset : gcc : implicit symmetric ;
867 feature.subfeature toolset gcc : version : 2.95.2 2.95.3 2.95.4 3.0 3.0.1
868 3.0.2 : optional ;
869 feature.feature define : : free ;
870 feature.feature runtime-link : dynamic static : symmetric link-incompatible ;
871 feature.feature optimization : on off ;
872 feature.feature variant : debug release : implicit composite symmetric ;
873 feature.feature rtti : on off : link-incompatible ;
874
875 feature.compose <variant>debug : <define>_DEBUG <optimization>off ;
876 feature.compose <variant>release : <define>NDEBUG <optimization>on ;
877
878 validate <toolset>gcc <toolset>gcc-3.0.1 : $(test-space) ;
879
880 assert.true path-order $(test-space) debug <define>foo ;
881 assert.false path-order $(test-space) <define>foo debug ;
882 assert.true path-order $(test-space) gcc debug ;
883 assert.false path-order $(test-space) debug gcc ;
884 assert.true path-order $(test-space) <optimization>on <rtti>on ;
885 assert.false path-order $(test-space) <rtti>on <optimization>on ;
886
887 assert.result-set-equal <toolset>gcc <rtti>off <define>FOO
888 : refine <toolset>gcc <rtti>off
889 : <define>FOO
890 : $(test-space) ;
891
892 assert.result-set-equal <toolset>gcc <optimization>on
893 : refine <toolset>gcc <optimization>off
894 : <optimization>on
895 : $(test-space) ;
896
897 assert.result-set-equal <toolset>gcc <rtti>off
898 : refine <toolset>gcc : <rtti>off : $(test-space) ;
899
900 assert.result-set-equal <toolset>gcc <rtti>off <rtti>off:<define>FOO
901 : refine <toolset>gcc : <rtti>off <rtti>off:<define>FOO
902 : $(test-space) ;
903
904 assert.result-set-equal <toolset>gcc:<define>foo <toolset>gcc:<define>bar
905 : refine <toolset>gcc:<define>foo : <toolset>gcc:<define>bar
906 : $(test-space) ;
907
908 assert.result
909 : evaluate-conditionals-in-context
910 <variant>release,<rtti>off:<define>MY_RELEASE
911 : <toolset>gcc <variant>release <rtti>on ;
912
913 assert.result <define>MY_RELEASE
914 : evaluate-conditionals-in-context
915 <variant>release,<rtti>off:<define>MY_RELEASE
916 : <toolset>gcc <variant>release <rtti>off ;
917
918 assert.result <define>MY_RELEASE
919 : evaluate-conditionals-in-context
920 <variant>release,!<rtti>off:<define>MY_RELEASE
921 : <toolset>gcc <variant>release <rtti>on ;
922
923 assert.result
924 : evaluate-conditionals-in-context
925 <variant>release,!<rtti>off:<define>MY_RELEASE
926 : <toolset>gcc <variant>release <rtti>off ;
927
928 assert.result debug
929 : as-path <optimization>off <variant>debug
930 : $(test-space) ;
931
932 assert.result gcc/debug/rtti-off
933 : as-path <toolset>gcc <optimization>off <rtti>off <variant>debug
934 : $(test-space) ;
935
936 assert.result optmz-off : abbreviate-dashed optimization-off ;
937 assert.result rntm-lnk-sttc : abbreviate-dashed runtime-link-static ;
938
939 try ;
940 validate <feature>value : $(test-space) ;
941 catch "Invalid property '<feature>value': unknown feature 'feature'." ;
942
943 try ;
944 validate <rtti>default : $(test-space) ;
945 catch \"default\" is not a known value of feature <rtti> ;
946
947 validate <define>WHATEVER : $(test-space) ;
948
949 try ;
950 validate <rtti> : $(test-space) ;
951 catch "Invalid property '<rtti>': No value specified for feature 'rtti'." ;
952
953 try ;
954 validate value : $(test-space) ;
955 catch \"value\" is not an implicit feature value ;
956
957 assert.result-set-equal <rtti>on
958 : remove free implicit : <toolset>gcc <define>foo <rtti>on : $(test-space) ;
959
960 assert.result-set-equal <include>a
961 : select include : <include>a <toolset>gcc ;
962
963 assert.result-set-equal <include>a
964 : select include bar : <include>a <toolset>gcc ;
965
966 assert.result-set-equal <include>a <toolset>gcc
967 : select include <bar> <toolset> : <include>a <toolset>gcc ;
968
969 assert.result-set-equal <toolset>kylix <include>a
970 : change <toolset>gcc <include>a : <toolset> kylix ;
971
972 pm = [ new property-map ] ;
973 $(pm).insert <toolset>gcc : o ;
974 $(pm).insert <toolset>gcc <os>NT : obj ;
975 $(pm).insert <toolset>gcc <os>CYGWIN : obj ;
976
977 try ;
978 $(pm).find [ new property-set <toolset>gcc <os>NT <os>CYGWIN ] ;
979 catch "Ambiguous key <toolset>gcc <os>NT <os>CYGWIN" ;
980
981 assert.equal o : [ $(pm).find-replace <toolset>gcc ] ;
982
983 assert.equal obj : [ $(pm).find-replace <toolset>gcc <os>NT ] ;
984
985 try ;
986 $(pm).find-replace <toolset>gcc <os>NT <os>CYGWIN ;
987 catch "Ambiguous key <toolset>gcc <os>NT <os>CYGWIN" ;
988
989 # Test ordinary properties.
990 assert.result : split-conditional <toolset>gcc ;
991
992 # Test properties with ":".
993 assert.result : split-conditional <define>"FOO=A::B" ;
994
995 # Test conditional feature.
996 assert.result-set-equal <toolset>gcc,<toolset-gcc:version>3.0 <define>FOO
997 : split-conditional <toolset>gcc,<toolset-gcc:version>3.0:<define>FOO ;
998
999 # Test translate does not choke on negations in conditional
1000 assert.result <toolset>gcc,!<rtti>off:<define>HELLO
1001 : translate <toolset>gcc,!<rtti>off:<define>HELLO
1002 : project-id : project-location : context-module ;
1003
1004 feature.finish-test property-test-temp ;
1005 }