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