1 # Copyright Vladimir Prus 2002.
2 # Copyright Rene Rivera 2006.
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)
8 # Manages 'generators' --- objects which can do transformation between different
9 # target types and contain algorithm for finding transformation from sources to
12 # The main entry point to this module is generators.construct rule. It is given
13 # a list of source targets, desired target type and a set of properties. It
14 # starts by selecting 'viable generators', which have any chances of producing
15 # the desired target type with the required properties. Generators are ranked
16 # and a set of the most specific ones is selected.
18 # The most specific generators have their 'run' methods called, with the
19 # properties and list of sources. Each one selects a target which can be
20 # directly consumed, and tries to convert the remaining ones to the types it can
21 # consume. This is done by recursively calling 'construct' with all consumable
24 # If the generator has collected all the targets it needs, it creates targets
25 # corresponding to result, and returns it. When all generators have been run,
26 # results of one of them are selected and returned as a result.
28 # It is quite possible for 'construct' to return more targets that it was asked
29 # for. For example, if it were asked to generate a target of type EXE, but the
30 # only found generator produces both EXE and TDS (file with debug) information.
31 # The extra target will be returned.
33 # Likewise, when generator tries to convert sources to consumable types, it can
34 # get more targets that it was asked for. The question is what to do with extra
35 # targets. Boost.Build attempts to convert them to requested types, and attempts
36 # that as early as possible. Specifically, this is done after invoking each
37 # generator. TODO: An example is needed to document the rationale for trying
38 # extra target conversion at that point.
40 # In order for the system to be able to use a specific generator instance 'when
41 # needed', the instance needs to be registered with the system using
42 # generators.register() or one of its related rules. Unregistered generators may
43 # only be run explicitly and will not be considered by Boost.Build when when
44 # converting between given target types.
46 import "class" : new ;
53 import virtual-target ;
56 if "--debug-generators" in [ modules.peek : ARGV ]
62 # Updated cached viable source target type information as needed after a new
63 # target type gets defined. This is needed because if a target type is a viable
64 # source target type for some generator then all of the target type's derived
65 # target types should automatically be considered as viable source target types
66 # for the same generator as well. Does nothing if a non-derived target type is
69 rule update-cached-information-with-a-new-type ( type )
71 local base-type = [ type.base $(type) ] ;
74 for local g in $(.vstg-cached-generators)
76 if $(base-type) in $(.vstg.$(g))
78 .vstg.$(g) += $(type) ;
82 for local t in $(.vst-cached-types)
84 if $(base-type) in $(.vst.$(t))
86 .vst.$(t) += $(type) ;
93 # Clears cached viable source target type information except for target types
94 # and generators with all source types listed as viable. Should be called when
95 # something invalidates those cached values by possibly causing some new source
96 # types to become viable.
98 local rule invalidate-extendable-viable-source-target-type-cache ( )
100 local generators-with-cached-source-types = $(.vstg-cached-generators) ;
101 .vstg-cached-generators = ;
102 for local g in $(generators-with-cached-source-types)
106 .vstg-cached-generators += $(g) ;
114 local types-with-cached-source-types = $(.vst-cached-types) ;
115 .vst-cached-types = ;
116 for local t in $(types-with-cached-source-types)
120 .vst-cached-types += $(t) ;
130 # Outputs a debug message if generators debugging is on. Each element of
131 # 'message' is checked to see if it is a class instance. If so, instead of the
132 # value, the result of 'str' call is output.
134 local rule generators.dout ( message * )
138 ECHO [ sequence.transform utility.str : $(message) ] ;
143 local rule indent ( )
145 return $(.indent:J="") ;
149 local rule increase-indent ( )
155 local rule decrease-indent ( )
157 .indent = $(.indent[2-]) ;
161 # Models a generator.
165 import generators : indent increase-indent decrease-indent generators.dout ;
172 import virtual-target ;
173 import "class" : new ;
177 EXPORT class@generator : indent increase-indent decrease-indent
181 id # Identifies the generator - should be name
182 # of the rule which sets up the build
185 composing ? # Whether generator processes each source
186 # target in turn, converting it to required
187 # types. Ordinary generators pass all
188 # sources together to the recursive
189 # generators.construct-types call.
191 : source-types * # Types that this generator can handle. If
192 # empty, the generator can consume anything.
194 : target-types-and-names + # Types the generator will create and,
195 # optionally, names for created targets.
196 # Each element should have the form
197 # type["(" name-pattern ")"], for example,
198 # obj(%_x). Generated target name will be
199 # found by replacing % with the name of
200 # source, provided an explicit name was not
207 self.rule-name = $(id) ;
208 self.composing = $(composing) ;
209 self.source-types = $(source-types) ;
210 self.target-types-and-names = $(target-types-and-names) ;
211 self.requirements = $(requirements) ;
213 for local e in $(target-types-and-names)
215 # Create three parallel lists: one with the list of target types,
216 # and two other with prefixes and postfixes to be added to target
217 # name. We use parallel lists for prefix and postfix (as opposed to
218 # mapping), because given target type might occur several times, for
219 # example "H H(%_symbols)".
220 local m = [ MATCH ([^\\(]*)(\\((.*)%(.*)\\))? : $(e) ] ;
221 self.target-types += $(m[1]) ;
222 self.name-prefix += $(m[3]:E="") ;
223 self.name-postfix += $(m[4]:E="") ;
226 # Note that 'transform' here, is the same as 'for_each'.
227 sequence.transform type.validate : $(self.source-types) ;
228 sequence.transform type.validate : $(self.target-types) ;
231 ################# End of constructor #################
238 # Returns the list of target type the generator accepts.
240 rule source-types ( )
242 return $(self.source-types) ;
245 # Returns the list of target types that this generator produces. It is
246 # assumed to be always the same -- i.e. it can not change depending on some
247 # provided list of sources.
249 rule target-types ( )
251 return $(self.target-types) ;
254 # Returns the required properties for this generator. Properties in returned
255 # set must be present in build properties if this generator is to be used.
256 # If result has grist-only element, that build properties must include some
257 # value of that feature.
259 # XXX: remove this method?
261 rule requirements ( )
263 return $(self.requirements) ;
266 rule set-rule-name ( rule-name )
268 self.rule-name = $(rule-name) ;
273 return $(self.rule-name) ;
276 # Returns a true value if the generator can be run with the specified
279 rule match-rank ( property-set-to-match )
281 # See if generator requirements are satisfied by 'properties'. Treat a
282 # feature name in requirements (i.e. grist-only element), as matching
283 # any value of the feature.
284 local all-requirements = [ requirements ] ;
286 local property-requirements feature-requirements ;
287 for local r in $(all-requirements)
291 property-requirements += $(r) ;
295 feature-requirements += $(r) ;
299 local properties-to-match = [ $(property-set-to-match).raw ] ;
300 if $(property-requirements) in $(properties-to-match) &&
301 $(feature-requirements) in $(properties-to-match:G)
311 # Returns another generator which differs from $(self) in
313 # - value to <toolset> feature in properties
315 rule clone ( new-id : new-toolset-properties + )
317 local g = [ new $(__class__) $(new-id) $(self.composing) :
318 $(self.source-types) : $(self.target-types-and-names) :
319 # Note: this does not remove any subfeatures of <toolset> which
320 # might cause problems.
321 [ property.change $(self.requirements) : <toolset> ]
322 $(new-toolset-properties) ] ;
326 # Creates another generator that is the same as $(self), except that if
327 # 'base' is in target types of $(self), 'type' will in target types of the
330 rule clone-and-change-target-type ( base : type )
333 for local t in $(self.target-types-and-names)
335 local m = [ MATCH ([^\\(]*)(\\(.*\\))? : $(t) ] ;
338 target-types += $(type)$(m[2]:E="") ;
342 target-types += $(t) ;
346 local g = [ new $(__class__) $(self.id) $(self.composing) :
347 $(self.source-types) : $(target-types) : $(self.requirements) ] ;
350 $(g).set-rule-name $(self.rule-name) ;
355 # Tries to invoke this generator on the given sources. Returns a list of
356 # generated targets (instances of 'virtual-target') and optionally a set of
357 # properties to be added to the usage-requirements for all the generated
358 # targets. Returning nothing from run indicates that the generator was
359 # unable to create the target.
363 project # Project for which the targets are generated.
364 name ? # Used when determining the 'name' attribute for all
365 # generated targets. See the 'generated-targets' method.
366 : property-set # Desired properties for generated targets.
367 : sources + # Source targets.
370 generators.dout [ indent ] " ** generator" $(self.id) ;
371 generators.dout [ indent ] " composing:" $(self.composing) ;
373 if ! $(self.composing) && $(sources[2]) && $(self.source-types[2])
375 errors.error "Unsupported source/source-type combination" ;
378 # We do not run composing generators if no name is specified. The reason
379 # is that composing generator combines several targets, which can have
380 # different names, and it cannot decide which name to give for produced
381 # target. Therefore, the name must be passed.
383 # This in effect, means that composing generators are runnable only at
384 # the top-level of a transformation graph, or if their name is passed
385 # explicitly. Thus, we dissallow composing generators in the middle. For
386 # example, the transformation CPP -> OBJ -> STATIC_LIB -> RSP -> EXE
387 # will not be allowed as the OBJ -> STATIC_LIB generator is composing.
388 if ! $(self.composing) || $(name)
390 run-really $(project) $(name) : $(property-set) : $(sources) ;
394 rule run-really ( project name ? : property-set : sources + )
396 # Targets that this generator will consume directly.
398 # Targets that can not be consumed and will be returned as-is.
403 convert-multiple-sources-to-consumable-types $(project)
404 : $(property-set) : $(sources) : consumed bypassed ;
408 convert-to-consumable-types $(project) $(name) : $(property-set)
409 : $(sources) : : consumed bypassed ;
415 result = [ construct-result $(consumed) : $(project) $(name) :
421 generators.dout [ indent ] " SUCCESS: " $(result) ;
425 generators.dout [ indent ] " FAILURE" ;
431 # Constructs the dependency graph to be returned by this generator.
433 rule construct-result
435 consumed + # Already prepared list of consumable targets.
436 # Composing generators may receive multiple sources
437 # all of which will have types matching those in
438 # $(self.source-types). Non-composing generators with
439 # multiple $(self.source-types) will receive exactly
440 # len $(self.source-types) sources with types matching
441 # those in $(self.source-types). And non-composing
442 # generators with only a single source type may
443 # receive multiple sources with all of them of the
444 # type listed in $(self.source-types).
446 : property-set # Properties to be used for all actions created here.
450 # If this is 1->1 transformation, apply it to all consumed targets in
452 if ! $(self.source-types[2]) && ! $(self.composing)
454 for local r in $(consumed)
456 result += [ generated-targets $(r) : $(property-set) :
457 $(project) $(name) ] ;
462 result += [ generated-targets $(consumed) : $(property-set) :
463 $(project) $(name) ] ;
468 # Determine target name from fullname (maybe including path components)
469 # Place optional prefix and postfix around basename
471 rule determine-target-name ( fullname : prefix ? : postfix ? )
473 # See if we need to add directory to the target name.
474 local dir = $(fullname:D) ;
475 local name = $(fullname:B) ;
477 name = $(prefix:E=)$(name) ;
478 name = $(name)$(postfix:E=) ;
481 # Never append '..' to target path.
482 ! [ MATCH .*(\\.\\.).* : $(dir) ]
484 ! [ path.is-rooted $(dir) ]
486 # Relative path is always relative to the source
487 # directory. Retain it, so that users can have files
488 # with the same in two different subdirectories.
489 name = $(dir)/$(name) ;
494 # Determine the name of the produced target from the names of the sources.
496 rule determine-output-name ( sources + )
498 # The simple case if when a name of source has single dot. Then, we take
499 # the part before dot. Several dots can be caused by:
500 # - using source file like a.host.cpp, or
501 # - a type whose suffix has a dot. Say, we can type 'host_cpp' with
502 # extension 'host.cpp'.
503 # In the first case, we want to take the part up to the last dot. In the
504 # second case -- not sure, but for now take the part up to the last dot
506 name = [ utility.basename [ $(sources[1]).name ] ] ;
508 for local s in $(sources[2])
510 local n2 = [ utility.basename [ $(s).name ] ] ;
513 errors.error "$(self.id): source targets have different names: cannot determine target name" ;
516 name = [ determine-target-name [ $(sources[1]).name ] ] ;
520 # Constructs targets that are created after consuming 'sources'. The result
521 # will be the list of virtual-target, which has the same length as the
522 # 'target-types' attribute and with corresponding types.
524 # When 'name' is empty, all source targets must have the same 'name'
525 # attribute value, which will be used instead of the 'name' argument.
527 # The 'name' attribute value for each generated target will be equal to
528 # the 'name' parameter if there is no name pattern for this type. Otherwise,
529 # the '%' symbol in the name pattern will be replaced with the 'name'
530 # parameter to obtain the 'name' attribute.
532 # For example, if targets types are T1 and T2 (with name pattern "%_x"),
533 # suffixes for T1 and T2 are .t1 and .t2, and source is foo.z, then created
534 # files would be "foo.t1" and "foo_x.t2". The 'name' attribute actually
535 # determines the basename of a file.
537 # Note that this pattern mechanism has nothing to do with implicit patterns
538 # in make. It is a way to produce a target whose name is different than the
539 # name of its source.
541 rule generated-targets ( sources + : property-set : project name ? )
545 name = [ determine-output-name $(sources) ] ;
548 # Assign an action for each target.
549 local action = [ action-class ] ;
550 local a = [ class.new $(action) $(sources) : $(self.rule-name) :
553 # Create generated target for each target type.
555 local pre = $(self.name-prefix) ;
556 local post = $(self.name-postfix) ;
557 for local t in $(self.target-types)
559 local generated-name = $(pre[1])$(name:BS)$(post[1]) ;
560 generated-name = $(generated-name:R=$(name:D)) ;
564 targets += [ class.new file-target $(generated-name) : $(t) :
565 $(project) : $(a) ] ;
568 return [ sequence.transform virtual-target.register : $(targets) ] ;
571 # Attempts to convert 'sources' to targets of types that this generator can
572 # handle. The intention is to produce the set of targets that can be used
573 # when the generator is run.
575 rule convert-to-consumable-types
580 : only-one ? # Convert 'source' to only one of the source types. If
581 # there is more that one possibility, report an error.
582 : consumed-var # Name of the variable which receives all targets which
584 bypassed-var # Name of the variable which receives all targets which
585 # can not be consumed.
588 # We are likely to be passed 'consumed' and 'bypassed' var names. Use
589 # '_' to avoid name conflicts.
592 local missing-types ;
596 # Do not know how to handle several sources yet. Just try to pass
597 # the request to other generator.
598 missing-types = $(self.source-types) ;
602 consume-directly $(sources) : _consumed : missing-types ;
605 # No need to search for transformation if some source type has consumed
606 # source and no more source types are needed.
607 if $(only-one) && $(_consumed)
612 # TODO: we should check that only one source type if create of
613 # 'only-one' is true.
614 # TODO: consider if consumed/bypassed separation should be done by
619 local transformed = [ generators.construct-types $(project) $(name)
620 : $(missing-types) : $(property-set) : $(sources) ] ;
622 # Add targets of right type to 'consumed'. Add others to 'bypassed'.
623 # The 'generators.construct' rule has done its best to convert
624 # everything to the required type. There is no need to rerun it on
625 # targets of different types.
627 # NOTE: ignoring usage requirements.
628 for local t in $(transformed[2-])
630 if [ $(t).type ] in $(missing-types)
641 _consumed = [ sequence.unique $(_consumed) ] ;
642 _bypassed = [ sequence.unique $(_bypassed) ] ;
644 # Remove elements of '_bypassed' that are in '_consumed'.
646 # Suppose the target type of current generator, X is produced from X_1
647 # and X_2, which are produced from Y by one generator. When creating X_1
648 # from Y, X_2 will be added to 'bypassed'. Likewise, when creating X_2
649 # from Y, X_1 will be added to 'bypassed', but they are also in
650 # 'consumed'. We have to remove them from bypassed, so that generators
651 # up the call stack do not try to convert them.
653 # In this particular case, X_1 instance in 'consumed' and X_1 instance
654 # in 'bypassed' will be the same: because they have the same source and
655 # action name, and 'virtual-target.register' will not allow two
656 # different instances. Therefore, it is OK to use 'set.difference'.
658 _bypassed = [ set.difference $(_bypassed) : $(_consumed) ] ;
660 $(consumed-var) += $(_consumed) ;
661 $(bypassed-var) += $(_bypassed) ;
664 # Converts several files to consumable types. Called for composing
667 rule convert-multiple-sources-to-consumable-types ( project : property-set :
668 sources * : consumed-var bypassed-var )
670 # We process each source one-by-one, trying to convert it to a usable
672 for local source in $(sources)
676 # TODO: need to check for failure on each source.
677 convert-to-consumable-types $(project) : $(property-set) : $(source)
681 generators.dout [ indent ] " failed to convert " $(source) ;
683 $(consumed-var) += $(_c) ;
684 $(bypassed-var) += $(_b) ;
688 rule consume-directly ( source : consumed-var : missing-types-var )
690 local real-source-type = [ $(source).type ] ;
692 # If there are no source types, we can consume anything.
693 local source-types = $(self.source-types) ;
694 source-types ?= $(real-source-type) ;
696 for local st in $(source-types)
698 # The 'source' if of the right type already.
699 if $(real-source-type) = $(st) || [ type.is-derived
700 $(real-source-type) $(st) ]
702 $(consumed-var) += $(source) ;
706 $(missing-types-var) += $(st) ;
711 # Returns the class to be used to actions. Default implementation returns
714 rule action-class ( )
721 # Registers a new generator instance 'g'.
725 .all-generators += $(g) ;
727 # A generator can produce several targets of the same type. We want unique
728 # occurrence of that generator in .generators.$(t) in that case, otherwise,
729 # it will be tried twice and we will get a false ambiguity.
730 for local t in [ sequence.unique [ $(g).target-types ] ]
732 .generators.$(t) += $(g) ;
735 # Update the set of generators for toolset.
737 # TODO: should we check that generator with this id is not already
738 # registered. For example, the fop.jam module intentionally declared two
739 # generators with the same id, so such check will break it.
740 local id = [ $(g).id ] ;
742 # Some generators have multiple periods in their name, so a simple $(id:S=)
743 # will not generate the right toolset name. E.g. if id = gcc.compile.c++,
744 # then .generators-for-toolset.$(id:S=) will append to
745 # .generators-for-toolset.gcc.compile, which is a separate value from
746 # .generators-for-toolset.gcc. Correcting this makes generator inheritance
747 # work properly. See also inherit-generators in the toolset module.
753 .generators-for-toolset.$(base) += $(g) ;
756 # After adding a new generator that can construct new target types, we need
757 # to clear the related cached viable source target type information for
758 # constructing a specific target type or using a specific generator. Cached
759 # viable source target type lists affected by this are those containing any
760 # of the target types constructed by the new generator or any of their base
763 # A more advanced alternative to clearing that cached viable source target
764 # type information would be to expand it with additional source types or
765 # even better - mark it as needing to be expanded on next use.
767 # Also see the http://thread.gmane.org/gmane.comp.lib.boost.build/19077
768 # mailing list thread for an even more advanced idea of how we could convert
769 # Boost Build's Jamfile processing, target selection and generator selection
770 # into separate steps which would prevent these caches from ever being
773 # For now we just clear all the cached viable source target type information
774 # that does not simply state 'all types' and may implement a more detailed
775 # algorithm later on if it becomes needed.
777 invalidate-extendable-viable-source-target-type-cache ;
781 # Creates a new non-composing 'generator' class instance and registers it.
782 # Returns the created instance. Rationale: the instance is returned so that it
783 # is possible to first register a generator and then call its 'run' method,
784 # bypassing the whole generator selection process.
786 rule register-standard ( id : source-types * : target-types + : requirements * )
788 local g = [ new generator $(id) : $(source-types) : $(target-types) :
795 # Creates a new composing 'generator' class instance and registers it.
797 rule register-composing ( id : source-types * : target-types + : requirements *
800 local g = [ new generator $(id) true : $(source-types) : $(target-types) :
807 # Returns all generators belonging to the given 'toolset', i.e. whose ids are
808 # '$(toolset).<something>'.
810 rule generators-for-toolset ( toolset )
812 return $(.generators-for-toolset.$(toolset)) ;
816 # Make generator 'overrider-id' be preferred to 'overridee-id'. If, when
817 # searching for generators that could produce a target of a certain type, both
818 # those generators are among viable generators, the overridden generator is
819 # immediately discarded.
821 # The overridden generators are discarded immediately after computing the list
822 # of viable generators but before running any of them.
824 rule override ( overrider-id : overridee-id )
826 .override.$(overrider-id) += $(overridee-id) ;
830 # Returns a list of source type which can possibly be converted to 'target-type'
831 # by some chain of generator invocation.
833 # More formally, takes all generators for 'target-type' and returns a union of
834 # source types for those generators and result of calling itself recursively on
837 # Returns '*' in case any type should be considered a viable source type for the
840 local rule viable-source-types-real ( target-type )
844 # 't0' is the initial list of target types we need to process to get a list
845 # of their viable source target types. New target types will not be added to
847 local t0 = [ type.all-bases $(target-type) ] ;
849 # 't' is the list of target types which have not yet been processed to get a
850 # list of their viable source target types. This list will get expanded as
851 # we locate more target types to process.
856 # Find all generators for the current type. Unlike
857 # 'find-viable-generators' we do not care about the property-set.
858 local generators = $(.generators.$(t[1])) ;
863 local g = $(generators[1]) ;
864 generators = $(generators[2-]) ;
866 if ! [ $(g).source-types ]
868 # Empty source types -- everything can be accepted.
870 # This will terminate this loop.
872 # This will terminate the outer loop.
876 for local source-type in [ $(g).source-types ]
878 if ! $(source-type) in $(result)
880 # If a generator accepts a 'source-type' it will also
881 # happily accept any type derived from it.
882 for local n in [ type.all-derived $(source-type) ]
884 if ! $(n) in $(result)
886 # Here there is no point in adding target types to
887 # the list of types to process in case they are or
888 # have already been on that list. We optimize this
889 # check by realizing that we only need to avoid the
890 # original target type's base types. Other target
891 # types that are or have been on the list of target
892 # types to process have been added to the 'result'
893 # list as well and have thus already been eliminated
894 # by the previous if.
911 # Helper rule, caches the result of 'viable-source-types-real'.
913 rule viable-source-types ( target-type )
915 local key = .vst.$(target-type) ;
918 .vst-cached-types += $(target-type) ;
919 local v = [ viable-source-types-real $(target-type) ] ;
934 # Returns the list of source types, which, when passed to 'run' method of
935 # 'generator', has some change of being eventually used (probably after
936 # conversion by other generators).
938 # Returns '*' in case any type should be considered a viable source type for the
941 rule viable-source-types-for-generator-real ( generator )
943 local source-types = [ $(generator).source-types ] ;
946 # If generator does not specify any source types, it might be a special
947 # generator like builtin.lib-generator which just relays to other
948 # generators. Return '*' to indicate that any source type is possibly
949 # OK, since we do not know for sure.
955 while $(source-types)
957 local s = $(source-types[1]) ;
958 source-types = $(source-types[2-]) ;
959 local viable-sources = [ generators.viable-source-types $(s) ] ;
960 if $(viable-sources) = *
963 source-types = ; # Terminate the loop.
967 result += [ type.all-derived $(s) ] $(viable-sources) ;
970 return [ sequence.unique $(result) ] ;
975 # Helper rule, caches the result of 'viable-source-types-for-generator'.
977 local rule viable-source-types-for-generator ( generator )
979 local key = .vstg.$(generator) ;
982 .vstg-cached-generators += $(generator) ;
983 local v = [ viable-source-types-for-generator-real $(generator) ] ;
998 # Returns usage requirements + list of created targets.
1000 local rule try-one-generator-really ( project name ? : generator : target-type
1001 : property-set : sources * )
1004 [ $(generator).run $(project) $(name) : $(property-set) : $(sources) ] ;
1006 local usage-requirements ;
1009 generators.dout [ indent ] returned $(targets) ;
1015 if [ class.is-a $(targets[1]) : property-set ]
1017 usage-requirements = $(targets[1]) ;
1018 targets = $(targets[2-]) ;
1022 usage-requirements = [ property-set.empty ] ;
1026 generators.dout [ indent ] " generator" [ $(generator).id ] " spawned " ;
1027 generators.dout [ indent ] " " $(targets) ;
1028 if $(usage-requirements)
1030 generators.dout [ indent ] " with usage requirements:" $(x) ;
1035 return $(usage-requirements) $(targets) ;
1040 # Checks if generator invocation can be pruned, because it is guaranteed to
1041 # fail. If so, quickly returns an empty list. Otherwise, calls
1042 # try-one-generator-really.
1044 local rule try-one-generator ( project name ? : generator : target-type
1045 : property-set : sources * )
1047 local source-types ;
1048 for local s in $(sources)
1050 source-types += [ $(s).type ] ;
1052 local viable-source-types = [ viable-source-types-for-generator $(generator)
1055 if $(source-types) && $(viable-source-types) != * &&
1056 ! [ set.intersection $(source-types) : $(viable-source-types) ]
1058 local id = [ $(generator).id ] ;
1059 generators.dout [ indent ] " ** generator '$(id)' pruned" ;
1060 #generators.dout [ indent ] "source-types" '$(source-types)' ;
1061 #generators.dout [ indent ] "viable-source-types" '$(viable-source-types)' ;
1065 return [ try-one-generator-really $(project) $(name) : $(generator) :
1066 $(target-type) : $(property-set) : $(sources) ] ;
1071 rule construct-types ( project name ? : target-types + : property-set
1075 local matched-types ;
1076 local usage-requirements = [ property-set.empty ] ;
1077 for local t in $(target-types)
1079 local r = [ construct $(project) $(name) : $(t) : $(property-set) :
1083 usage-requirements = [ $(usage-requirements).add $(r[1]) ] ;
1084 result += $(r[2-]) ;
1085 matched-types += $(t) ;
1088 # TODO: have to introduce parameter controlling if several types can be
1089 # matched and add appropriate checks.
1091 # TODO: need to review the documentation for 'construct' to see if it should
1092 # return $(source) even if nothing can be done with it. Currents docs seem
1093 # to imply that, contrary to the behaviour.
1096 return $(usage-requirements) $(result) ;
1100 return $(usage-requirements) $(sources) ;
1105 # Ensures all 'targets' have their type. If this is not so, exists with error.
1107 local rule ensure-type ( targets * )
1109 for local t in $(targets)
1113 errors.error "target" [ $(t).str ] "has no type" ;
1119 # Returns generators which can be used to construct target of specified type
1120 # with specified properties. Uses the following algorithm:
1121 # - iterates over requested target-type and all its bases (in the order returned
1122 # by type.all-bases).
1123 # - for each type find all generators that generate that type and whose
1124 # requirements are satisfied by properties.
1125 # - if the set of generators is not empty, returns that set.
1127 # Note: this algorithm explicitly ignores generators for base classes if there
1128 # is at least one generator for the requested target-type.
1130 local rule find-viable-generators-aux ( target-type : property-set )
1132 # Select generators that can create the required target type.
1133 local viable-generators = ;
1134 local generator-rank = ;
1137 local t = [ type.all-bases $(target-type) ] ;
1139 generators.dout [ indent ] find-viable-generators target-type= $(target-type)
1140 property-set= [ $(property-set).as-path ] ;
1142 # Get the list of generators for the requested type. If no generator is
1143 # registered, try base type, and so on.
1147 generators.dout [ indent ] "trying type" $(t[1]) ;
1148 if $(.generators.$(t[1]))
1150 generators.dout [ indent ] "there are generators for this type" ;
1151 generators = $(.generators.$(t[1])) ;
1153 if $(t[1]) != $(target-type)
1155 # We are here because there were no generators found for
1156 # target-type but there are some generators for its base type.
1157 # We will try to use them, but they will produce targets of
1158 # base type, not of 'target-type'. So, we clone the generators
1159 # and modify the list of target types.
1161 for local g in $(generators)
1163 # generators.register adds a generator to the list of
1164 # generators for toolsets, which is a bit strange, but
1165 # should work. That list is only used when inheriting a
1166 # toolset, which should have been done before running
1168 generators2 += [ $(g).clone-and-change-target-type $(t[1]) :
1170 generators.register $(generators2[-1]) ;
1172 generators = $(generators2) ;
1179 for local g in $(generators)
1181 generators.dout [ indent ] "trying generator" [ $(g).id ] "(" [ $(g).source-types ] -> [ $(g).target-types ] ")" ;
1183 local m = [ $(g).match-rank $(property-set) ] ;
1186 generators.dout [ indent ] " is viable" ;
1187 viable-generators += $(g) ;
1191 return $(viable-generators) ;
1195 rule find-viable-generators ( target-type : property-set )
1197 local key = $(target-type).$(property-set) ;
1198 local l = $(.fv.$(key)) ;
1201 l = [ find-viable-generators-aux $(target-type) : $(property-set) ] ;
1214 local viable-generators ;
1217 # Avoid trying the same generator twice on different levels.
1218 if ! $(g) in $(.active-generators)
1220 viable-generators += $(g) ;
1224 generators.dout [ indent ] " generator " [ $(g).id ] "is active, discaring" ;
1228 # Generators which override 'all'.
1229 local all-overrides ;
1230 # Generators which are overriden.
1231 local overriden-ids ;
1232 for local g in $(viable-generators)
1234 local id = [ $(g).id ] ;
1235 local this-overrides = $(.override.$(id)) ;
1236 overriden-ids += $(this-overrides) ;
1237 if all in $(this-overrides)
1239 all-overrides += $(g) ;
1244 viable-generators = $(all-overrides) ;
1247 for local g in $(viable-generators)
1249 if ! [ $(g).id ] in $(overriden-ids)
1259 .construct-stack = ;
1262 # Attempts to construct a target by finding viable generators, running them and
1263 # selecting the dependency graph.
1265 local rule construct-really ( project name ? : target-type : property-set :
1268 viable-generators = [ find-viable-generators $(target-type) :
1271 generators.dout [ indent ] "*** " [ sequence.length $(viable-generators) ]
1272 " viable generators" ;
1275 local generators-that-succeeded ;
1276 for local g in $(viable-generators)
1278 # This variable will be restored on exit from this scope.
1279 local .active-generators = $(g) $(.active-generators) ;
1281 local r = [ try-one-generator $(project) $(name) : $(g) : $(target-type)
1282 : $(property-set) : $(sources) ] ;
1286 generators-that-succeeded += $(g) ;
1289 ECHO "Error: ambiguity found when searching for best transformation" ;
1290 ECHO "Trying to produce type '$(target-type)' from: " ;
1291 for local s in $(sources)
1293 ECHO " - " [ $(s).str ] ;
1295 ECHO "Generators that succeeded:" ;
1296 for local g in $(generators-that-succeeded)
1298 ECHO " - " [ $(g).id ] ;
1300 ECHO "First generator produced: " ;
1301 for local t in $(result[2-])
1303 ECHO " - " [ $(t).str ] ;
1305 ECHO "Second generator produced: " ;
1306 for local t in $(r[2-])
1308 ECHO " - " [ $(t).str ] ;
1323 # Attempts to create a target of 'target-type' with 'properties' from 'sources'.
1324 # The 'sources' are treated as a collection of *possible* ingridients, i.e.
1325 # there is no obligation to consume them all.
1327 # Returns a list of targets. When this invocation is first instance of
1328 # 'construct' in stack, returns only targets of requested 'target-type',
1329 # otherwise, returns also unused sources and additionally generated targets.
1331 # If 'top-level' is set, does not suppress generators that are already
1332 # used in the stack. This may be useful in cases where a generator
1333 # has to build a metatargets -- for example a target corresponding to
1336 rule construct ( project name ? : target-type : property-set * : sources * : top-level ? )
1341 saved-active = $(.active-generators) ;
1342 .active-generators = ;
1345 if (.construct-stack)
1347 ensure-type $(sources) ;
1350 .construct-stack += 1 ;
1356 generators.dout [ indent ] "*** construct" $(target-type) ;
1358 for local s in $(sources)
1360 generators.dout [ indent ] " from" $(s) ;
1362 generators.dout [ indent ] " properties:" [ $(property-set).raw ] ;
1365 local result = [ construct-really $(project) $(name) : $(target-type) :
1366 $(property-set) : $(sources) ] ;
1370 .construct-stack = $(.construct-stack[2-]) ;
1374 .active-generators = $(saved-active) ;
1380 # Given 'result', obtained from some generator or generators.construct, adds
1381 # 'raw-properties' as usage requirements to it. If result already contains usage
1382 # requirements -- that is the first element of result of an instance of the
1383 # property-set class, the existing usage requirements and 'raw-properties' are
1386 rule add-usage-requirements ( result * : raw-properties * )
1390 if [ class.is-a $(result[1]) : property-set ]
1392 return [ $(result[1]).add-raw $(raw-properties) ] $(result[2-]) ;
1396 return [ property-set.create $(raw-properties) ] $(result) ;
1403 for local g in $(.all-generators)
1405 ECHO [ $(g).id ] ":" [ $(g).source-types ] -> [ $(g).target-types ] ;