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