Imported Upstream version 1.49.0
[platform/upstream/boost.git] / tools / build / v2 / build / generators.jam
1 # Copyright Vladimir Prus 2002.
2 # Copyright Rene Rivera 2006.
3 #
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 # Manages 'generators' --- objects which can do transformation between different
9 # target types and contain algorithm for finding transformation from sources to
10 # targets.
11 #
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.
17 #
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
22 # types.
23 #
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.
27 #
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.
32 #
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.
39 #
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.
45
46 import "class" : new ;
47 import errors ;
48 import property-set ;
49 import sequence ;
50 import set ;
51 import type ;
52 import utility ;
53 import virtual-target ;
54
55
56 if "--debug-generators" in [ modules.peek : ARGV ]
57 {
58     .debug = true ;
59 }
60
61
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
67 # passed to it.
68 #
69 rule update-cached-information-with-a-new-type ( type )
70 {
71     local base-type = [ type.base $(type) ] ;
72     if $(base-type)
73     {
74         for local g in $(.vstg-cached-generators)
75         {
76             if $(base-type) in $(.vstg.$(g))
77             {
78                 .vstg.$(g) += $(type) ;
79             }
80         }
81
82         for local t in $(.vst-cached-types)
83         {
84             if $(base-type) in $(.vst.$(t))
85             {
86                 .vst.$(t) += $(type) ;
87             }
88         }
89     }
90 }
91
92
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.
97 #
98 local rule invalidate-extendable-viable-source-target-type-cache ( )
99 {
100     local generators-with-cached-source-types = $(.vstg-cached-generators) ;
101     .vstg-cached-generators = ;
102     for local g in $(generators-with-cached-source-types)
103     {
104         if $(.vstg.$(g)) = *
105         {
106             .vstg-cached-generators += $(g) ;
107         }
108         else
109         {
110             .vstg.$(g) = ;
111         }
112     }
113
114     local types-with-cached-source-types = $(.vst-cached-types) ;
115     .vst-cached-types = ;
116     for local t in $(types-with-cached-source-types)
117     {
118         if $(.vst.$(t)) = *
119         {
120             .vst-cached-types += $(t) ;
121         }
122         else
123         {
124             .vst.$(t) = ;
125         }
126     }
127 }
128
129
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.
133 #
134 local rule generators.dout ( message * )
135 {
136     if $(.debug)
137     {
138         ECHO [ sequence.transform utility.str : $(message) ] ;
139     }
140 }
141
142
143 local rule indent ( )
144 {
145     return $(.indent:J="") ;
146 }
147
148
149 local rule increase-indent ( )
150 {
151     .indent += "    " ;
152 }
153
154
155 local rule decrease-indent ( )
156 {
157     .indent = $(.indent[2-]) ;
158 }
159
160
161 # Models a generator.
162 #
163 class generator
164 {
165     import generators : indent increase-indent decrease-indent generators.dout ;
166     import set ;
167     import utility ;
168     import feature ;
169     import errors ;
170     import sequence ;
171     import type ;
172     import virtual-target ;
173     import "class" : new ;
174     import property ;
175     import path ;
176
177     EXPORT class@generator : indent increase-indent decrease-indent
178         generators.dout ;
179
180     rule __init__ (
181         id                          # Identifies the generator - should be name
182                                     # of the rule which sets up the build
183                                     # actions.
184
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.
190
191         : source-types *            # Types that this generator can handle. If
192                                     # empty, the generator can consume anything.
193
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
201                                     # specified.
202
203         : requirements *
204     )
205     {
206         self.id = $(id) ;
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) ;
212
213         for local e in $(target-types-and-names)
214         {
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="") ;
224         }
225
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) ;
229     }
230
231     ################# End of constructor #################
232
233     rule id ( )
234     {
235         return $(self.id) ;
236     }
237
238     # Returns the list of target type the generator accepts.
239     #
240     rule source-types ( )
241     {
242         return $(self.source-types) ;
243     }
244
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.
248     #
249     rule target-types ( )
250     {
251         return $(self.target-types) ;
252     }
253
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.
258     #
259     # XXX: remove this method?
260     #
261     rule requirements ( )
262     {
263         return $(self.requirements) ;
264     }
265     
266     rule set-rule-name ( rule-name )
267     {
268         self.rule-name = $(rule-name) ;
269     }
270     
271     rule rule-name ( )
272     {
273         return $(self.rule-name) ;
274     }
275         
276     # Returns a true value if the generator can be run with the specified
277     # properties.
278     #
279     rule match-rank ( property-set-to-match )
280     {
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 ] ;
285
286         local property-requirements feature-requirements ;
287         for local r in $(all-requirements)
288         {
289             if $(r:G=)
290             {
291                 property-requirements += $(r) ;
292             }
293             else
294             {
295                 feature-requirements += $(r) ;
296             }
297         }
298
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)
302         {
303             return true ;
304         }
305         else
306         {
307             return ;
308         }
309     }
310
311     # Returns another generator which differs from $(self) in
312     #   - id
313     #   - value to <toolset> feature in properties
314     #
315     rule clone ( new-id : new-toolset-properties + )
316     {
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) ] ;       
323         return $(g) ;
324     }
325
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
328     # new generator.
329     #
330     rule clone-and-change-target-type ( base : type )
331     {
332         local target-types ;
333         for local t in $(self.target-types-and-names)
334         {
335             local m = [ MATCH ([^\\(]*)(\\(.*\\))? : $(t) ] ;
336             if $(m) = $(base)
337             {
338                 target-types += $(type)$(m[2]:E="") ;
339             }
340             else
341             {
342                 target-types += $(t) ;
343             }
344         }
345
346         local g = [ new $(__class__) $(self.id) $(self.composing) :
347             $(self.source-types) : $(target-types) : $(self.requirements) ] ;
348         if $(self.rule-name)
349         {            
350             $(g).set-rule-name $(self.rule-name) ;
351         }        
352         return $(g) ;        
353     }
354
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.
360     #
361     rule run
362     (
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.
368     )
369     {
370         generators.dout [ indent ] "  ** generator" $(self.id) ;
371         generators.dout [ indent ] "  composing:" $(self.composing) ;
372
373         if ! $(self.composing) && $(sources[2]) && $(self.source-types[2])
374         {
375             errors.error "Unsupported source/source-type combination" ;
376         }
377
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.
382         #
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)
389         {
390             run-really $(project) $(name) : $(property-set) : $(sources) ;
391         }
392     }
393
394     rule run-really ( project name ? : property-set : sources + )
395     {
396         # Targets that this generator will consume directly.
397         local consumed = ;
398         # Targets that can not be consumed and will be returned as-is.
399         local bypassed = ;
400
401         if $(self.composing)
402         {
403             convert-multiple-sources-to-consumable-types $(project)
404                 : $(property-set) : $(sources) : consumed bypassed ;
405         }
406         else
407         {
408             convert-to-consumable-types $(project) $(name) : $(property-set)
409                 : $(sources) : : consumed bypassed ;
410         }
411
412         local result ;
413         if $(consumed)
414         {
415             result = [ construct-result $(consumed) : $(project) $(name) :
416                 $(property-set) ] ;
417         }
418
419         if $(result)
420         {
421             generators.dout [ indent ] "  SUCCESS: " $(result) ;
422         }
423         else
424         {
425             generators.dout [ indent ] "  FAILURE" ;
426         }
427         generators.dout ;
428         return $(result) ;
429     }
430
431     # Constructs the dependency graph to be returned by this generator.
432     #
433     rule construct-result
434     (
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).
445         : project name ?
446         : property-set    # Properties to be used for all actions created here.
447     )
448     {
449         local result ;
450         # If this is 1->1 transformation, apply it to all consumed targets in
451         # order.
452         if ! $(self.source-types[2]) && ! $(self.composing)
453         {
454             for local r in $(consumed)
455             {
456                 result += [ generated-targets $(r) : $(property-set) :
457                     $(project) $(name) ] ;
458             }
459         }
460         else if $(consumed)
461         {
462             result += [ generated-targets $(consumed) : $(property-set) :
463                 $(project) $(name) ] ;
464         }
465         return $(result) ;
466     }
467
468     # Determine target name from fullname (maybe including path components)
469     # Place optional prefix and postfix around basename
470     #
471     rule determine-target-name ( fullname  : prefix ? : postfix ? )
472     {
473         # See if we need to add directory to the target name.
474         local dir  = $(fullname:D) ;            
475         local name = $(fullname:B) ; 
476         
477         name = $(prefix:E=)$(name) ;
478         name = $(name)$(postfix:E=) ;
479
480         if $(dir) && 
481           # Never append '..' to target path.
482           ! [ MATCH .*(\\.\\.).* : $(dir) ] 
483             && 
484           ! [ path.is-rooted $(dir) ]
485         {
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) ;                
490         }            
491         return $(name) ;
492     }
493
494     # Determine the name of the produced target from the names of the sources.
495     #
496     rule determine-output-name ( sources + )
497     {
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
505         # too.
506         name = [ utility.basename [ $(sources[1]).name ] ] ;
507
508         for local s in $(sources[2])
509         {
510             local n2 = [ utility.basename [ $(s).name ] ] ;
511             if $(n2) != $(name)
512             {
513                 errors.error "$(self.id): source targets have different names: cannot determine target name" ;
514             }
515         }
516         name = [ determine-target-name [ $(sources[1]).name ] ] ;
517         return $(name) ;
518     }
519
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.
523     #
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.
526     #
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.
531     #
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.
536     #
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.
540     #
541     rule generated-targets ( sources + : property-set : project name ? )
542     {
543         if ! $(name)
544         {
545             name = [ determine-output-name $(sources) ] ;
546         }
547
548         # Assign an action for each target.
549         local action = [ action-class ] ;
550         local a = [ class.new $(action) $(sources) : $(self.rule-name) :
551                     $(property-set) ] ;
552
553         # Create generated target for each target type.
554         local targets ;
555         local pre = $(self.name-prefix) ;
556         local post = $(self.name-postfix) ;
557         for local t in $(self.target-types)
558         {
559             local generated-name = $(pre[1])$(name:BS)$(post[1]) ;
560             generated-name = $(generated-name:R=$(name:D)) ;
561             pre = $(pre[2-]) ;
562             post = $(post[2-]) ;
563
564             targets += [ class.new file-target $(generated-name) : $(t) :
565                 $(project) : $(a) ] ;
566         }
567
568         return [ sequence.transform virtual-target.register : $(targets) ] ;
569     }
570
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.
574     #
575     rule convert-to-consumable-types
576     (
577         project name ?
578         : property-set
579         : sources +
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
583                         # can be consumed.
584           bypassed-var  # Name of the variable which receives all targets which
585                         # can not be consumed.
586     )
587     {
588         # We are likely to be passed 'consumed' and 'bypassed' var names. Use
589         # '_' to avoid name conflicts.
590         local _consumed ;
591         local _bypassed ;
592         local missing-types ;
593
594         if $(sources[2])
595         {
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) ;
599         }
600         else
601         {
602             consume-directly $(sources) : _consumed : missing-types ;
603         }
604
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)
608         {
609             missing-types = ;
610         }
611
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
615         # 'construct-types'.
616
617         if $(missing-types)
618         {
619             local transformed = [ generators.construct-types $(project) $(name)
620                 : $(missing-types) : $(property-set) : $(sources) ] ;
621
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.
626
627             # NOTE: ignoring usage requirements.
628             for local t in $(transformed[2-])
629             {
630                 if [ $(t).type ] in $(missing-types)
631                 {
632                     _consumed += $(t) ;
633                 }
634                 else
635                 {
636                     _bypassed += $(t) ;
637                 }
638             }
639         }
640
641         _consumed = [ sequence.unique $(_consumed) ] ;
642         _bypassed = [ sequence.unique $(_bypassed) ] ;
643
644         # Remove elements of '_bypassed' that are in '_consumed'.
645
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.
652
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'.
657
658         _bypassed = [ set.difference $(_bypassed) : $(_consumed) ] ;
659
660         $(consumed-var) += $(_consumed) ;
661         $(bypassed-var) += $(_bypassed) ;
662     }
663
664     # Converts several files to consumable types. Called for composing
665     # generators only.
666     #
667     rule convert-multiple-sources-to-consumable-types ( project : property-set :
668         sources * : consumed-var bypassed-var )
669     {
670         # We process each source one-by-one, trying to convert it to a usable
671         # type.
672         for local source in $(sources)
673         {
674             local _c ;
675             local _b ;
676             # TODO: need to check for failure on each source.
677             convert-to-consumable-types $(project) : $(property-set) : $(source)
678                 : true : _c _b ;
679             if ! $(_c)
680             {
681                 generators.dout [ indent ] " failed to convert " $(source) ;
682             }
683             $(consumed-var) += $(_c) ;
684             $(bypassed-var) += $(_b) ;
685         }
686     }
687
688     rule consume-directly ( source : consumed-var : missing-types-var )
689     {
690         local real-source-type = [ $(source).type ] ;
691
692         # If there are no source types, we can consume anything.
693         local source-types = $(self.source-types) ;
694         source-types ?= $(real-source-type) ;
695
696         for local st in $(source-types)
697         {
698             # The 'source' if of the right type already.
699             if $(real-source-type) = $(st) || [ type.is-derived
700                 $(real-source-type) $(st) ]
701             {
702                 $(consumed-var) += $(source) ;
703             }
704             else
705             {
706                 $(missing-types-var) += $(st) ;
707             }
708         }
709     }
710
711     # Returns the class to be used to actions. Default implementation returns
712     # "action".
713     #
714     rule action-class ( )
715     {
716         return "action" ;
717     }
718 }
719
720
721 # Registers a new generator instance 'g'.
722 #
723 rule register ( g )
724 {
725     .all-generators += $(g) ;
726         
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 ] ]
731     {
732         .generators.$(t) += $(g) ;
733     }
734
735     # Update the set of generators for toolset.
736
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 ] ;
741
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.
748     local base = $(id) ;
749     while $(base:S)
750     {
751         base = $(base:B) ;
752     }
753     .generators-for-toolset.$(base) += $(g) ;
754
755
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
761     # target types.
762     #
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.
766     #
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
771     # invalidated.
772     #
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.
776
777     invalidate-extendable-viable-source-target-type-cache ;
778 }
779
780
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.
785 #
786 rule register-standard ( id : source-types * : target-types + : requirements * )
787 {
788     local g = [ new generator $(id) : $(source-types) : $(target-types) :
789         $(requirements) ] ;
790     register $(g) ;
791     return $(g) ;
792 }
793
794
795 # Creates a new composing 'generator' class instance and registers it.
796 #
797 rule register-composing ( id : source-types * : target-types + : requirements *
798     )
799 {
800     local g = [ new generator $(id) true : $(source-types) : $(target-types) :
801         $(requirements) ] ;
802     register $(g) ;
803     return $(g) ;
804 }
805
806
807 # Returns all generators belonging to the given 'toolset', i.e. whose ids are
808 # '$(toolset).<something>'.
809 #
810 rule generators-for-toolset ( toolset )
811 {
812     return $(.generators-for-toolset.$(toolset)) ;
813 }
814
815
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.
820 #
821 # The overridden generators are discarded immediately after computing the list
822 # of viable generators but before running any of them.
823 #
824 rule override ( overrider-id : overridee-id )
825 {
826     .override.$(overrider-id) += $(overridee-id) ;
827 }
828
829
830 # Returns a list of source type which can possibly be converted to 'target-type'
831 # by some chain of generator invocation.
832 #
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
835 # source types.
836 #
837 # Returns '*' in case any type should be considered a viable source type for the
838 # given type.
839 #
840 local rule viable-source-types-real ( target-type )
841 {
842     local result ;
843
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
846     # this list.
847     local t0 = [ type.all-bases $(target-type) ] ;
848
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.
852     local t = $(t0) ;
853
854     while $(t)
855     {
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])) ;
859         t = $(t[2-]) ;
860
861         while $(generators)
862         {
863             local g = $(generators[1]) ;
864             generators = $(generators[2-]) ;
865
866             if ! [ $(g).source-types ]
867             {
868                 # Empty source types -- everything can be accepted.
869                 result = * ;
870                 # This will terminate this loop.
871                 generators = ;
872                 # This will terminate the outer loop.
873                 t = ;
874             }
875
876             for local source-type in [ $(g).source-types ]
877             {
878                 if ! $(source-type) in $(result)
879                 {
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) ]
883                     {
884                         if ! $(n) in $(result)
885                         {
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.
895                             if ! $(n) in $(t0)
896                             {
897                                 t += $(n) ;
898                             }
899                             result += $(n) ;
900                         }
901                     }
902                 }
903             }
904         }
905     }
906
907     return $(result) ;
908 }
909
910
911 # Helper rule, caches the result of 'viable-source-types-real'.
912 #
913 rule viable-source-types ( target-type )
914 {
915     local key = .vst.$(target-type) ;
916     if ! $($(key))
917     {
918         .vst-cached-types += $(target-type) ;
919         local v = [ viable-source-types-real $(target-type) ] ;
920         if ! $(v)
921         {
922             v = none ;
923         }
924         $(key) = $(v) ;
925     }
926
927     if $($(key)) != none
928     {
929         return $($(key)) ;
930     }
931 }
932
933
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).
937 #
938 # Returns '*' in case any type should be considered a viable source type for the
939 # given generator.
940 #
941 rule viable-source-types-for-generator-real ( generator )
942 {
943     local source-types = [ $(generator).source-types ] ;
944     if ! $(source-types)
945     {
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.
950         return * ;
951     }
952     else
953     {
954         local result ;
955         while $(source-types)
956         {
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) = *
961             {
962                 result = * ;
963                 source-types = ;  # Terminate the loop.
964             }
965             else
966             {
967                 result += [ type.all-derived $(s) ] $(viable-sources) ;
968             }
969         }
970         return [ sequence.unique $(result) ] ;
971     }
972 }
973
974
975 # Helper rule, caches the result of 'viable-source-types-for-generator'.
976 #
977 local rule viable-source-types-for-generator ( generator )
978 {
979     local key = .vstg.$(generator) ;
980     if ! $($(key))
981     {
982         .vstg-cached-generators += $(generator) ;
983         local v = [ viable-source-types-for-generator-real $(generator) ] ;
984         if ! $(v)
985         {
986             v = none ;
987         }
988         $(key) = $(v) ;
989     }
990
991     if $($(key)) != none
992     {
993         return $($(key)) ;
994     }
995 }
996
997
998 # Returns usage requirements + list of created targets.
999 #
1000 local rule try-one-generator-really ( project name ? : generator : target-type
1001     : property-set : sources * )
1002 {
1003     local targets =
1004         [ $(generator).run $(project) $(name) : $(property-set) : $(sources) ] ;
1005
1006     local usage-requirements ;
1007     local success ;
1008
1009     generators.dout [ indent ] returned $(targets) ;
1010
1011     if $(targets)
1012     {
1013         success = true ;
1014
1015         if  [ class.is-a $(targets[1]) : property-set ]
1016         {
1017             usage-requirements = $(targets[1]) ;
1018             targets = $(targets[2-]) ;
1019         }
1020         else
1021         {
1022             usage-requirements = [ property-set.empty ] ;
1023         }
1024     }
1025
1026     generators.dout [ indent ] "  generator" [ $(generator).id ] " spawned " ;
1027     generators.dout [ indent ] " " $(targets) ;
1028     if $(usage-requirements)
1029     {
1030         generators.dout [ indent ] "  with usage requirements:" $(x) ;
1031     }
1032
1033     if $(success)
1034     {
1035         return $(usage-requirements) $(targets) ;
1036     }
1037 }
1038
1039
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.
1043 #
1044 local rule try-one-generator ( project name ? : generator : target-type
1045     : property-set : sources * )
1046 {
1047     local source-types ;
1048     for local s in $(sources)
1049     {
1050         source-types += [ $(s).type ] ;
1051     }
1052     local viable-source-types = [ viable-source-types-for-generator $(generator)
1053         ] ;
1054
1055     if  $(source-types) && $(viable-source-types) != * &&
1056         ! [ set.intersection $(source-types) : $(viable-source-types) ]
1057     {
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)' ;
1062     }
1063     else
1064     {
1065         return [ try-one-generator-really $(project) $(name) : $(generator) :
1066             $(target-type) : $(property-set) : $(sources) ] ;
1067     }
1068 }
1069
1070
1071 rule construct-types ( project name ? : target-types + : property-set
1072     : sources + )
1073 {
1074     local result ;
1075     local matched-types ;
1076     local usage-requirements = [ property-set.empty ] ;
1077     for local t in $(target-types)
1078     {
1079         local r = [ construct $(project) $(name) : $(t) : $(property-set) :
1080             $(sources) ] ;
1081         if $(r)
1082         {
1083             usage-requirements = [ $(usage-requirements).add $(r[1]) ] ;
1084             result += $(r[2-]) ;
1085             matched-types += $(t) ;
1086         }
1087     }
1088     # TODO: have to introduce parameter controlling if several types can be
1089     # matched and add appropriate checks.
1090
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.
1094     if $(result)
1095     {
1096         return $(usage-requirements) $(result) ;
1097     }
1098     else
1099     {
1100         return $(usage-requirements) $(sources) ;
1101     }
1102 }
1103
1104
1105 # Ensures all 'targets' have their type. If this is not so, exists with error.
1106 #
1107 local rule ensure-type ( targets * )
1108 {
1109     for local t in $(targets)
1110     {
1111         if ! [ $(t).type ]
1112         {
1113             errors.error "target" [ $(t).str ] "has no type" ;
1114         }
1115     }
1116 }
1117
1118
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.
1126 #
1127 # Note: this algorithm explicitly ignores generators for base classes if there
1128 # is at least one generator for the requested target-type.
1129 #
1130 local rule find-viable-generators-aux ( target-type : property-set )
1131 {
1132     # Select generators that can create the required target type.
1133     local viable-generators = ;
1134     local generator-rank = ;
1135
1136     import type ;
1137     local t = [ type.all-bases $(target-type) ] ;
1138
1139     generators.dout [ indent ] find-viable-generators target-type= $(target-type)
1140         property-set= [ $(property-set).as-path ] ;
1141
1142     # Get the list of generators for the requested type. If no generator is
1143     # registered, try base type, and so on.
1144     local generators ;
1145     while $(t[1])
1146     {
1147         generators.dout [ indent ] "trying type" $(t[1]) ;
1148         if $(.generators.$(t[1]))
1149         {
1150             generators.dout [ indent ] "there are generators for this type" ;
1151             generators = $(.generators.$(t[1])) ;
1152
1153             if $(t[1]) != $(target-type)
1154             {
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.
1160                 local generators2 ;
1161                 for local g in $(generators)
1162                 {
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
1167                     # generators.
1168                     generators2 += [ $(g).clone-and-change-target-type $(t[1]) :
1169                         $(target-type) ] ;
1170                     generators.register $(generators2[-1]) ;
1171                 }
1172                 generators = $(generators2) ;
1173             }
1174             t = ;
1175         }
1176         t = $(t[2-]) ;
1177     }
1178
1179     for local g in $(generators)
1180     {
1181         generators.dout [ indent ] "trying generator" [ $(g).id ] "(" [ $(g).source-types ] -> [ $(g).target-types ] ")" ;
1182
1183         local m = [ $(g).match-rank $(property-set) ] ;
1184         if $(m)
1185         {
1186             generators.dout [ indent ] "  is viable" ;
1187             viable-generators += $(g) ;
1188         }
1189     }
1190
1191     return $(viable-generators) ;
1192 }
1193
1194
1195 rule find-viable-generators ( target-type : property-set )
1196 {
1197     local key = $(target-type).$(property-set) ;
1198     local l = $(.fv.$(key)) ;
1199     if ! $(l)
1200     {
1201         l = [ find-viable-generators-aux $(target-type) : $(property-set) ] ;
1202         if ! $(l)
1203         {
1204             l = none ;
1205         }
1206         .fv.$(key) = $(l) ;
1207     }
1208
1209     if $(l) = none
1210     {
1211         l = ;
1212     }
1213
1214     local viable-generators ;
1215     for local g in $(l)
1216     {
1217         # Avoid trying the same generator twice on different levels.
1218         if ! $(g) in $(.active-generators)
1219         {
1220             viable-generators += $(g) ;
1221         }
1222         else
1223         {
1224             generators.dout [ indent ] "   generator " [ $(g).id ] "is active, discaring" ;
1225         }        
1226     }
1227
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)
1233     {
1234         local id = [ $(g).id ] ;
1235         local this-overrides = $(.override.$(id)) ;
1236         overriden-ids += $(this-overrides) ;
1237         if all in $(this-overrides)
1238         {
1239             all-overrides += $(g) ;
1240         }
1241     }
1242     if $(all-overrides)
1243     {
1244         viable-generators = $(all-overrides) ;
1245     }
1246     local result ;
1247     for local g in $(viable-generators)
1248     {
1249         if ! [ $(g).id ] in $(overriden-ids)
1250         {
1251             result += $(g) ;
1252         }
1253     }
1254
1255     return $(result) ;
1256 }
1257
1258
1259 .construct-stack = ;
1260
1261
1262 # Attempts to construct a target by finding viable generators, running them and
1263 # selecting the dependency graph.
1264 #
1265 local rule construct-really ( project name ? : target-type : property-set :
1266     sources * )
1267 {
1268     viable-generators = [ find-viable-generators $(target-type) :
1269         $(property-set) ] ;
1270
1271     generators.dout [ indent ] "*** " [ sequence.length $(viable-generators) ]
1272         " viable generators" ;
1273
1274     local result ;
1275     local generators-that-succeeded ;
1276     for local g in $(viable-generators)
1277     {
1278         # This variable will be restored on exit from this scope.
1279         local .active-generators = $(g) $(.active-generators) ;
1280
1281         local r = [ try-one-generator $(project) $(name) : $(g) : $(target-type)
1282             : $(property-set) : $(sources) ] ;
1283
1284         if $(r)
1285         {
1286             generators-that-succeeded += $(g) ;
1287             if $(result)
1288             {
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)
1292                 {
1293                     ECHO " - " [ $(s).str ] ;
1294                 }
1295                 ECHO "Generators that succeeded:" ;
1296                 for local g in $(generators-that-succeeded)
1297                 {
1298                     ECHO " - " [ $(g).id ] ;
1299                 }
1300                 ECHO "First generator produced: " ;
1301                 for local t in $(result[2-])
1302                 {
1303                     ECHO " - " [ $(t).str ] ;
1304                 }
1305                 ECHO "Second generator produced: " ;
1306                 for local t in $(r[2-])
1307                 {
1308                     ECHO " - " [ $(t).str ] ;
1309                 }
1310                 EXIT ;
1311             }
1312             else
1313             {
1314                 result = $(r) ;
1315             }
1316         }
1317     }
1318
1319     return $(result) ;
1320 }
1321
1322
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.
1326 #
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.
1330 #
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
1334 # built tool.
1335 #
1336 rule construct ( project name ? : target-type : property-set * : sources * : top-level ? )
1337 {
1338     local saved-stack ;
1339     if $(top-level)
1340     {
1341         saved-active = $(.active-generators) ;
1342         .active-generators = ;
1343     }
1344         
1345     if (.construct-stack)
1346     {
1347         ensure-type $(sources) ;
1348     }
1349
1350     .construct-stack += 1 ;
1351
1352     increase-indent ;
1353
1354     if $(.debug)
1355     {
1356         generators.dout [ indent ] "*** construct" $(target-type) ;
1357
1358         for local s in $(sources)
1359         {
1360             generators.dout [ indent ] "    from" $(s) ;
1361         }
1362         generators.dout [ indent ] "    properties:" [ $(property-set).raw ] ;
1363     }
1364
1365     local result = [ construct-really $(project) $(name) : $(target-type) :
1366         $(property-set) : $(sources) ] ;
1367
1368     decrease-indent ;
1369
1370     .construct-stack = $(.construct-stack[2-]) ;
1371     
1372     if $(top-level)
1373     {
1374         .active-generators = $(saved-active) ;
1375     }
1376
1377     return $(result) ;
1378 }
1379
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
1384 # combined.
1385 #
1386 rule add-usage-requirements ( result * : raw-properties * )
1387 {
1388     if $(result)
1389     {
1390         if [ class.is-a $(result[1]) : property-set ]
1391         {
1392             return [ $(result[1]).add-raw $(raw-properties) ] $(result[2-]) ;
1393         }
1394         else
1395         {
1396             return [ property-set.create $(raw-properties) ] $(result) ;
1397         }
1398     }
1399 }
1400
1401 rule dump ( )
1402 {
1403     for local g in $(.all-generators)
1404     {
1405         ECHO [ $(g).id ] ":" [ $(g).source-types ] -> [ $(g).target-types ] ;            
1406     }    
1407 }
1408