]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/src/build/targets.jam
update sources to v12.2.3
[ceph.git] / ceph / src / boost / tools / build / src / build / targets.jam
1 # Copyright Vladimir Prus 2002.
2 # Copyright Rene Rivera 2006.
3 # Distributed under the Boost Software License, Version 1.0.
4 # (See accompanying file LICENSE_1_0.txt or copy at
5 # http://www.boost.org/LICENSE_1_0.txt)
6
7 # Supports 'abstract' targets, which are targets explicitly defined in a
8 # Jamfile.
9 #
10 # Abstract targets are represented by classes derived from 'abstract-target'
11 # class. The first abstract target is 'project-target', which is created for
12 # each Jamfile, and can be obtained by the 'target' rule in the Jamfile's module
13 # (see project.jam).
14 #
15 # Project targets keep a list of 'main-target' instances. A main target is what
16 # the user explicitly defines in a Jamfile. It is possible to have several
17 # definitions for a main target, for example to have different lists of sources
18 # for different platforms. So, main targets keep a list of alternatives.
19 #
20 # Each alternative is an instance of 'abstract-target'. When a main target
21 # subvariant is defined by some rule, that rule will decide what class to use,
22 # create an instance of that class and add it to the list of alternatives for
23 # the main target.
24 #
25 # Rules supplied by the build system will use only targets derived from the
26 # 'basic-target' class, which will provide some default behaviour. There will be
27 # different classes derived from it such as 'make-target', created by the 'make'
28 # rule, and 'typed-target', created by rules such as 'exe' and 'lib'.
29 #
30 # +--------------------------+
31 # | abstract-target |
32 # +==========================+
33 # | name |
34 # | project |
35 # | |
36 # | generate(properties) = 0 |
37 # +-------------+------------+
38 # |
39 # ^
40 # / \
41 # +-+-+
42 # |
43 # |
44 # +------------------+-----+-------------------------------+
45 # | | |
46 # | | |
47 # +-----------+----------+ +------+------+ +-------+------+
48 # | project-target | | main-target | | basic-target |
49 # +======================+ 1 * +=============+ alternatives +==============+
50 # | generate(properties) |o-----+ generate |<>------------->| generate |
51 # | main-target | +-------------+ | construct = 0|
52 # +----------------------+ +-------+------+
53 # |
54 # ^
55 # / \
56 # +-+-+
57 # |
58 # |
59 # ...--+-----------------+-----------------+------------------+
60 # | | | |
61 # | | | |
62 # ... ---+-----+ +-------+------+ +------+------+ +-------+------+
63 # | | typed-target | | make-target | | stage-target |
64 # . +==============+ +=============+ +==============+
65 # . | construct | | construct | | construct |
66 # +--------------+ +-------------+ +--------------+
67
68 import assert ;
69 import build-request ;
70 import "class" : new ;
71 import feature ;
72 import indirect ;
73 import path ;
74 import property ;
75 import property-set ;
76 import sequence ;
77 import set ;
78 import toolset ;
79
80
81 # Base class for all abstract targets.
82 #
83 class abstract-target
84 {
85 import assert ;
86 import "class" ;
87 import errors ;
88 import project ;
89
90 rule __init__ ( name # Name of the target in Jamfile.
91 : project-target # The project target to which this one belongs.
92 )
93 {
94 # Note: it might seem that we don't need either name or project at all.
95 # However, there are places where we really need it. One example is
96 # error messages which should name problematic targets. Another is
97 # setting correct paths for sources and generated files.
98
99 self.name = $(name) ;
100 self.project = $(project-target) ;
101 self.location = [ errors.nearest-user-location ] ;
102 }
103
104 # Returns the name of this target.
105 rule name ( )
106 {
107 return $(self.name) ;
108 }
109
110 # Returns the project for this target.
111 rule project ( )
112 {
113 return $(self.project) ;
114 }
115
116 # Return the location where the target was declared.
117 rule location ( )
118 {
119 return $(self.location) ;
120 }
121
122 # Returns a user-readable name for this target.
123 rule full-name ( )
124 {
125 local location = [ $(self.project).get location ] ;
126 return $(location)/$(self.name) ;
127 }
128
129 # Generates virtual targets for this abstract target using the specified
130 # properties, unless a different value of some feature is required by the
131 # target.
132 # On success, returns:
133 # - a property-set with the usage requirements to be applied to dependants
134 # - a list of produced virtual targets, which may be empty.
135 # If 'property-set' is empty, performs the default build of this target, in
136 # a way specific to the derived class.
137 #
138 rule generate ( property-set )
139 {
140 errors.error "method should be defined in derived classes" ;
141 }
142
143 rule rename ( new-name )
144 {
145 self.name = $(new-name) ;
146 }
147 }
148
149
150 if --debug-building in [ modules.peek : ARGV ]
151 {
152 modules.poke : .debug-building : true ;
153 }
154
155
156 rule indent ( )
157 {
158 return $(.indent:J="") ;
159 }
160
161
162 rule increase-indent ( )
163 {
164 .indent += " " ;
165 }
166
167
168 rule decrease-indent ( )
169 {
170 .indent = $(.indent[2-]) ;
171 }
172
173
174 # Project target class (derived from 'abstract-target').
175 #
176 # This class has the following responsibilities:
177 # - Maintaining a list of main targets in this project and building them.
178 #
179 # Main targets are constructed in two stages:
180 # - When Jamfile is read, a number of calls to 'add-alternative' is made. At
181 # that time, alternatives can also be renamed to account for inline targets.
182 # - The first time 'main-target' or 'has-main-target' rule is called, all
183 # alternatives are enumerated and main targets are created.
184 #
185 class project-target : abstract-target
186 {
187 import project ;
188 import targets ;
189 import path ;
190 import print ;
191 import property-set ;
192 import set ;
193 import sequence ;
194 import "class" : new ;
195
196 rule __init__ ( name : project-module parent-project ?
197 : requirements * : default-build * )
198 {
199 abstract-target.__init__ $(name) : $(__name__) ;
200
201 self.project-module = $(project-module) ;
202 self.location = [ project.attribute $(project-module) location ] ;
203 self.requirements = $(requirements) ;
204 self.default-build = $(default-build) ;
205
206 if $(parent-project)
207 {
208 inherit $(parent-project) ;
209 }
210 }
211
212 # This is needed only by the 'make' rule. Need to find a way to make 'make'
213 # work without this method.
214 #
215 rule project-module ( )
216 {
217 return $(self.project-module) ;
218 }
219
220 rule get ( attribute )
221 {
222 return [ project.attribute $(self.project-module) $(attribute) ] ;
223 }
224
225 rule build-dir ( )
226 {
227 if ! $(self.build-dir)
228 {
229 self.build-dir = [ get build-dir ] ;
230 if ! $(self.build-dir)
231 {
232 local location = [ $(self.project).get location ] ;
233 if $(location)
234 {
235 self.build-dir = [ path.join $(location) bin ] ;
236 }
237 else
238 {
239 local id = [ get id ] ;
240 if $(id)
241 {
242 local rid = [ MATCH ^/(.*) : $(id) ] ;
243 self.build-dir = [ path.join [ project.standalone-build-dir ] $(rid) ] ;
244 }
245 else
246 {
247 errors.error "Could not create build-dir for standalone project $(self.project-module:E=)."
248 : "Missing project id" ;
249 }
250 }
251 }
252 }
253 return $(self.build-dir) ;
254 }
255
256 # Generates all possible targets contained in this project.
257 #
258 rule generate ( property-set * )
259 {
260 if [ modules.peek : .debug-building ]
261 {
262 ECHO [ targets.indent ] "building project" [ name ]
263 " ('$(__name__)') with" [ $(property-set).raw ] ;
264 targets.increase-indent ;
265 }
266
267 local usage-requirements = [ property-set.empty ] ;
268 local targets ;
269
270 for local t in [ targets-to-build ]
271 {
272 local g = [ $(t).generate $(property-set) ] ;
273 usage-requirements = [ $(usage-requirements).add $(g[1]) ] ;
274 targets += $(g[2-]) ;
275 }
276 targets.decrease-indent ;
277 return $(usage-requirements) [ sequence.unique $(targets) ] ;
278 }
279
280 # Computes and returns a list of abstract-target instances which must be
281 # built when this project is built.
282 #
283 rule targets-to-build ( )
284 {
285 local result ;
286
287 if ! $(self.built-main-targets)
288 {
289 build-main-targets ;
290 }
291
292 # Collect all main targets here, except for "explicit" ones.
293 for local t in $(self.main-targets)
294 {
295 if ! [ $(t).name ] in $(self.explicit-targets)
296 {
297 result += $(t) ;
298 }
299 }
300
301 # Collect all projects referenced via "projects-to-build" attribute.
302 local self-location = [ get location ] ;
303 for local pn in [ get projects-to-build ]
304 {
305 result += [ find $(pn)/ ] ;
306 }
307
308 return $(result) ;
309 }
310
311 # Add 'target' to the list of targets in this project that should be build
312 # only by explicit request
313 #
314 rule mark-target-as-explicit ( target-name * )
315 {
316 # Record the name of the target, not instance, since this rule is called
317 # before main target instances are created.
318 self.explicit-targets += $(target-name) ;
319 }
320
321 rule mark-target-as-always ( target-name * )
322 {
323 # Record the name of the target, not instance, since this rule is called
324 # before main target instances are created.
325 self.always-targets += $(target-name) ;
326 }
327
328 # Add new target alternative
329 #
330 rule add-alternative ( target-instance )
331 {
332 if $(self.built-main-targets)
333 {
334 import errors : error : errors.error ;
335 errors.error add-alternative called when main targets are already
336 created. : in project [ full-name ] ;
337 }
338 self.alternatives += $(target-instance) ;
339 if ! ( [ $(target-instance).name ] in $(self.alternative-names) )
340 {
341 self.alternative-names += [ $(target-instance).name ] ;
342 }
343 }
344
345 # Checks if an alternative was declared for the target.
346 # Unlike checking for a main target this does not require
347 # building the main targets. And hence can be used in/directly
348 # while loading a project.
349 #
350 rule has-alternative-for-target ( target-name )
351 {
352 if $(target-name) in $(self.alternative-names)
353 {
354 return 1 ;
355 }
356 }
357
358 # Returns a 'main-target' class instance corresponding to 'name'.
359 #
360 rule main-target ( name )
361 {
362 if ! $(self.built-main-targets)
363 {
364 build-main-targets ;
365 }
366 return $(self.main-target.$(name)) ;
367 }
368
369 # Returns whether a main target with the specified name exists.
370 #
371 rule has-main-target ( name )
372 {
373 if ! $(self.built-main-targets)
374 {
375 build-main-targets ;
376 }
377
378 if $(self.main-target.$(name))
379 {
380 return true ;
381 }
382 }
383
384 # Worker function for the find rule not implementing any caching and simply
385 # returning nothing in case the target can not be found.
386 #
387 rule find-really ( id )
388 {
389 local result ;
390 local current-location = [ get location ] ;
391
392 local split = [ MATCH ^(.*)//(.*)$ : $(id) ] ;
393 local project-part = $(split[1]) ;
394 local target-part = $(split[2]) ;
395
396 local extra-error-message ;
397 if $(project-part)
398 {
399 # There is an explicitly specified project part in id. Looks up the
400 # project and passes the request to it.
401 local pm = [ project.find $(project-part) : $(current-location) ] ;
402 if $(pm)
403 {
404 project-target = [ project.target $(pm) ] ;
405 result = [ $(project-target).find $(target-part) : no-error ] ;
406 }
407 else
408 {
409 extra-error-message = could not resolve project reference
410 '$(project-part)' ;
411 if ! [ path.is-rooted $(project-part) ]
412 {
413 local rooted = [ path.root $(project-part) / ] ;
414 if $(rooted) && [ project.is-registered-id $(rooted) ]
415 {
416 extra-error-message += - possibly missing a leading
417 slash ('/') character. ;
418 }
419 }
420 }
421 }
422 else
423 {
424 # Interpret target-name as name of main target. Need to do this
425 # before checking for file. Consider the following scenario with a
426 # toolset not modifying its executable's names, e.g. gcc on
427 # Unix-like platforms:
428 #
429 # exe test : test.cpp ;
430 # install s : test : <location>. ;
431 #
432 # After the first build we would have a target named 'test' in the
433 # Jamfile and a file named 'test' on the disk. We need the target to
434 # override the file.
435 result = [ main-target $(id) ] ;
436
437 # Interpret id as an existing file reference.
438 if ! $(result)
439 {
440 result = [ new file-reference [ path.make $(id) ] :
441 $(self.project) ] ;
442 if ! [ $(result).exists ]
443 {
444 result = ;
445 }
446 }
447
448 # Interpret id as project-id.
449 if ! $(result)
450 {
451 local project-module = [ project.find $(id) :
452 $(current-location) ] ;
453 if $(project-module)
454 {
455 result = [ project.target $(project-module) ] ;
456 }
457 }
458 }
459
460 return $(result:E="") $(extra-error-message) ;
461 }
462
463 # Find and return the target with the specified id, treated relative to
464 # self. Id may specify either a target or a file name with the target taking
465 # priority. May report an error or return nothing if the target is not found
466 # depending on the 'no-error' parameter.
467 #
468 rule find ( id : no-error ? )
469 {
470 local v = $(.id.$(id)) ;
471 local extra-error-message ;
472 if ! $(v)
473 {
474 local r = [ find-really $(id) ] ;
475 v = $(r[1]) ;
476 extra-error-message = $(r[2-]) ;
477 if ! $(v)
478 {
479 v = none ;
480 }
481 .id.$(id) = $(v) ;
482 }
483
484 if $(v) != none
485 {
486 return $(v) ;
487 }
488 else if ! $(no-error)
489 {
490 local current-location = [ get location ] ;
491 import errors : user-error : errors.user-error ;
492 errors.user-error Unable to find file or target named
493 : " " '$(id)'
494 : referred to from project at
495 : " " '$(current-location)'
496 : $(extra-error-message) ;
497 }
498 }
499
500 rule build-main-targets ( )
501 {
502 self.built-main-targets = true ;
503 for local a in $(self.alternatives)
504 {
505 local name = [ $(a).name ] ;
506 local target = $(self.main-target.$(name)) ;
507 if ! $(target)
508 {
509 local t = [ new main-target $(name) : $(self.project) ] ;
510 self.main-target.$(name) = $(t) ;
511 self.main-targets += $(t) ;
512 target = $(self.main-target.$(name)) ;
513 }
514
515 if $(name) in $(self.always-targets)
516 {
517 $(a).always ;
518 }
519
520 $(target).add-alternative $(a) ;
521 }
522 }
523
524 # Accessor, add a constant.
525 #
526 rule add-constant (
527 name # Variable name of the constant.
528 : value + # Value of the constant.
529 : type ? # Optional type of value.
530 )
531 {
532 switch $(type)
533 {
534 case path :
535 local r ;
536 for local v in $(value)
537 {
538 local l = $(self.location) ;
539 if ! $(l)
540 {
541 # Project corresponding to config files do not have
542 # 'location' attribute, but do have source location. It
543 # might be more reasonable to make every project have a
544 # location and use some other approach to prevent buildable
545 # targets in config files, but that has been left for later.
546 l = [ get source-location ] ;
547 }
548 v = [ path.root [ path.make $(v) ] $(l) ] ;
549 # Now make the value absolute path.
550 v = [ path.root $(v) [ path.pwd ] ] ;
551 # Constants should be in platform-native form.
552 v = [ path.native $(v) ] ;
553 r += $(v) ;
554 }
555 value = $(r) ;
556 }
557 if ! $(name) in $(self.constants)
558 {
559 self.constants += $(name) ;
560 }
561 self.constant.$(name) = $(value) ;
562 # Inject the constant in the scope of the Jamroot module.
563 modules.poke $(self.project-module) : $(name) : $(value) ;
564 }
565
566 rule inherit ( parent )
567 {
568 for local c in [ modules.peek $(parent) : self.constants ]
569 {
570 # No need to pass the type. Path constants were converted to
571 # absolute paths already by parent.
572 add-constant $(c) : [ modules.peek $(parent) : self.constant.$(c) ]
573 ;
574 }
575
576 # Import rules from parent.
577 local this-module = [ project-module ] ;
578 local parent-module = [ $(parent).project-module ] ;
579 # Do not import rules coming from 'project-rules' as they must be
580 # imported localized.
581 local user-rules = [ set.difference
582 [ RULENAMES $(parent-module) ] :
583 [ RULENAMES project-rules ] ] ;
584 IMPORT $(parent-module) : $(user-rules) : $(this-module) : $(user-rules)
585 ;
586 EXPORT $(this-module) : $(user-rules) ;
587 }
588 }
589
590
591 # Helper rules to detect cycles in main target references.
592 #
593 local rule start-building ( main-target-instance )
594 {
595 if $(main-target-instance) in $(.targets-being-built)
596 {
597 local names ;
598 for local t in $(.targets-being-built) $(main-target-instance)
599 {
600 names += [ $(t).full-name ] ;
601 }
602
603 import errors ;
604 errors.error "Recursion in main target references"
605 : "the following target are being built currently:"
606 : $(names) ;
607 }
608 .targets-being-built += $(main-target-instance) ;
609 }
610
611
612 local rule end-building ( main-target-instance )
613 {
614 .targets-being-built = $(.targets-being-built[1--2]) ;
615 }
616
617
618 # A named top-level target in Jamfile.
619 #
620 class main-target : abstract-target
621 {
622 import assert ;
623 import feature ;
624 import print ;
625 import property-set ;
626 import sequence ;
627 import targets : start-building end-building ;
628
629 rule __init__ ( name : project )
630 {
631 abstract-target.__init__ $(name) : $(project) ;
632 }
633
634 # Add a new alternative for this target
635 rule add-alternative ( target )
636 {
637 local d = [ $(target).default-build ] ;
638 if $(self.alternatives) && ( $(self.default-build) != $(d) )
639 {
640 import errors : error : errors.error ;
641 errors.error "default build must be identical in all alternatives"
642 : "main target is" [ full-name ]
643 : "with" [ $(d).raw ]
644 : "differing from previous default build"
645 [ $(self.default-build).raw ] ;
646 }
647 else
648 {
649 self.default-build = $(d) ;
650 }
651 self.alternatives += $(target) ;
652 }
653
654 # Returns the best viable alternative for this property-set. See the
655 # documentation for selection rules.
656 #
657 rule select-alternatives ( property-set debug ? )
658 {
659 # When selecting alternatives we have to consider defaults, for example:
660 # lib l : l.cpp : <variant>debug ;
661 # lib l : l_opt.cpp : <variant>release ;
662 # will not work unless we add default value <variant>debug.
663 property-set = [ $(property-set).add-defaults ] ;
664
665 # The algorithm: we keep the current best viable alternative. When we
666 # encounter a new best viable alternative, we compare it with the
667 # current one.
668
669 local best ;
670 local best-properties ;
671
672 if $(self.alternatives[2-])
673 {
674 local bad ;
675 local worklist = $(self.alternatives) ;
676 while $(worklist) && ! $(bad)
677 {
678 local v = $(worklist[1]) ;
679 local properties = [ $(v).match $(property-set) $(debug) ] ;
680
681 if $(properties) != no-match
682 {
683 if ! $(best)
684 {
685 best = $(v) ;
686 best-properties = $(properties) ;
687 }
688 else
689 {
690 if $(properties) = $(best-properties)
691 {
692 bad = true ;
693 }
694 else if $(properties) in $(best-properties)
695 {
696 # Do nothing, this alternative is worse
697 }
698 else if $(best-properties) in $(properties)
699 {
700 best = $(v) ;
701 best-properties = $(properties) ;
702 }
703 else
704 {
705 bad = true ;
706 }
707 }
708 }
709 worklist = $(worklist[2-]) ;
710 }
711 if ! $(bad)
712 {
713 return $(best) ;
714 }
715 }
716 else
717 {
718 return $(self.alternatives) ;
719 }
720 }
721
722 rule apply-default-build ( property-set )
723 {
724 return [ targets.apply-default-build $(property-set) :
725 $(self.default-build) ] ;
726 }
727
728 # Select an alternative for this main target, by finding all alternatives
729 # whose requirements are satisfied by 'properties' and picking the one with
730 # the longest requirements set. Returns the result of calling 'generate' on
731 # that alternative.
732 #
733 rule generate ( property-set )
734 {
735 start-building $(__name__) ;
736
737 # We want composite properties in the build request to act as if all the
738 # properties they expand to have been explicitly specified.
739 property-set = [ $(property-set).expand ] ;
740
741 local all-property-sets = [ apply-default-build $(property-set) ] ;
742 local usage-requirements = [ property-set.empty ] ;
743 local result ;
744 for local p in $(all-property-sets)
745 {
746 local r = [ generate-really $(p) ] ;
747 if $(r)
748 {
749 usage-requirements = [ $(usage-requirements).add $(r[1]) ] ;
750 result += $(r[2-]) ;
751 }
752 }
753 end-building $(__name__) ;
754 return $(usage-requirements) [ sequence.unique $(result) ] ;
755 }
756
757 # Generates the main target with the given property set and returns a list
758 # which first element is property-set object containing usage-requirements
759 # of generated target and with generated virtual target in other elements.
760 # It is possible that no targets are generated.
761 #
762 local rule generate-really ( property-set )
763 {
764 local best-alternatives = [ select-alternatives $(property-set) ] ;
765 if ! $(best-alternatives)
766 {
767 ECHO "error: No best alternative for" [ full-name ] ;
768 select-alternatives $(property-set) debug ;
769 return [ property-set.empty ] ;
770 }
771 else
772 {
773 # Now return virtual targets for the only alternative.
774 return [ $(best-alternatives).generate $(property-set) ] ;
775 }
776 }
777
778 rule rename ( new-name )
779 {
780 abstract-target.rename $(new-name) ;
781 for local a in $(self.alternatives)
782 {
783 $(a).rename $(new-name) ;
784 }
785 }
786 }
787
788
789 # Abstract target referring to a source file. This is an artificial entity
790 # allowing sources to a target to be represented using a list of abstract target
791 # instances.
792 #
793 class file-reference : abstract-target
794 {
795 import virtual-target ;
796 import property-set ;
797 import path ;
798
799 rule __init__ ( file : project )
800 {
801 abstract-target.__init__ $(file) : $(project) ;
802 }
803
804 rule generate ( properties )
805 {
806 return [ property-set.empty ] [ virtual-target.from-file $(self.name) :
807 [ location ] : $(self.project) ] ;
808 }
809
810 # Returns true if the referred file really exists.
811 rule exists ( )
812 {
813 location ;
814 return $(self.file-path) ;
815 }
816
817 # Returns the location of target. Needed by 'testing.jam'.
818 rule location ( )
819 {
820 if ! $(self.file-location)
821 {
822 local source-location = [ $(self.project).get source-location ] ;
823 for local src-dir in $(source-location)
824 {
825 if ! $(self.file-location)
826 {
827 local location = [ path.root $(self.name) $(src-dir) ] ;
828 if [ CHECK_IF_FILE [ path.native $(location) ] ]
829 {
830 self.file-location = $(src-dir) ;
831 self.file-path = $(location) ;
832 }
833 }
834 }
835 }
836 return $(self.file-location) ;
837 }
838 }
839
840
841 # Given a target-reference, made in context of 'project', returns the
842 # abstract-target instance that is referred to, as well as properties explicitly
843 # specified for this reference.
844 #
845 rule resolve-reference ( target-reference : project )
846 {
847 # Separate target name from properties override.
848 local split = [ MATCH "^([^<]*)(/(<.*))?$" : $(target-reference) ] ;
849 local id = $(split[1]) ;
850 if ! $(split) || ! $(id)
851 {
852 error "Malformed target reference $(target-reference)" ;
853 }
854 local sproperties = ;
855 if $(split[3])
856 {
857 sproperties = [ property.make [ feature.split $(split[3]) ] ] ;
858 sproperties = [ feature.expand-composites $(sproperties) ] ;
859 }
860
861 # Find the target.
862 local target = [ $(project).find $(id) ] ;
863
864 return $(target) [ property-set.create $(sproperties) ] ;
865 }
866
867
868 # Attempts to generate the target given by target reference, which can refer
869 # both to a main target or to a file. Returns a list consisting of
870 # - usage requirements
871 # - generated virtual targets, if any
872 #
873 rule generate-from-reference (
874 target-reference # Target reference.
875 : project # Project where the reference is made.
876 : property-set # Properties of the main target that makes the reference.
877 )
878 {
879 local r = [ resolve-reference $(target-reference) : $(project) ] ;
880 local target = $(r[1]) ;
881 local sproperties = $(r[2]) ;
882
883 # Take properties which should be propagated and refine them with
884 # source-specific requirements.
885 local propagated = [ $(property-set).propagated ] ;
886 local rproperties = [ $(propagated).refine $(sproperties) ] ;
887 if $(rproperties[1]) = "@error"
888 {
889 import errors ;
890 errors.error
891 "When building" [ full-name ] " with properties " $(properties) :
892 "Invalid properties specified for " $(source) ":"
893 $(rproperties[2-]) ;
894 }
895 return [ $(target).generate $(rproperties) ] ;
896 }
897
898
899 rule apply-default-build ( property-set : default-build )
900 {
901 # 1. First, see what properties from default-build are already present in
902 # property-set.
903
904 local raw = [ $(property-set).raw ] ;
905 local specified-features = $(raw:G) ;
906
907 local defaults-to-apply ;
908 for local d in [ $(default-build).raw ]
909 {
910 if ! $(d:G) in $(specified-features)
911 {
912 defaults-to-apply += $(d) ;
913 }
914 }
915
916 # 2. If there are any defaults to be applied, form a new build request. Pass
917 # it through to 'expand-no-defaults' since default-build might contain
918 # "release debug" resulting in two property-sets.
919 local result ;
920 if $(defaults-to-apply)
921 {
922 # We have to compress subproperties here to prevent property lists like:
923 # <toolset>msvc <toolset-msvc:version>7.1 <threading>multi
924 #
925 # from being expanded into:
926 # <toolset-msvc:version>7.1/<threading>multi
927 # <toolset>msvc/<toolset-msvc:version>7.1/<threading>multi
928 #
929 # due to a cross-product property combination. That may be an indication
930 # that build-request.expand-no-defaults is the wrong rule to use here.
931 properties = [ build-request.expand-no-defaults
932 [ feature.compress-subproperties $(raw) ] $(defaults-to-apply) ] ;
933
934 if $(properties)
935 {
936 for local p in $(properties)
937 {
938 result += [ property-set.create
939 [ feature.expand [ feature.split $(p) ] ] ] ;
940 }
941 }
942 else
943 {
944 result = [ property-set.empty ] ;
945 }
946 }
947 else
948 {
949 result = $(property-set) ;
950 }
951 return $(result) ;
952 }
953
954
955 # Given a build request and requirements, return properties common to dependency
956 # build request and target requirements.
957 #
958 # TODO: Document exactly what 'common properties' are, whether they should
959 # include default property values, whether they should contain any conditional
960 # properties or should those be already processed, etc. See whether there are
961 # any differences between use cases with empty and non-empty build-request as
962 # well as with requirements containing and those not containing any non-free
963 # features.
964 #
965 rule common-properties ( build-request requirements )
966 {
967 # For optimization, we add free requirements directly, without using a
968 # complex algorithm. This gives the complex algorithm a better chance of
969 # caching results.
970 local free = [ $(requirements).free ] ;
971 local non-free = [ property-set.create [ $(requirements).base ]
972 [ $(requirements).incidental ] ] ;
973
974 local key = .rp.$(build-request)-$(non-free) ;
975 if ! $($(key))
976 {
977 $(key) = [ common-properties2 $(build-request) $(non-free) ] ;
978 }
979 return [ $($(key)).add-raw $(free) ] ;
980 }
981
982
983 # Given a 'context' -- a set of already present properties, and 'requirements',
984 # decide which extra properties should be applied to 'context'. For conditional
985 # requirements, this means evaluating the condition. For indirect conditional
986 # requirements, this means calling a rule. Ordinary requirements are always
987 # applied.
988 #
989 # Handles the situation where evaluating one conditional requirement affects
990 # conditions of another conditional requirements, such as:
991 # <toolset>gcc:<variant>release <variant>release:<define>RELEASE
992 #
993 # If 'what' is 'refined' returns context refined with new requirements. If
994 # 'what' is 'added' returns just the requirements to be applied.
995 #
996 rule evaluate-requirements ( requirements : context : what )
997 {
998 # Apply non-conditional requirements. It is possible that further
999 # conditional requirement change a value set by non-conditional
1000 # requirements. For example:
1001 #
1002 # exe a : a.cpp : <threading>single <toolset>foo:<threading>multi ;
1003 #
1004 # I am not sure if this should be an error, or not, especially given that
1005 #
1006 # <threading>single
1007 #
1008 # might come from project's requirements.
1009
1010 local unconditional = [ feature.expand [ $(requirements).non-conditional ] ]
1011 ;
1012
1013 local raw = [ $(context).raw ] ;
1014 raw = [ property.refine $(raw) : $(unconditional) ] ;
1015
1016 # We have collected properties that surely must be present in common
1017 # properties. We now try to figure out what other properties should be added
1018 # in order to satisfy rules (4)-(6) from the docs.
1019
1020 local conditionals = [ $(requirements).conditional ] ;
1021 # The 'count' variable has one element for each conditional feature and for
1022 # each occurrence of '<indirect-conditional>' feature. It is used as a loop
1023 # counter: for each iteration of the loop before we remove one element and
1024 # the property set should stabilize before we are done. It is assumed that
1025 # #conditionals iterations should be enough for properties to propagate
1026 # along conditions in any direction.
1027 local count = $(conditionals) [ $(requirements).get <conditional> ]
1028 and-once-more ;
1029
1030 local added-requirements ;
1031
1032 local current = $(raw) ;
1033
1034 # It is assumed that ordinary conditional requirements can not add
1035 # <conditional> properties (a.k.a. indirect conditional properties), and
1036 # that rules referred to by <conditional> properties can not add new
1037 # <conditional> properties. So the list of indirect conditionals does not
1038 # change.
1039 local indirect = [ $(requirements).get <conditional> ] ;
1040 indirect = [ MATCH ^@(.*) : $(indirect) ] ;
1041
1042 local ok ;
1043 while $(count)
1044 {
1045 # Evaluate conditionals in context of current properties.
1046 local e = [ property.evaluate-conditionals-in-context $(conditionals) :
1047 $(current) ] ;
1048
1049 # Evaluate indirect conditionals.
1050 for local i in $(indirect)
1051 {
1052 local t = [ current ] ;
1053 local p = [ $(t).project ] ;
1054 local new = [ indirect.call $(i) $(current) ] ;
1055 e += [ property.translate-paths $(new) : [ $(p).location ] ] ;
1056 }
1057
1058 if $(e) = $(added-requirements)
1059 {
1060 # If we got the same result, we have found the final properties.
1061 count = ;
1062 ok = true ;
1063 }
1064 else
1065 {
1066 # Oops, conditional evaluation results have changed. Also 'current'
1067 # contains leftovers from a previous evaluation. Recompute 'current'
1068 # using initial properties and conditional requirements.
1069 added-requirements = $(e) ;
1070 current = [ property.refine $(raw) : [ feature.expand $(e) ] ] ;
1071 }
1072 count = $(count[2-]) ;
1073 }
1074 if ! $(ok)
1075 {
1076 import errors ;
1077 errors.error Can not evaluate conditional properties $(conditionals) ;
1078 }
1079
1080 if $(what) = added
1081 {
1082 return [ property-set.create $(unconditional) $(added-requirements) ] ;
1083 }
1084 else if $(what) = refined
1085 {
1086 return [ property-set.create $(current) ] ;
1087 }
1088 else
1089 {
1090 import errors ;
1091 errors.error "Invalid value of the 'what' parameter." ;
1092 }
1093 }
1094
1095
1096 rule common-properties2 ( build-request requirements )
1097 {
1098 # This guarantees that default properties are present in the result, unless
1099 # they are overriden by some requirement. FIXME: There is a possibility that
1100 # we have added <foo>bar, which is composite and expands to <foo2>bar2, but
1101 # default value of <foo2> is not bar2, in which case it is not clear what to
1102 # do.
1103 #
1104 build-request = [ $(build-request).add-defaults ] ;
1105 # Features added by 'add-defaults' can be composite and expand to features
1106 # without default values -- which therefore have not been added yet. It
1107 # could be clearer/faster to expand only newly added properties but that is
1108 # not critical.
1109 build-request = [ $(build-request).expand ] ;
1110
1111 return [ evaluate-requirements $(requirements) : $(build-request) :
1112 refined ] ;
1113 }
1114
1115
1116 rule push-target ( target )
1117 {
1118 .targets = $(target) $(.targets) ;
1119 }
1120
1121 rule pop-target ( )
1122 {
1123 .targets = $(.targets[2-]) ;
1124 }
1125
1126 # Return the metatarget that is currently being generated.
1127 rule current ( )
1128 {
1129 return $(.targets[1]) ;
1130 }
1131
1132
1133 # Implements the most standard way of constructing main target alternative from
1134 # sources. Allows sources to be either file or other main target and handles
1135 # generation of those dependency targets.
1136 #
1137 class basic-target : abstract-target
1138 {
1139 import build-request ;
1140 import build-system ;
1141 import "class" : new ;
1142 import feature ;
1143 import property ;
1144 import property-set ;
1145 import sequence ;
1146 import set ;
1147 import targets ;
1148 import virtual-target ;
1149
1150 rule __init__ ( name : project : sources * : requirements * :
1151 default-build * : usage-requirements * )
1152 {
1153 abstract-target.__init__ $(name) : $(project) ;
1154
1155 self.sources = $(sources) ;
1156 if ! $(requirements)
1157 {
1158 requirements = [ property-set.empty ] ;
1159 }
1160 self.requirements = $(requirements) ;
1161 if ! $(default-build)
1162 {
1163 default-build = [ property-set.empty ] ;
1164 }
1165 self.default-build = $(default-build) ;
1166 if ! $(usage-requirements)
1167 {
1168 usage-requirements = [ property-set.empty ] ;
1169 }
1170 self.usage-requirements = $(usage-requirements) ;
1171
1172 if $(sources:G)
1173 {
1174 import errors : user-error : errors.user-error ;
1175 errors.user-error properties found "in" the 'sources' parameter
1176 "for" [ full-name ] ;
1177 }
1178 }
1179
1180 rule always ( )
1181 {
1182 self.always = 1 ;
1183 }
1184
1185 # Returns the list of abstract-targets which are used as sources. The extra
1186 # properties specified for sources are not represented. The only user for
1187 # this rule at the moment is the "--dump-tests" feature of the test system.
1188 #
1189 rule sources ( )
1190 {
1191 if ! $(self.source-targets)
1192 {
1193 for local s in $(self.sources)
1194 {
1195 self.source-targets += [ targets.resolve-reference $(s) :
1196 $(self.project) ] ;
1197 }
1198 }
1199 return $(self.source-targets) ;
1200 }
1201
1202 rule requirements ( )
1203 {
1204 return $(self.requirements) ;
1205 }
1206
1207 rule default-build ( )
1208 {
1209 return $(self.default-build) ;
1210 }
1211
1212 # Returns the alternative condition for this alternative, if the condition
1213 # is satisfied by 'property-set'.
1214 #
1215 rule match ( property-set debug ? )
1216 {
1217 # The condition is composed of all base non-conditional properties. It
1218 # is not clear if we should expand 'self.requirements' or not. For one
1219 # thing, it would be nice to be able to put
1220 # <toolset>msvc-6.0
1221 # in requirements. On the other hand, if we have <variant>release as a
1222 # condition it does not make sense to require <optimization>full to be
1223 # in the build request just to select this variant.
1224 local bcondition = [ $(self.requirements).base ] ;
1225 local ccondition = [ $(self.requirements).conditional ] ;
1226 local condition = [ set.difference $(bcondition) : $(ccondition) ] ;
1227 if $(debug)
1228 {
1229 ECHO " next alternative: required properties:"
1230 $(condition:E=(empty)) ;
1231 }
1232
1233 if $(condition) in [ $(property-set).raw ]
1234 {
1235 if $(debug)
1236 {
1237 ECHO " matched" ;
1238 }
1239 return $(condition) ;
1240 }
1241 else
1242 {
1243 if $(debug)
1244 {
1245 ECHO " not matched" ;
1246 }
1247 return no-match ;
1248 }
1249 }
1250
1251 # Takes a target reference, which might be either target id or a dependency
1252 # property, and generates that target using 'property-set' as a build
1253 # request.
1254 #
1255 # The results are added to the variable called 'result-var'. Usage
1256 # requirements are added to the variable called 'usage-requirements-var'.
1257 #
1258 rule generate-dependencies ( dependencies * : property-set : result-var
1259 usage-requirements-var )
1260 {
1261 for local dependency in $(dependencies)
1262 {
1263 local grist = $(dependency:G) ;
1264 local id = $(dependency:G=) ;
1265 local result = [ targets.generate-from-reference $(id) :
1266 $(self.project) : $(property-set) ] ;
1267
1268 $(result-var) += $(result[2-]:G=$(grist)) ;
1269 $(usage-requirements-var) += [ $(result[1]).raw ] ;
1270 }
1271 }
1272
1273 # Determines final build properties, generates sources, and calls
1274 # 'construct'. This method should not be overridden.
1275 #
1276 rule generate ( property-set )
1277 {
1278 if [ modules.peek : .debug-building ]
1279 {
1280 ECHO ;
1281 local fn = [ full-name ] ;
1282 ECHO [ targets.indent ] "Building target '$(fn)'" ;
1283 targets.increase-indent ;
1284 ECHO [ targets.indent ] Build request: $(property-set)
1285 [ $(property-set).raw ] ;
1286 local cf = [ build-system.command-line-free-features ] ;
1287 ECHO [ targets.indent ] Command line free features: [ $(cf).raw ] ;
1288 ECHO [ targets.indent ] Target requirements:
1289 [ $(self.requirements).raw ] ;
1290 }
1291 targets.push-target $(__name__) ;
1292
1293 # Apply free features from the command line. If user said
1294 # define=FOO
1295 # he most likely wants this define to be set for all compiles.
1296 # Make it before check for already built.
1297 property-set = [ $(property-set).refine
1298 [ build-system.command-line-free-features ] ] ;
1299
1300 if ! $(self.generated.$(property-set))
1301 {
1302 local rproperties = [ targets.common-properties $(property-set)
1303 $(self.requirements) ] ;
1304
1305 if [ modules.peek : .debug-building ]
1306 {
1307 ECHO ;
1308 ECHO [ targets.indent ] "Common properties: "
1309 [ $(rproperties).raw ] ;
1310 }
1311
1312 if ( $(rproperties[1]) != "@error" ) && ( [ $(rproperties).get
1313 <build> ] != no )
1314 {
1315 local source-targets ;
1316 local properties = [ $(rproperties).non-dependency ] ;
1317 local usage-requirements ;
1318
1319 generate-dependencies [ $(rproperties).dependency ] :
1320 $(rproperties) : properties usage-requirements ;
1321
1322 generate-dependencies $(self.sources) : $(rproperties) :
1323 source-targets usage-requirements ;
1324
1325 if [ modules.peek : .debug-building ]
1326 {
1327 ECHO ;
1328 ECHO [ targets.indent ] "Usage requirements for"
1329 $(self.name)": " $(usage-requirements) ;
1330 }
1331
1332 rproperties = [ property-set.create $(properties)
1333 $(usage-requirements) ] ;
1334 usage-requirements = [ property-set.create $(usage-requirements)
1335 ] ;
1336
1337 if [ modules.peek : .debug-building ]
1338 {
1339 ECHO [ targets.indent ] "Build properties: "
1340 [ $(rproperties).raw ] ;
1341 }
1342
1343 local extra = [ $(rproperties).get <source> ] ;
1344 source-targets += $(extra:G=) ;
1345 # We might get duplicate sources, for example if we link to two
1346 # libraries having the same <library> usage requirement. Use
1347 # stable sort, since for some targets the order is important,
1348 # e.g. RUN_PY targets need a python source to come first.
1349 source-targets = [ sequence.unique $(source-targets) : stable ]
1350 ;
1351
1352 local result = [ construct $(self.name) : $(source-targets) :
1353 $(rproperties) ] ;
1354
1355 if $(result)
1356 {
1357 local gur = $(result[1]) ;
1358 result = $(result[2-]) ;
1359
1360 if $(self.always)
1361 {
1362 for local t in $(result)
1363 {
1364 $(t).always ;
1365 }
1366 }
1367
1368 local s = [ create-subvariant $(result)
1369 : [ virtual-target.recent-targets ]
1370 : $(property-set) : $(source-targets)
1371 : $(rproperties) : $(usage-requirements) ] ;
1372 virtual-target.clear-recent-targets ;
1373
1374 local ur = [ compute-usage-requirements $(s) ] ;
1375 ur = [ $(ur).add $(gur) ] ;
1376 $(s).set-usage-requirements $(ur) ;
1377 if [ modules.peek : .debug-building ]
1378 {
1379 ECHO [ targets.indent ] "Usage requirements from"
1380 $(self.name)": " [ $(ur).raw ] ;
1381 }
1382
1383 self.generated.$(property-set) = $(ur) $(result) ;
1384 }
1385 }
1386 else
1387 {
1388 if $(rproperties[1]) = "@error"
1389 {
1390 ECHO [ targets.indent ] "Skipping build of:" [ full-name ]
1391 "cannot compute common properties" ;
1392 }
1393 else if [ $(rproperties).get <build> ] = no
1394 {
1395 # If we just see <build>no, we cannot produce any reasonable
1396 # diagnostics. The code that adds this property is expected
1397 # to explain why a target is not built, for example using
1398 # the configure.log-component-configuration function.
1399 }
1400 else
1401 {
1402 ECHO [ targets.indent ] "Skipping build of: " [ full-name ]
1403 " unknown reason" ;
1404 }
1405
1406 # We are here either because there has been an error computing
1407 # properties or there is <build>no in properties. In the latter
1408 # case we do not want any diagnostic. In the former case, we
1409 # need diagnostics. FIXME
1410
1411 # If this target fails to build, add <build>no to properties to
1412 # cause any parent target to fail to build. Except that it
1413 # - does not work now, since we check for <build>no only in
1414 # common properties, but not in properties that came from
1415 # dependencies
1416 # - it is not clear if that is a good idea anyway. The alias
1417 # target, for example, should not fail to build if a
1418 # dependency fails.
1419 self.generated.$(property-set) = [ property-set.create <build>no
1420 ] ;
1421 }
1422 }
1423 else
1424 {
1425 if [ modules.peek : .debug-building ]
1426 {
1427 ECHO [ targets.indent ] "Already built" ;
1428 local ur = $(self.generated.$(property-set)) ;
1429 ur = $(ur[0]) ;
1430 targets.increase-indent ;
1431 ECHO [ targets.indent ] "Usage requirements from"
1432 $(self.name)": " [ $(ur).raw ] ;
1433 targets.decrease-indent ;
1434 }
1435 }
1436
1437 targets.pop-target ;
1438 targets.decrease-indent ;
1439 return $(self.generated.$(property-set)) ;
1440 }
1441
1442 # Given the set of generated targets, and refined build properties,
1443 # determines and sets appropriate usage requirements on those targets.
1444 #
1445 rule compute-usage-requirements ( subvariant )
1446 {
1447 local rproperties = [ $(subvariant).build-properties ] ;
1448 xusage-requirements = [ targets.evaluate-requirements
1449 $(self.usage-requirements) : $(rproperties) : added ] ;
1450
1451 # We generate all dependency properties and add them, as well as their
1452 # usage requirements, to the result.
1453 local extra ;
1454 generate-dependencies [ $(xusage-requirements).dependency ] :
1455 $(rproperties) : extra extra ;
1456
1457 local result = [ property-set.create
1458 [ $(xusage-requirements).non-dependency ] $(extra) ] ;
1459
1460 # Propagate usage requirements we got from sources, except for the
1461 # <pch-header> and <pch-file> features.
1462 #
1463 # That feature specifies which pch file to use, and should apply only to
1464 # direct dependents. Consider:
1465 #
1466 # pch pch1 : ...
1467 # lib lib1 : ..... pch1 ;
1468 # pch pch2 :
1469 # lib lib2 : pch2 lib1 ;
1470 #
1471 # Here, lib2 should not get <pch-header> property from pch1.
1472 #
1473 # Essentially, when those two features are in usage requirements, they
1474 # are propagated only to direct dependents. We might need a more general
1475 # mechanism, but for now, only those two features are special.
1476 #
1477 # TODO - Actually there are more possible candidates like for instance
1478 # when listing static library X as a source for another static library.
1479 # Then static library X will be added as a <source> property to the
1480 # second library's usage requirements but those requirements should last
1481 # only up to the first executable or shared library that actually links
1482 # to it.
1483 local raw = [ $(subvariant).sources-usage-requirements ] ;
1484 raw = [ $(raw).raw ] ;
1485 raw = [ property.change $(raw) : <pch-header> ] ;
1486 raw = [ property.change $(raw) : <pch-file> ] ;
1487 return [ $(result).add [ property-set.create $(raw) ] ] ;
1488 }
1489
1490 # Creates new subvariant instances for 'targets'.
1491 # 'root-targets' - virtual targets to be returned to dependants
1492 # 'all-targets' - virtual targets created while building this main target
1493 # 'build-request' - property-set instance with requested build properties
1494 #
1495 local rule create-subvariant ( root-targets * : all-targets * :
1496 build-request : sources * : rproperties : usage-requirements )
1497 {
1498 for local e in $(root-targets)
1499 {
1500 $(e).root true ;
1501 }
1502
1503 # Process all virtual targets that will be created if this main target
1504 # is created.
1505 local s = [ new subvariant $(__name__) : $(build-request) : $(sources) :
1506 $(rproperties) : $(usage-requirements) : $(all-targets) ] ;
1507 for local v in $(all-targets)
1508 {
1509 if ! [ $(v).creating-subvariant ]
1510 {
1511 $(v).creating-subvariant $(s) ;
1512 }
1513 }
1514 return $(s) ;
1515 }
1516
1517 # Constructs virtual targets for this abstract target and the dependency
1518 # graph. Returns a usage-requirements property-set and a list of virtual
1519 # targets. Should be overriden in derived classes.
1520 #
1521 rule construct ( name : source-targets * : properties * )
1522 {
1523 import errors : error : errors.error ;
1524 errors.error "method should be defined in derived classes" ;
1525 }
1526 }
1527
1528
1529 class typed-target : basic-target
1530 {
1531 import generators ;
1532
1533 rule __init__ ( name : project : type : sources * : requirements * :
1534 default-build * : usage-requirements * )
1535 {
1536 basic-target.__init__ $(name) : $(project) : $(sources) :
1537 $(requirements) : $(default-build) : $(usage-requirements) ;
1538
1539 self.type = $(type) ;
1540 }
1541
1542 rule type ( )
1543 {
1544 return $(self.type) ;
1545 }
1546
1547 rule construct ( name : source-targets * : property-set )
1548 {
1549 local r = [ generators.construct $(self.project) $(name:S=)
1550 : $(self.type)
1551 : [ property-set.create [ $(property-set).raw ]
1552 <main-target-type>$(self.type) ]
1553 : $(source-targets) : true ] ;
1554 if ! $(r)
1555 {
1556 local viable-generators = [ generators.find-viable-generators
1557 $(self.type) : $(property-set) ] ;
1558 ECHO "WARNING: Unable to construct" [ full-name ]
1559 "of type" $(self.type)
1560 "with these properties:" [ $(property-set).raw ] ;
1561 ECHO "WARNING: Considered these as possible generators:" ;
1562 for local gen in $(viable-generators)
1563 {
1564 ECHO "WARNING:" [ $(gen).id ]
1565 "with source types {" [ $(gen).source-types ] "}"
1566 "and requirements {" [ $(gen).requirements ] "}" ;
1567 }
1568
1569 # Are there any top-level generators for this type/property set.
1570 if ! [ generators.find-viable-generators $(self.type) :
1571 $(property-set) ]
1572 {
1573 ECHO "error: no generators were found for type '$(self.type)'" ;
1574 ECHO "error: and the requested properties" ;
1575 ECHO "error: make sure you've configured the needed tools" ;
1576 ECHO "See http://boost.org/boost-build2/doc/html/bbv2/advanced/configuration.html" ;
1577 EXIT "To debug this problem, try the --debug-generators option."
1578 ;
1579 }
1580 }
1581 return $(r) ;
1582 }
1583 }
1584
1585
1586 # Return the list of sources to use, if main target rule is invoked with
1587 # 'sources'. If there are any objects in 'sources', they are treated as main
1588 # target instances, and the name of such targets are adjusted to be
1589 # '<name_of_this_target>__<name_of_source_target>'. Such renaming is disabled if
1590 # a non-empty value is passed as the 'no-renaming' parameter.
1591 #
1592 rule main-target-sources ( sources * : main-target-name : no-renaming ? )
1593 {
1594 local result ;
1595 for local t in $(sources)
1596 {
1597 if [ class.is-instance $(t) ]
1598 {
1599 local name = [ $(t).name ] ;
1600 if ! $(no-renaming)
1601 {
1602 name = $(main-target-name)__$(name) ;
1603 $(t).rename $(name) ;
1604 }
1605 # Inline targets are not built by default.
1606 local p = [ $(t).project ] ;
1607 $(p).mark-target-as-explicit $(name) ;
1608 result += $(name) ;
1609 }
1610 else
1611 {
1612 result += $(t) ;
1613 }
1614 }
1615 return $(result) ;
1616 }
1617
1618
1619 # Returns the requirements to use when declaring a main target, obtained by
1620 # translating all specified property paths and refining project requirements
1621 # with the ones specified for the target.
1622 #
1623 rule main-target-requirements (
1624 specification * # Properties explicitly specified for the main target.
1625 : project # Project where the main target is to be declared.
1626 )
1627 {
1628 local requirements = [ property-set.refine-from-user-input
1629 [ $(project).get requirements ] : $(specification) :
1630 [ $(project).project-module ] : [ $(project).get location ] ] ;
1631 if $(requirements[1]) = "@error"
1632 {
1633 import errors ;
1634 errors.error "Conflicting requirements for target:" $(requirements) ;
1635 }
1636 return [ $(requirements).add [ toolset.requirements ] ] ;
1637 }
1638
1639
1640 # Returns the usage requirements to use when declaring a main target, which are
1641 # obtained by translating all specified property paths and adding project's
1642 # usage requirements.
1643 #
1644 rule main-target-usage-requirements (
1645 specification * # Use-properties explicitly specified for a main target.
1646 : project # Project where the main target is to be declared.
1647 )
1648 {
1649 local project-usage-requirements = [ $(project).get usage-requirements ] ;
1650
1651 # We do not use 'refine-from-user-input' because:
1652 # - I am not sure if removing parent's usage requirements makes sense
1653 # - refining usage requirements is not needed, since usage requirements are
1654 # always free.
1655 local usage-requirements = [ property-set.create-from-user-input
1656 $(specification)
1657 : [ $(project).project-module ] [ $(project).get location ] ] ;
1658
1659 return [ $(project-usage-requirements).add $(usage-requirements) ] ;
1660 }
1661
1662
1663 # Return the default build value to use when declaring a main target, which is
1664 # obtained by using the specified value if not empty and parent's default build
1665 # attribute otherwise.
1666 #
1667 rule main-target-default-build (
1668 specification * # Default build explicitly specified for a main target.
1669 : project # Project where the main target is to be declared.
1670 )
1671 {
1672 local result ;
1673 if $(specification)
1674 {
1675 result = $(specification) ;
1676 }
1677 else
1678 {
1679 result = [ $(project).get default-build ] ;
1680 }
1681 return [ property-set.create-with-validation $(result) ] ;
1682 }
1683
1684
1685 # Registers the specified target as a main target alternative and returns it.
1686 #
1687 rule main-target-alternative ( target )
1688 {
1689 local ptarget = [ $(target).project ] ;
1690 $(ptarget).add-alternative $(target) ;
1691 return $(target) ;
1692 }
1693
1694
1695 # Creates a metatarget with the specified properties, using 'klass' as the
1696 # class. The 'name', 'sources', 'requirements', 'default-build' and
1697 # 'usage-requirements' are assumed to be in the form specified by the user in
1698 # the Jamfile corresponding to 'project'.
1699 #
1700 rule create-metatarget ( klass : project : name : sources * : requirements * :
1701 default-build * : usage-requirements * )
1702 {
1703 return [ targets.main-target-alternative [ new $(klass) $(name) : $(project)
1704 : [ targets.main-target-sources $(sources) : $(name) ]
1705 : [ targets.main-target-requirements $(requirements) : $(project) ]
1706 : [ targets.main-target-default-build $(default-build) : $(project) ]
1707 : [ targets.main-target-usage-requirements $(usage-requirements) :
1708 $(project) ] ] ] ;
1709 }
1710
1711
1712 # Creates a typed-target with the specified properties. The 'name', 'sources',
1713 # 'requirements', 'default-build' and 'usage-requirements' are assumed to be in
1714 # the form specified by the user in the Jamfile corresponding to 'project'.
1715 #
1716 rule create-typed-target ( type : project : name : sources * : requirements * :
1717 default-build * : usage-requirements * )
1718 {
1719 return [ targets.main-target-alternative [ new typed-target $(name) :
1720 $(project) : $(type)
1721 : [ targets.main-target-sources $(sources) : $(name) ]
1722 : [ targets.main-target-requirements $(requirements) : $(project) ]
1723 : [ targets.main-target-default-build $(default-build) : $(project) ]
1724 : [ targets.main-target-usage-requirements $(usage-requirements) :
1725 $(project) ] ] ] ;
1726 }