]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/src/build/virtual-target.jam
update sources to v12.2.3
[ceph.git] / ceph / src / boost / tools / build / src / build / virtual-target.jam
1 # Copyright 2003 Dave Abrahams
2 # Copyright 2005, 2006 Rene Rivera
3 # Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus
4 # Distributed under the Boost Software License, Version 1.0.
5 # (See accompanying file LICENSE_1_0.txt or copy at
6 # http://www.boost.org/LICENSE_1_0.txt)
7
8 # Implements virtual targets, which correspond to actual files created during a
9 # build, but are not yet targets in Jam sense. They are needed, for example,
10 # when searching for possible transformation sequences, when it is not yet known
11 # whether a particular target should be created at all.
12 #
13 # +--------------------------+
14 # | virtual-target |
15 # +==========================+
16 # | actualize |
17 # +--------------------------+
18 # | actualize-action() = 0 |
19 # | actualize-location() = 0 |
20 # +----------------+---------+
21 # |
22 # ^
23 # / \
24 # +-+-+
25 # |
26 # +---------------------+ +-------+--------------+
27 # | action | | abstract-file-target |
28 # +=====================| * +======================+
29 # | action-name | +--+ action |
30 # | properties | | +----------------------+
31 # +---------------------+--+ | actualize-action() |
32 # | actualize() |0..1 +-----------+----------+
33 # | path() | |
34 # | adjust-properties() | sources |
35 # | actualize-sources() | targets |
36 # +------+--------------+ ^
37 # | / \
38 # ^ +-+-+
39 # / \ |
40 # +-+-+ +-------------+-------------+
41 # | | |
42 # | +------+---------------+ +--------+-------------+
43 # | | file-target | | searched-lib-target |
44 # | +======================+ +======================+
45 # | | actualize-location() | | actualize-location() |
46 # | +----------------------+ +----------------------+
47 # |
48 # +-+------------------------------+
49 # | |
50 # +----+----------------+ +---------+-----------+
51 # | compile-action | | link-action |
52 # +=====================+ +=====================+
53 # | adjust-properties() | | adjust-properties() |
54 # +---------------------+ | actualize-sources() |
55 # +---------------------+
56 #
57 # The 'compile-action' and 'link-action' classes are not defined here but in
58 # builtin.jam modules. They are shown in the diagram to give the big picture.
59
60 import "class" : new ;
61 import path ;
62 import sequence ;
63 import set ;
64 import type ;
65 import utility ;
66
67
68 # Models a potential target. It can be converted into a Jam target and used in
69 # building, if needed. However, it can be also dropped, which allows us to
70 # search for different transformations and select only one.
71 #
72 class virtual-target
73 {
74 import scanner ;
75 import sequence ;
76 import utility ;
77 import virtual-target ;
78
79 rule __init__ (
80 name # Target/project name.
81 : project # Project to which this target belongs.
82 )
83 {
84 self.name = $(name) ;
85 self.project = $(project) ;
86 self.dependencies = ;
87 }
88
89 # Name of this target.
90 #
91 rule name ( )
92 {
93 return $(self.name) ;
94 }
95
96 # Project of this target.
97 #
98 rule project ( )
99 {
100 return $(self.project) ;
101 }
102
103 # Adds additional 'virtual-target' instances this one depends on.
104 #
105 rule depends ( d + )
106 {
107 self.dependencies = [ sequence.merge $(self.dependencies) :
108 [ sequence.insertion-sort $(d) ] ] ;
109 }
110
111 rule dependencies ( )
112 {
113 return $(self.dependencies) ;
114 }
115
116 rule always ( )
117 {
118 .always = 1 ;
119 }
120
121 # Generates all the actual targets and sets up build actions for this
122 # target.
123 #
124 # If 'scanner' is specified, creates an additional target with the same
125 # location as the actual target, which will depend on the actual target and
126 # be associated with a 'scanner'. That additional target is returned. See
127 # the docs (#dependency_scanning) for rationale. Target must correspond to a
128 # file if 'scanner' is specified.
129 #
130 # If scanner is not specified then the actual target is returned.
131 #
132 rule actualize ( scanner ? )
133 {
134 local actual-name = [ actualize-no-scanner ] ;
135
136 if $(.always)
137 {
138 ALWAYS $(actual-name) ;
139 }
140
141 if ! $(scanner)
142 {
143 return $(actual-name) ;
144 }
145 else
146 {
147 # Add the scanner instance to the grist for name.
148 local g = [ sequence.join [ utility.ungrist $(actual-name:G) ]
149 $(scanner) : - ] ;
150 local name = $(actual-name:G=$(g)) ;
151
152 if ! $(self.made.$(scanner))
153 {
154 self.made.$(scanner) = true ;
155 actualize-location $(name) ;
156 scanner.install $(scanner) : $(name) ;
157 }
158 return $(name) ;
159 }
160 }
161
162 # private: (overridables)
163
164 # Sets up build actions for 'target'. Should call appropriate rules and set
165 # target variables.
166 #
167 rule actualize-action ( target )
168 {
169 import errors : error : errors.error ;
170 errors.error "method should be defined in derived classes" ;
171 }
172
173 # Sets up variables on 'target' which specify its location.
174 #
175 rule actualize-location ( target )
176 {
177 import errors : error : errors.error ;
178 errors.error "method should be defined in derived classes" ;
179 }
180
181 # If the target is a generated one, returns the path where it will be
182 # generated. Otherwise, returns an empty list.
183 #
184 rule path ( )
185 {
186 import errors : error : errors.error ;
187 errors.error "method should be defined in derived classes" ;
188 }
189
190 # Returns the actual target name to be used in case when no scanner is
191 # involved.
192 #
193 rule actual-name ( )
194 {
195 import errors : error : errors.error ;
196 errors.error "method should be defined in derived classes" ;
197 }
198
199 # implementation
200 rule actualize-no-scanner ( )
201 {
202 # In fact, we just need to merge virtual-target with
203 # abstract-file-target as the latter is the only class derived from the
204 # former. But that has been left for later.
205
206 import errors : error : errors.error ;
207 errors.error "method should be defined in derived classes" ;
208 }
209 }
210
211
212 # Target corresponding to a file. The exact mapping for file is not yet
213 # specified in this class. (TODO: Actually, the class name could be better...)
214 #
215 # May be a source file (when no action is specified) or a derived file
216 # (otherwise).
217 #
218 # The target's grist is a concatenation of its project's location, action
219 # properties (for derived targets) and, optionally, value identifying the main
220 # target.
221 #
222 class abstract-file-target : virtual-target
223 {
224 import project ;
225 import regex ;
226 import sequence ;
227 import path ;
228 import type ;
229 import property-set ;
230 import indirect ;
231
232 rule __init__ (
233 name # Target's name.
234 exact ? # If non-empty, the name is exactly the name created file
235 # should have. Otherwise, the '__init__' method will add a
236 # suffix obtained from 'type' by calling
237 # 'type.generated-target-suffix'.
238 : type ? # Target's type.
239 : project
240 : action ?
241 )
242 {
243 virtual-target.__init__ $(name) : $(project) ;
244
245 self.type = $(type) ;
246 self.action = $(action) ;
247 if $(action)
248 {
249 $(action).add-targets $(__name__) ;
250
251 if $(self.type) && ! $(exact)
252 {
253 _adjust-name $(name) ;
254 }
255 }
256 }
257
258 rule type ( )
259 {
260 return $(self.type) ;
261 }
262
263 # Sets the path. When generating target name, it will override any path
264 # computation from properties.
265 #
266 rule set-path ( path )
267 {
268 self.path = [ path.native $(path) ] ;
269 }
270
271 # Returns the currently set action.
272 #
273 rule action ( )
274 {
275 return $(self.action) ;
276 }
277
278 # Sets/gets the 'root' flag. Target is root if it directly corresponds to
279 # some variant of a main target.
280 #
281 rule root ( set ? )
282 {
283 if $(set)
284 {
285 self.root = true ;
286 }
287 return $(self.root) ;
288 }
289
290 # Gets or sets the subvariant which created this target. Subvariant is set
291 # when target is brought into existance and is never changed after that. In
292 # particular, if a target is shared by multiple subvariants, only the first
293 # one is stored.
294 #
295 rule creating-subvariant ( s ? # If specified, specifies the value to set,
296 # which should be a 'subvariant' class
297 # instance.
298 )
299 {
300 if $(s) && ! $(self.creating-subvariant)
301 {
302 self.creating-subvariant = $(s) ;
303 }
304 return $(self.creating-subvariant) ;
305 }
306
307 rule actualize-action ( target )
308 {
309 if $(self.action)
310 {
311 $(self.action).actualize ;
312 }
313 }
314
315 # Return a human-readable representation of this target. If this target has
316 # an action, that is:
317 #
318 # { <action-name>-<self.name>.<self.type> <action-sources>... }
319 #
320 # otherwise, it is:
321 #
322 # { <self.name>.<self.type> }
323 #
324 rule str ( )
325 {
326 local action = [ action ] ;
327 local name-dot-type = [ sequence.join $(self.name) "." $(self.type) ] ;
328
329 if $(action)
330 {
331 local sources = [ $(action).sources ] ;
332 local action-name = [ $(action).action-name ] ;
333
334 local ss ;
335 for local s in $(sources)
336 {
337 ss += [ $(s).str ] ;
338 }
339
340 return "{" $(action-name)-$(name-dot-type) $(ss) "}" ;
341 }
342 else
343 {
344 return "{" $(name-dot-type) "}" ;
345 }
346 }
347
348 rule less ( a )
349 {
350 if [ str ] < [ $(a).str ]
351 {
352 return true ;
353 }
354 }
355
356 rule equal ( a )
357 {
358 if [ str ] = [ $(a).str ]
359 {
360 return true ;
361 }
362 }
363
364 # private:
365 rule actual-name ( )
366 {
367 if ! $(self.actual-name)
368 {
369 local grist = [ grist ] ;
370 local basename = [ path.native $(self.name) ] ;
371 self.actual-name = <$(grist)>$(basename) ;
372 }
373 return $(self.actual-name) ;
374 }
375
376 # Helper to 'actual-name', above. Computes a unique prefix used to
377 # distinguish this target from other targets with the same name creating
378 # different files.
379 #
380 rule grist ( )
381 {
382 # Depending on target, there may be different approaches to generating
383 # unique prefixes. We generate prefixes in the form:
384 # <one letter approach code> <the actual prefix>
385 local path = [ path ] ;
386 if $(path)
387 {
388 # The target will be generated to a known path. Just use the path
389 # for identification, since path is as unique as it can get.
390 return p$(path) ;
391 }
392 else
393 {
394 # File is either source, which will be searched for, or is not a
395 # file at all. Use the location of project for distinguishing.
396 local project-location = [ $(self.project).get location ] ;
397 local location-grist = [ sequence.join [ regex.split
398 $(project-location) "/" ] : "!" ] ;
399
400 if $(self.action)
401 {
402 local ps = [ $(self.action).properties ] ;
403 local property-grist = [ $(ps).as-path ] ;
404 # 'property-grist' can be empty when 'ps' is an empty property
405 # set.
406 if $(property-grist)
407 {
408 location-grist = $(location-grist)/$(property-grist) ;
409 }
410 }
411
412 return l$(location-grist) ;
413 }
414 }
415
416 # Given the target name specified in constructor, returns the name which
417 # should be really used, by looking at the <tag> properties. Tag properties
418 # need to be specified as <tag>@rule-name. This makes Boost Build call the
419 # specified rule with the target name, type and properties to get the new
420 # name. If no <tag> property is specified or the rule specified by <tag>
421 # returns nothing, returns the result of calling
422 # virtual-target.add-prefix-and-suffix.
423 #
424 rule _adjust-name ( specified-name )
425 {
426 local ps ;
427 if $(self.action)
428 {
429 ps = [ $(self.action).properties ] ;
430 }
431 else
432 {
433 ps = [ property-set.empty ] ;
434 }
435
436 # Add this target object for use in getting additional information
437 # when tagging.
438 ps = [ property-set.create [ $(ps).raw ] <target>$(__name__) ] ;
439
440 local tag = [ $(ps).get <tag> ] ;
441
442 if $(tag)
443 {
444 local rule-name = [ MATCH ^@(.*) : $(tag) ] ;
445 if $(rule-name)
446 {
447 if $(tag[2])
448 {
449 import errors : error : errors.error ;
450 errors.error <tag>@rulename is present but is not the only
451 <tag> feature. ;
452 }
453
454 self.name = [ indirect.call $(rule-name) $(specified-name)
455 : $(self.type) : $(ps) ] ;
456 }
457 else
458 {
459 import errors : error : errors.error ;
460 errors.error <tag> property value must be '@rule-name'. ;
461 }
462 }
463
464 # If there is no tag or the tag rule returned nothing.
465 if ! $(tag) || ! $(self.name)
466 {
467 self.name = [ virtual-target.add-prefix-and-suffix $(specified-name)
468 : $(self.type) : $(ps) ] ;
469 }
470 }
471
472 rule actualize-no-scanner ( )
473 {
474 local name = [ actual-name ] ;
475
476 # Do anything only on the first invocation.
477 if ! $(self.made-no-scanner)
478 {
479 self.made-no-scanner = true ;
480
481 if $(self.action)
482 {
483 # For non-derived target, we do not care if there are several
484 # virtual targets that refer to the same name. One case when
485 # this is unavoidable is when the file name is main.cpp and two
486 # targets have types CPP (for compiling) and MOCCABLE_CPP (for
487 # conversion to H via Qt tools).
488 virtual-target.register-actual-name $(name) : $(__name__) ;
489 }
490
491 for local i in $(self.dependencies)
492 {
493 DEPENDS $(name) : [ $(i).actualize ] ;
494 }
495
496 actualize-location $(name) ;
497 actualize-action $(name) ;
498 }
499 return $(name) ;
500 }
501 }
502
503
504 # Appends the suffix appropriate to 'type/property-set' combination to the
505 # specified name and returns the result.
506 #
507 rule add-prefix-and-suffix ( specified-name : type ? : property-set )
508 {
509 local suffix = [ type.generated-target-suffix $(type) : $(property-set) ] ;
510
511 # Handle suffixes for which no leading dot is desired. Those are specified
512 # by enclosing them in <...>. Needed by python so it can create "_d.so"
513 # extensions, for example.
514 if $(suffix:G)
515 {
516 suffix = [ utility.ungrist $(suffix) ] ;
517 }
518 else
519 {
520 suffix = .$(suffix) ;
521 }
522
523 local prefix = [ type.generated-target-prefix $(type) : $(property-set) ] ;
524
525 if [ MATCH ^($(prefix)) : $(specified-name) ]
526 {
527 prefix = ;
528 }
529 return $(prefix:E="")$(specified-name)$(suffix:E="") ;
530 }
531
532
533 # File targets with explicitly known location.
534 #
535 # The file path is determined as
536 # * Value passed to the 'set-path' method, if any.
537 # * For derived files, project's build dir, joined with components that
538 # describe action properties. If free properties are not equal to the
539 # project's reference properties an element with the name of the main
540 # target is added.
541 # * For source files, project's source dir.
542 #
543 # The file suffix is determined as:
544 # * The value passed to the 'suffix' method, if any.
545 # * The suffix corresponding to the target's type.
546 #
547 class file-target : abstract-file-target
548 {
549 import "class" : new ;
550 import common ;
551
552 rule __init__ (
553 name exact ?
554 : type ? # Optional type for this target.
555 : project
556 : action ?
557 : path ?
558 )
559 {
560 abstract-file-target.__init__ $(name) $(exact) : $(type) : $(project) :
561 $(action) ;
562
563 self.path = $(path) ;
564 }
565
566 rule clone-with-different-type ( new-type )
567 {
568 return [ new file-target $(self.name) exact : $(new-type) :
569 $(self.project) : $(self.action) : $(self.path) ] ;
570 }
571
572 rule actualize-location ( target )
573 {
574 # Scanner targets are always bound to already existing files in already
575 # existing folder. They need to be marked as depending on their base
576 # target (i.e. the target being scanned) but, unlike regular
577 # dependencies set up by the DEPENDS rule, they must not depend on any
578 # targets already marked as included by the base target. Otherwise such
579 # an included file being newer than the file being scanned would cause
580 # the scanner target to be updated, further causing any target depending
581 # on that scanner target to be rebuilt. This is the exact relationship
582 # as set up by Boost Jam's SEARCH binding method (needed to support
583 # searching for generated targets) so we want to bind scanner targets
584 # using this method instead of explicitly specifying their location
585 # using LOCATE.
586 #
587 # FIXME: We recognize scanner targets by their given name being
588 # different from this target's actual name. This is a hack and should be
589 # cleaned up by reorganizing who knows about scanners in the
590 # virtual-target/abstract-file-target/file-target/notfile-target/
591 # searched-lib-target/... class hierarchy.
592 local is-scanner-target ;
593 if $(target) != [ actual-name ]
594 {
595 is-scanner-target = true ;
596 }
597
598 if $(self.action) && ! $(is-scanner-target)
599 {
600 # This is a derived file.
601 local path = [ path ] ;
602 LOCATE on $(target) = $(path) ;
603
604 # Make sure the path exists.
605 DEPENDS $(target) : $(path) ;
606 common.MkDir $(path) ;
607
608 # It is possible that the target name includes a directory too, for
609 # example when installing headers. Create that directory.
610 if $(target:D)
611 {
612 local d = $(target:D) ;
613 d = $(d:R=$(path)) ;
614 DEPENDS $(target) : $(d) ;
615 common.MkDir $(d) ;
616 }
617
618 # For a real file target, we create a fake target depending on the
619 # real target. This allows us to run
620 #
621 # b2 hello.o
622 #
623 # without trying to guess the name of the real target. Note that the
624 # target has no directory name and uses a special <e> grist.
625 #
626 # First, that means that "b2 hello.o" will build all known hello.o
627 # targets. Second, the <e> grist makes sure this target will not be
628 # confused with other targets, for example, if we have subdir 'test'
629 # with target 'test' in it that includes a 'test.o' file, then the
630 # target for directory will be just 'test' the target for test.o
631 # will be <ptest/bin/gcc/debug>test.o and the target we create below
632 # will be <e>test.o
633 DEPENDS $(target:G=e) : $(target) ;
634 # Allow b2 <path-to-file>/<file> to work. This will not catch all
635 # possible ways to refer to the path (relative/absolute, extra ".",
636 # various "..", but should help in obvious cases.
637 DEPENDS $(target:G=e:R=$(path)) : $(target) ;
638 }
639 else
640 {
641 SEARCH on $(target) = [ path.native $(self.path) ] ;
642 }
643 }
644
645 # Returns the directory for this target.
646 #
647 rule path ( )
648 {
649 if ! $(self.path)
650 {
651 if $(self.action)
652 {
653 local p = [ $(self.action).properties ] ;
654 local path,relative-to-build-dir = [ $(p).target-path ] ;
655 local path = $(path,relative-to-build-dir[1]) ;
656 local relative-to-build-dir = $(path,relative-to-build-dir[2]) ;
657
658 if $(relative-to-build-dir)
659 {
660 path = [ path.join [ $(self.project).build-dir ] $(path) ] ;
661 }
662
663 self.path = [ path.native $(path) ] ;
664 }
665 }
666 return $(self.path) ;
667 }
668 }
669
670
671 class notfile-target : abstract-file-target
672 {
673 rule __init__ ( name : project : action ? )
674 {
675 abstract-file-target.__init__ $(name) : : $(project) : $(action) ;
676 }
677
678 # Returns nothing to indicate that the target's path is not known.
679 #
680 rule path ( )
681 {
682 return ;
683 }
684
685 rule actualize-location ( target )
686 {
687 NOTFILE $(target) ;
688 ALWAYS $(target) ;
689 # TEMPORARY $(target) ;
690 NOUPDATE $(target) ;
691 }
692 }
693
694
695 # Class representing an action. Both 'targets' and 'sources' should list
696 # instances of 'virtual-target'. Action name should name a rule with this
697 # prototype:
698 # rule action-name ( targets + : sources * : properties * )
699 # Targets and sources are passed as actual Jam targets. The rule may not
700 # establish additional dependency relationships.
701 #
702 class action
703 {
704 import "class" ;
705 import indirect ;
706 import path ;
707 import property-set ;
708 import set : difference ;
709 import toolset ;
710 import type ;
711
712 rule __init__ ( sources * : action-name + : property-set ? )
713 {
714 self.sources = $(sources) ;
715
716 self.action-name = [ indirect.make-qualified $(action-name) ] ;
717
718 if ! $(property-set)
719 {
720 property-set = [ property-set.empty ] ;
721 }
722
723 if ! [ class.is-instance $(property-set) ]
724 {
725 import errors : error : errors.error ;
726 errors.error "Property set instance required" ;
727 }
728
729 self.properties = $(property-set) ;
730 }
731
732 rule add-targets ( targets * )
733 {
734 self.targets += $(targets) ;
735 }
736
737 rule replace-targets ( old-targets * : new-targets * )
738 {
739 self.targets = [ set.difference $(self.targets) : $(old-targets) ] ;
740 self.targets += $(new-targets) ;
741 }
742
743 rule targets ( )
744 {
745 return $(self.targets) ;
746 }
747
748 rule sources ( )
749 {
750 return $(self.sources) ;
751 }
752
753 rule action-name ( )
754 {
755 return $(self.action-name) ;
756 }
757
758 rule properties ( )
759 {
760 return $(self.properties) ;
761 }
762
763 # Generates actual build instructions.
764 #
765 rule actualize ( )
766 {
767 if ! $(self.actualized)
768 {
769 self.actualized = true ;
770
771 local ps = [ properties ] ;
772 local properties = [ adjust-properties $(ps) ] ;
773
774 local actual-targets ;
775 for local i in [ targets ]
776 {
777 actual-targets += [ $(i).actualize ] ;
778 }
779
780 actualize-sources [ sources ] : $(properties) ;
781
782 DEPENDS $(actual-targets) : $(self.actual-sources)
783 $(self.dependency-only-sources) ;
784
785 # Action name can include additional rule arguments, which should
786 # not be passed to 'set-target-variables'.
787 toolset.set-target-variables
788 [ indirect.get-rule $(self.action-name[1]) ] $(actual-targets)
789 : $(properties) ;
790
791 # Reflect ourselves in a variable for the target. This allows
792 # looking up additional info for the action given the raw target.
793 # For example to debug or output action information from action
794 # rules.
795 .action on $(actual-targets) = $(__name__) ;
796
797 #indirect.call $(self.action-name) $(actual-targets)
798 # : $(self.actual-sources) : [ $(properties).raw ] ;
799 execute $(self.action-name) $(actual-targets)
800 : $(self.actual-sources) : [ $(properties).raw ] ;
801
802 # Since we set up the creating action here, we set up the action for
803 # cleaning up as well.
804 common.Clean clean-all : $(actual-targets) ;
805 }
806 }
807
808 # Helper for 'actualize-sources'. For each passed source, actualizes it with
809 # the appropriate scanner. Returns the actualized virtual targets.
810 #
811 rule actualize-source-type ( sources * : property-set )
812 {
813 local result = ;
814 for local i in $(sources)
815 {
816 local scanner ;
817 if [ $(i).type ]
818 {
819 scanner = [ type.get-scanner [ $(i).type ] : $(property-set) ] ;
820 }
821 result += [ $(i).actualize $(scanner) ] ;
822 }
823 return $(result) ;
824 }
825
826 # Creates actual Jam targets for sources. Initializes the following member
827 # variables:
828 # 'self.actual-sources' -- sources passed to the updating action.
829 # 'self.dependency-only-sources' -- sources marked as dependencies, but
830 # are not used otherwise.
831 #
832 # New values will be *appended* to the variables. They may be non-empty if
833 # caller wants it.
834 #
835 rule actualize-sources ( sources * : property-set )
836 {
837 local dependencies = [ $(self.properties).get <dependency> ] ;
838
839 self.dependency-only-sources +=
840 [ actualize-source-type $(dependencies) : $(property-set) ] ;
841 self.actual-sources +=
842 [ actualize-source-type $(sources) : $(property-set) ] ;
843
844 # This is used to help b2 find dependencies in generated headers and
845 # other main targets, e.g. in:
846 #
847 # make a.h : ....... ;
848 # exe hello : hello.cpp : <implicit-dependency>a.h ;
849 #
850 # For b2 to find the dependency the generated target must be
851 # actualized (i.e. have its Jam target constructed). In the above case,
852 # if we are building just hello ("b2 hello"), 'a.h' will not be
853 # actualized unless we do it here.
854 local implicit = [ $(self.properties).get <implicit-dependency> ] ;
855 for local i in $(implicit)
856 {
857 $(i:G=).actualize ;
858 }
859 }
860
861 # Determines real properties when trying to build with 'properties'. This is
862 # the last chance to fix properties, for example to adjust includes to get
863 # generated headers correctly. Default implementation simply returns its
864 # argument.
865 #
866 rule adjust-properties ( property-set )
867 {
868 return $(property-set) ;
869 }
870
871 # Execute the action rule on the given targets, sources, and properties.
872 # Since this does the final call to the engine action rule this takes
873 # engine level targets and raw properties. One could override this, for
874 # example, to set additional variables on hte target that might be
875 # difficult to determine just using toolset flags.
876 # Note, you must call this base rule when overriding as otherwise the
877 # actions will not execute and the engine will not run commands.
878 #
879 rule execute ( action-name targets + : sources * : properties * )
880 {
881 indirect.call $(action-name) $(targets) : $(sources) : $(properties) ;
882 }
883 }
884
885
886 # Action class which does nothing --- it produces the targets with specific
887 # properties out of nowhere. It is needed to distinguish virtual targets with
888 # different properties that are known to exist and have no actions which create
889 # them.
890 #
891 class null-action : action
892 {
893 rule __init__ ( property-set ? )
894 {
895 action.__init__ : .no-action : $(property-set) ;
896 }
897
898 rule actualize ( )
899 {
900 if ! $(self.actualized)
901 {
902 self.actualized = true ;
903 for local i in [ targets ]
904 {
905 $(i).actualize ;
906 }
907 }
908 }
909 }
910
911
912 # Class which acts exactly like 'action', except that its sources are not
913 # scanned for dependencies.
914 #
915 class non-scanning-action : action
916 {
917 rule __init__ ( sources * : action-name + : property-set ? )
918 {
919 action.__init__ $(sources) : $(action-name) : $(property-set) ;
920 }
921
922 rule actualize-source-type ( sources * : property-set )
923 {
924 local result ;
925 for local i in $(sources)
926 {
927 result += [ $(i).actualize ] ;
928 }
929 return $(result) ;
930 }
931 }
932
933
934 # Creates a virtual target with an appropriate name and type from 'file'. If a
935 # target with that name in that project already exists, returns that already
936 # created target.
937 #
938 # FIXME: a more correct way would be to compute the path to the file, based on
939 # name and source location for the project, and use that path to determine if
940 # the target has already been created. This logic should be shared with how we
941 # usually find targets identified by a specific target id. It should also be
942 # updated to work correctly when the file is specified using both relative and
943 # absolute paths.
944 #
945 # TODO: passing a project with all virtual targets is starting to be annoying.
946 #
947 rule from-file ( file : file-loc : project )
948 {
949 import type ; # Had to do this here to break a circular dependency.
950
951 # Check whether we already created a target corresponding to this file.
952 local path = [ path.root [ path.root $(file) $(file-loc) ] [ path.pwd ] ] ;
953
954 if $(.files.$(path))
955 {
956 return $(.files.$(path)) ;
957 }
958 else
959 {
960 local name = [ path.make $(file) ] ;
961 local type = [ type.type $(file) ] ;
962 local result ;
963
964 result = [ new file-target $(file) : $(type) : $(project) : :
965 $(file-loc) ] ;
966
967 .files.$(path) = $(result) ;
968 return $(result) ;
969 }
970 }
971
972
973 # Registers a new virtual target. Checks if there is already a registered target
974 # with the same name, type, project and subvariant properties as well as the
975 # same sources and equal action. If such target is found it is returned and a
976 # new 'target' is not registered. Otherwise, 'target' is registered and
977 # returned.
978 #
979 rule register ( target )
980 {
981 local signature = [ sequence.join [ $(target).path ] [ $(target).name ] : -
982 ] ;
983
984 local result ;
985 for local t in $(.cache.$(signature))
986 {
987 local a1 = [ $(t).action ] ;
988 local a2 = [ $(target).action ] ;
989
990 if ! $(result)
991 {
992 if ! $(a1) && ! $(a2)
993 {
994 result = $(t) ;
995 }
996 else if $(a1) && $(a2) &&
997 ( [ $(a1).action-name ] = [ $(a2).action-name ] ) &&
998 ( [ $(a1).sources ] = [ $(a2).sources ] )
999 {
1000 local ps1 = [ $(a1).properties ] ;
1001 local ps2 = [ $(a2).properties ] ;
1002 local p1 = [ $(ps1).base ] [ $(ps1).free ] [ set.difference
1003 [ $(ps1).dependency ] : [ $(ps1).incidental ] ] ;
1004 local p2 = [ $(ps2).base ] [ $(ps2).free ] [ set.difference
1005 [ $(ps2).dependency ] : [ $(ps2).incidental ] ] ;
1006 if $(p1) = $(p2)
1007 {
1008 result = $(t) ;
1009 }
1010 }
1011 }
1012 }
1013
1014 if ! $(result)
1015 {
1016 .cache.$(signature) += $(target) ;
1017 result = $(target) ;
1018 }
1019
1020 .recent-targets += $(result) ;
1021 .all-targets += $(result) ;
1022
1023 return $(result) ;
1024 }
1025
1026
1027 # Each target returned by 'register' is added to the .recent-targets list,
1028 # returned by this function. This allows us to find all virtual targets created
1029 # when building a specific main target, even those constructed only as
1030 # intermediate targets.
1031 #
1032 rule recent-targets ( )
1033 {
1034 return $(.recent-targets) ;
1035 }
1036
1037
1038 rule clear-recent-targets ( )
1039 {
1040 .recent-targets = ;
1041 }
1042
1043
1044 # Returns all virtual targets ever created.
1045 #
1046 rule all-targets ( )
1047 {
1048 return $(.all-targets) ;
1049 }
1050
1051
1052 # Returns all targets from 'targets' with types equal to 'type' or derived from
1053 # it.
1054 #
1055 rule select-by-type ( type : targets * )
1056 {
1057 local result ;
1058 for local t in $(targets)
1059 {
1060 if [ type.is-subtype [ $(t).type ] $(type) ]
1061 {
1062 result += $(t) ;
1063 }
1064 }
1065 return $(result) ;
1066 }
1067
1068
1069 rule register-actual-name ( actual-name : virtual-target )
1070 {
1071 if $(.actual.$(actual-name))
1072 {
1073 local cs1 = [ $(.actual.$(actual-name)).creating-subvariant ] ;
1074 local cmt1-name ;
1075 if $(cs1)-is-defined
1076 {
1077 local cmt1 = [ $(cs1).main-target ] ;
1078 cmt1-name = [ $(cmt1).full-name ] ;
1079 }
1080 local cs2 = [ $(virtual-target).creating-subvariant ] ;
1081 local cmt2-name ;
1082 if $(cs2)-is-defined
1083 {
1084 local cmt2 = [ $(cs2).main-target ] ;
1085 cmt2-name = [ $(cmt2).full-name ] ;
1086 }
1087 local extra-error-information ;
1088 if ! $(cs1)-is-defined || ! $(cs2)-is-defined
1089 {
1090 extra-error-information = Encountered a virtual-target without a
1091 creating subvariant. It could be the virtual target has not been
1092 registered via the virtual-target.register rule. ;
1093 }
1094
1095 local action1 = [ $(.actual.$(actual-name)).action ] ;
1096 local action2 = [ $(virtual-target).action ] ;
1097 local properties-added ;
1098 local properties-removed ;
1099 if $(action1) && $(action2)
1100 {
1101 local p1 = [ $(action1).properties ] ;
1102 p1 = [ $(p1).raw ] ;
1103 local p2 = [ $(action2).properties ] ;
1104 p2 = [ $(p2).raw ] ;
1105 properties-removed = [ set.difference $(p1) : $(p2) ] ;
1106 properties-removed ?= "none" ;
1107 properties-added = [ set.difference $(p2) : $(p1) ] ;
1108 properties-added ?= "none" ;
1109 }
1110 import errors : user-error : errors.user-error ;
1111 errors.user-error "Name clash for '$(actual-name)'"
1112 : ""
1113 : "Tried to build the target twice, with property sets having "
1114 : "these incompatible properties:"
1115 : ""
1116 : " - " $(properties-removed)
1117 : " - " $(properties-added)
1118 : ""
1119 : "Please make sure to have consistent requirements for these "
1120 : "properties everywhere in your project, especially for install"
1121 : "targets."
1122 ;
1123 }
1124 else
1125 {
1126 .actual.$(actual-name) = $(virtual-target) ;
1127 }
1128 }
1129
1130
1131 # Traverses the dependency graph of 'target' and return all targets that will be
1132 # created before this one is created. If the root of some dependency graph is
1133 # found during traversal, it is either included or not, depending on the
1134 # 'include-roots' value. In either case traversal stops at root targets, i.e.
1135 # root target sources are not traversed.
1136 #
1137 rule traverse ( target : include-roots ? : include-sources ? )
1138 {
1139 local result ;
1140 if [ $(target).action ]
1141 {
1142 local action = [ $(target).action ] ;
1143 # This includes the 'target' as well.
1144 result += [ $(action).targets ] ;
1145
1146 for local t in [ $(action).sources ]
1147 {
1148 if ! [ $(t).root ]
1149 {
1150 result += [ traverse $(t) : $(include-roots) :
1151 $(include-sources) ] ;
1152 }
1153 else if $(include-roots)
1154 {
1155 result += $(t) ;
1156 }
1157 }
1158 }
1159 else if $(include-sources)
1160 {
1161 result = $(target) ;
1162 }
1163 return $(result) ;
1164 }
1165
1166
1167 # Takes an 'action' instance and creates a new instance of it and all targets
1168 # produced by the action. The rule-name and properties are set to
1169 # 'new-rule-name' and 'new-properties', if those are specified. Returns the
1170 # cloned action.
1171 #
1172 rule clone-action ( action : new-project : new-action-name ? : new-properties ?
1173 )
1174 {
1175 if ! $(new-action-name)
1176 {
1177 new-action-name = [ $(action).action-name ] ;
1178 }
1179 if ! $(new-properties)
1180 {
1181 new-properties = [ $(action).properties ] ;
1182 }
1183
1184 local action-class = [ modules.peek $(action) : __class__ ] ;
1185 local cloned-action = [ class.new $(action-class)
1186 [ $(action).sources ] : $(new-action-name) : $(new-properties) ] ;
1187
1188 local cloned-targets ;
1189 for local target in [ $(action).targets ]
1190 {
1191 local n = [ $(target).name ] ;
1192 # Do not modify produced target names.
1193 local cloned-target = [ class.new file-target $(n) exact :
1194 [ $(target).type ] : $(new-project) : $(cloned-action) ] ;
1195 local d = [ $(target).dependencies ] ;
1196 if $(d)
1197 {
1198 $(cloned-target).depends $(d) ;
1199 }
1200 $(cloned-target).root [ $(target).root ] ;
1201 $(cloned-target).creating-subvariant [ $(target).creating-subvariant ] ;
1202
1203 cloned-targets += $(cloned-target) ;
1204 }
1205
1206 return $(cloned-action) ;
1207 }
1208
1209
1210 class subvariant
1211 {
1212 import sequence ;
1213 import type ;
1214
1215 rule __init__ ( main-target # The instance of main-target class.
1216 : property-set # Properties requested for this target.
1217 : sources *
1218 : build-properties # Actually used properties.
1219 : sources-usage-requirements # Properties propagated from sources.
1220 : created-targets * ) # Top-level created targets.
1221 {
1222 self.main-target = $(main-target) ;
1223 self.properties = $(property-set) ;
1224 self.sources = $(sources) ;
1225 self.build-properties = $(build-properties) ;
1226 self.sources-usage-requirements = $(sources-usage-requirements) ;
1227 self.created-targets = $(created-targets) ;
1228
1229 # Pre-compose a list of other dependency graphs this one depends on.
1230 local deps = [ $(build-properties).get <implicit-dependency> ] ;
1231 for local d in $(deps)
1232 {
1233 self.other-dg += [ $(d:G=).creating-subvariant ] ;
1234 }
1235
1236 self.other-dg = [ sequence.unique $(self.other-dg) ] ;
1237 }
1238
1239 rule main-target ( )
1240 {
1241 return $(self.main-target) ;
1242 }
1243
1244 rule created-targets ( )
1245 {
1246 return $(self.created-targets) ;
1247 }
1248
1249 rule requested-properties ( )
1250 {
1251 return $(self.properties) ;
1252 }
1253
1254 rule build-properties ( )
1255 {
1256 return $(self.build-properties) ;
1257 }
1258
1259 rule sources-usage-requirements ( )
1260 {
1261 return $(self.sources-usage-requirements) ;
1262 }
1263
1264 rule set-usage-requirements ( usage-requirements )
1265 {
1266 self.usage-requirements = $(usage-requirements) ;
1267 }
1268
1269 rule usage-requirements ( )
1270 {
1271 return $(self.usage-requirements) ;
1272 }
1273
1274 # Returns all targets referenced by this subvariant, either directly or
1275 # indirectly, and either as sources, or as dependency properties. Targets
1276 # referred to using the dependency property are returned as properties, not
1277 # targets.
1278 #
1279 rule all-referenced-targets ( theset )
1280 {
1281 # Find directly referenced targets.
1282 local deps = [ $(self.build-properties).dependency ] ;
1283 local all-targets = $(self.sources) $(deps) ;
1284
1285 # Find other subvariants.
1286 local r ;
1287 for local t in $(all-targets)
1288 {
1289 if ! [ $(theset).contains $(t) ]
1290 {
1291 $(theset).add $(t) ;
1292 r += [ $(t:G=).creating-subvariant ] ;
1293 }
1294 }
1295 r = [ sequence.unique $(r) ] ;
1296 for local s in $(r)
1297 {
1298 if $(s) != $(__name__)
1299 {
1300 $(s).all-referenced-targets $(theset) ;
1301 }
1302 }
1303 }
1304
1305 # Returns the properties specifying implicit include paths to generated
1306 # headers. This traverses all targets in this subvariant and subvariants
1307 # referred by <implicit-dependency> properties. For all targets of type
1308 # 'target-type' (or for all targets, if 'target-type' is not specified), the
1309 # result will contain <$(feature)>path-to-that-target.
1310 #
1311 rule implicit-includes ( feature : target-type ? )
1312 {
1313 local key = ii$(feature)-$(target-type:E="") ;
1314 if ! $($(key))-is-not-empty
1315 {
1316 local target-paths = [ all-target-directories $(target-type) ] ;
1317 target-paths = [ sequence.unique $(target-paths) ] ;
1318 local result = $(target-paths:G=$(feature)) ;
1319 if ! $(result)
1320 {
1321 result = "" ;
1322 }
1323 $(key) = $(result) ;
1324 }
1325 if $($(key)) = ""
1326 {
1327 return ;
1328 }
1329 else
1330 {
1331 return $($(key)) ;
1332 }
1333 }
1334
1335 rule all-target-directories ( target-type ? )
1336 {
1337 if ! $(self.target-directories)
1338 {
1339 compute-target-directories $(target-type) ;
1340 }
1341 return $(self.target-directories) ;
1342 }
1343
1344 rule compute-target-directories ( target-type ? )
1345 {
1346 local result ;
1347 for local t in $(self.created-targets)
1348 {
1349 # Skip targets of the wrong type.
1350 local type = [ $(t).type ] ;
1351 if ! $(target-type) ||
1352 ( $(type) && [ type.is-derived $(type) $(target-type) ] )
1353 {
1354 result = [ sequence.merge $(result) : [ $(t).path ] ] ;
1355 }
1356 }
1357 for local d in $(self.other-dg)
1358 {
1359 result += [ $(d).all-target-directories $(target-type) ] ;
1360 }
1361 self.target-directories = $(result) ;
1362 }
1363 }