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)
7 # Supports 'abstract' targets, which are targets explicitly defined in a
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
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.
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
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'.
30 # +--------------------------+
32 # +==========================+
36 # | generate(properties) = 0 |
37 # +-------------+------------+
44 # +------------------+-----+-------------------------------+
47 # +-----------+----------+ +------+------+ +-------+------+
48 # | project-target | | main-target | | basic-target |
49 # +======================+ 1 * +=============+ alternatives +==============+
50 # | generate(properties) |o-----+ generate |<>------------->| generate |
51 # | main-target | +-------------+ | construct = 0|
52 # +----------------------+ +-------+------+
59 # ...--+-----------------+-----------------+------------------+
62 # ... ---+-----+ +-------+------+ +------+------+ +-------+------+
63 # | | typed-target | | make-target | | stage-target |
64 # . +==============+ +=============+ +==============+
65 # . | construct | | construct | | construct |
66 # +--------------+ +-------------+ +--------------+
69 import build-request ;
70 import "class" : new ;
81 # Base class for all abstract targets.
90 rule __init__ ( name # Name of the target in Jamfile.
91 : project-target # The project target to which this one belongs.
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.
100 self.project = $(project-target) ;
101 self.location = [ errors.nearest-user-location ] ;
104 # Returns the name of this target.
107 return $(self.name) ;
110 # Returns the project for this target.
113 return $(self.project) ;
116 # Return the location where the target was declared.
119 return $(self.location) ;
122 # Returns a user-readable name for this target.
125 local location = [ $(self.project).get location ] ;
126 return $(location)/$(self.name) ;
129 # Generates virtual targets for this abstract target using the specified
130 # properties, unless a different value of some feature is required by the
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.
138 rule generate ( property-set )
140 errors.error "method should be defined in derived classes" ;
143 rule rename ( new-name )
145 self.name = $(new-name) ;
150 if --debug-building in [ modules.peek : ARGV ]
152 modules.poke : .debug-building : true ;
158 return $(.indent:J="") ;
162 rule increase-indent ( )
168 rule decrease-indent ( )
170 .indent = $(.indent[2-]) ;
174 # Project target class (derived from 'abstract-target').
176 # This class has the following responsibilities:
177 # - Maintaining a list of main targets in this project and building them.
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.
185 class project-target : abstract-target
191 import property-set ;
194 import "class" : new ;
196 rule __init__ ( name : project-module parent-project ?
197 : requirements * : default-build * )
199 abstract-target.__init__ $(name) : $(__name__) ;
201 self.project-module = $(project-module) ;
202 self.location = [ project.attribute $(project-module) location ] ;
203 self.requirements = $(requirements) ;
204 self.default-build = $(default-build) ;
208 inherit $(parent-project) ;
212 # This is needed only by the 'make' rule. Need to find a way to make 'make'
213 # work without this method.
215 rule project-module ( )
217 return $(self.project-module) ;
220 rule get ( attribute )
222 return [ project.attribute $(self.project-module) $(attribute) ] ;
227 if ! $(self.build-dir)
229 self.build-dir = [ get build-dir ] ;
230 if ! $(self.build-dir)
232 local location = [ $(self.project).get location ] ;
235 self.build-dir = [ path.join $(location) bin ] ;
239 local id = [ get id ] ;
242 local rid = [ MATCH ^/(.*) : $(id) ] ;
243 self.build-dir = [ path.join [ project.standalone-build-dir ] $(rid) ] ;
247 errors.error "Could not create build-dir for standalone project $(self.project-module:E=)."
248 : "Missing project id" ;
253 return $(self.build-dir) ;
256 # Generates all possible targets contained in this project.
258 rule generate ( property-set * )
260 if [ modules.peek : .debug-building ]
262 ECHO [ targets.indent ] "building project" [ name ]
263 " ('$(__name__)') with" [ $(property-set).raw ] ;
264 targets.increase-indent ;
267 local usage-requirements = [ property-set.empty ] ;
270 for local t in [ targets-to-build ]
272 local g = [ $(t).generate $(property-set) ] ;
273 usage-requirements = [ $(usage-requirements).add $(g[1]) ] ;
274 targets += $(g[2-]) ;
276 targets.decrease-indent ;
277 return $(usage-requirements) [ sequence.unique $(targets) ] ;
280 # Computes and returns a list of abstract-target instances which must be
281 # built when this project is built.
283 rule targets-to-build ( )
287 if ! $(self.built-main-targets)
292 # Collect all main targets here, except for "explicit" ones.
293 for local t in $(self.main-targets)
295 if ! [ $(t).name ] in $(self.explicit-targets)
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 ]
305 result += [ find $(pn)/ ] ;
311 # Add 'target' to the list of targets in this project that should be build
312 # only by explicit request
314 rule mark-target-as-explicit ( target-name * )
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) ;
321 rule mark-target-as-always ( target-name * )
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) ;
328 # Add new target alternative
330 rule add-alternative ( target-instance )
332 if $(self.built-main-targets)
334 import errors : error : errors.error ;
335 errors.error add-alternative called when main targets are already
336 created. : in project [ full-name ] ;
338 self.alternatives += $(target-instance) ;
339 if ! ( [ $(target-instance).name ] in $(self.alternative-names) )
341 self.alternative-names += [ $(target-instance).name ] ;
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.
350 rule has-alternative-for-target ( target-name )
352 if $(target-name) in $(self.alternative-names)
358 # Returns a 'main-target' class instance corresponding to 'name'.
360 rule main-target ( name )
362 if ! $(self.built-main-targets)
366 return $(self.main-target.$(name)) ;
369 # Returns whether a main target with the specified name exists.
371 rule has-main-target ( name )
373 if ! $(self.built-main-targets)
378 if $(self.main-target.$(name))
384 # Worker function for the find rule not implementing any caching and simply
385 # returning nothing in case the target can not be found.
387 rule find-really ( id )
390 local current-location = [ get location ] ;
392 local split = [ MATCH ^(.*)//(.*)$ : $(id) ] ;
393 local project-part = $(split[1]) ;
394 local target-part = $(split[2]) ;
396 local extra-error-message ;
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) ] ;
404 project-target = [ project.target $(pm) ] ;
405 result = [ $(project-target).find $(target-part) : no-error ] ;
409 extra-error-message = could not resolve project reference
411 if ! [ path.is-rooted $(project-part) ]
413 local rooted = [ path.root $(project-part) / ] ;
414 if $(rooted) && [ project.is-registered-id $(rooted) ]
416 extra-error-message += - possibly missing a leading
417 slash ('/') character. ;
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:
429 # exe test : test.cpp ;
430 # install s : test : <location>. ;
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
435 result = [ main-target $(id) ] ;
437 # Interpret id as an existing file reference.
440 result = [ new file-reference [ path.make $(id) ] :
442 if ! [ $(result).exists ]
448 # Interpret id as project-id.
451 local project-module = [ project.find $(id) :
452 $(current-location) ] ;
455 result = [ project.target $(project-module) ] ;
460 return $(result:E="") $(extra-error-message) ;
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.
468 rule find ( id : no-error ? )
470 local v = $(.id.$(id)) ;
471 local extra-error-message ;
474 local r = [ find-really $(id) ] ;
476 extra-error-message = $(r[2-]) ;
488 else if ! $(no-error)
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
494 : referred to from project at
495 : " " '$(current-location)'
496 : $(extra-error-message) ;
500 rule build-main-targets ( )
502 self.built-main-targets = true ;
503 for local a in $(self.alternatives)
505 local name = [ $(a).name ] ;
506 local target = $(self.main-target.$(name)) ;
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)) ;
515 if $(name) in $(self.always-targets)
520 $(target).add-alternative $(a) ;
524 # Accessor, add a constant.
527 name # Variable name of the constant.
528 : value + # Value of the constant.
529 : type ? # Optional type of value.
536 for local v in $(value)
538 local l = $(self.location) ;
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 ] ;
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) ] ;
557 if ! $(name) in $(self.constants)
559 self.constants += $(name) ;
561 self.constant.$(name) = $(value) ;
562 # Inject the constant in the scope of the Jamroot module.
563 modules.poke $(self.project-module) : $(name) : $(value) ;
566 rule inherit ( parent )
568 for local c in [ modules.peek $(parent) : self.constants ]
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) ]
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)
586 EXPORT $(this-module) : $(user-rules) ;
591 # Helper rules to detect cycles in main target references.
593 local rule start-building ( main-target-instance )
595 if $(main-target-instance) in $(.targets-being-built)
598 for local t in $(.targets-being-built) $(main-target-instance)
600 names += [ $(t).full-name ] ;
604 errors.error "Recursion in main target references"
605 : "the following target are being built currently:"
608 .targets-being-built += $(main-target-instance) ;
612 local rule end-building ( main-target-instance )
614 .targets-being-built = $(.targets-being-built[1--2]) ;
618 # A named top-level target in Jamfile.
620 class main-target : abstract-target
625 import property-set ;
627 import targets : start-building end-building ;
629 rule __init__ ( name : project )
631 abstract-target.__init__ $(name) : $(project) ;
634 # Add a new alternative for this target
635 rule add-alternative ( target )
637 local d = [ $(target).default-build ] ;
638 if $(self.alternatives) && ( $(self.default-build) != $(d) )
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 ] ;
649 self.default-build = $(d) ;
651 self.alternatives += $(target) ;
654 # Returns the best viable alternative for this property-set. See the
655 # documentation for selection rules.
657 rule select-alternatives ( property-set debug ? )
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 ] ;
665 # The algorithm: we keep the current best viable alternative. When we
666 # encounter a new best viable alternative, we compare it with the
670 local best-properties ;
672 if $(self.alternatives[2-])
675 local worklist = $(self.alternatives) ;
676 while $(worklist) && ! $(bad)
678 local v = $(worklist[1]) ;
679 local properties = [ $(v).match $(property-set) $(debug) ] ;
681 if $(properties) != no-match
686 best-properties = $(properties) ;
690 if $(properties) = $(best-properties)
694 else if $(properties) in $(best-properties)
696 # Do nothing, this alternative is worse
698 else if $(best-properties) in $(properties)
701 best-properties = $(properties) ;
709 worklist = $(worklist[2-]) ;
718 return $(self.alternatives) ;
722 rule apply-default-build ( property-set )
724 return [ targets.apply-default-build $(property-set) :
725 $(self.default-build) ] ;
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
733 rule generate ( property-set )
735 start-building $(__name__) ;
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 ] ;
741 local all-property-sets = [ apply-default-build $(property-set) ] ;
742 local usage-requirements = [ property-set.empty ] ;
744 for local p in $(all-property-sets)
746 local r = [ generate-really $(p) ] ;
749 usage-requirements = [ $(usage-requirements).add $(r[1]) ] ;
753 end-building $(__name__) ;
754 return $(usage-requirements) [ sequence.unique $(result) ] ;
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.
762 local rule generate-really ( property-set )
764 local best-alternatives = [ select-alternatives $(property-set) ] ;
765 if ! $(best-alternatives)
767 ECHO "error: No best alternative for" [ full-name ] ;
768 select-alternatives $(property-set) debug ;
769 return [ property-set.empty ] ;
773 # Now return virtual targets for the only alternative.
774 return [ $(best-alternatives).generate $(property-set) ] ;
778 rule rename ( new-name )
780 abstract-target.rename $(new-name) ;
781 for local a in $(self.alternatives)
783 $(a).rename $(new-name) ;
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
793 class file-reference : abstract-target
795 import virtual-target ;
796 import property-set ;
799 rule __init__ ( file : project )
801 abstract-target.__init__ $(file) : $(project) ;
804 rule generate ( properties )
806 return [ property-set.empty ] [ virtual-target.from-file $(self.name) :
807 [ location ] : $(self.project) ] ;
810 # Returns true if the referred file really exists.
814 return $(self.file-path) ;
817 # Returns the location of target. Needed by 'testing.jam'.
820 if ! $(self.file-location)
822 local source-location = [ $(self.project).get source-location ] ;
823 for local src-dir in $(source-location)
825 if ! $(self.file-location)
827 local location = [ path.root $(self.name) $(src-dir) ] ;
828 if [ CHECK_IF_FILE [ path.native $(location) ] ]
830 self.file-location = $(src-dir) ;
831 self.file-path = $(location) ;
836 return $(self.file-location) ;
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.
845 rule resolve-reference ( target-reference : project )
847 # Separate target name from properties override.
848 local split = [ MATCH "^([^<]*)(/(<.*))?$" : $(target-reference) ] ;
849 local id = $(split[1]) ;
850 if ! $(split) || ! $(id)
852 error "Malformed target reference $(target-reference)" ;
854 local sproperties = ;
857 sproperties = [ property.make [ feature.split $(split[3]) ] ] ;
858 sproperties = [ feature.expand-composites $(sproperties) ] ;
862 local target = [ $(project).find $(id) ] ;
864 return $(target) [ property-set.create $(sproperties) ] ;
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
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.
879 local r = [ resolve-reference $(target-reference) : $(project) ] ;
880 local target = $(r[1]) ;
881 local sproperties = $(r[2]) ;
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"
891 "When building" [ full-name ] " with properties " $(properties) :
892 "Invalid properties specified for " $(source) ":"
895 return [ $(target).generate $(rproperties) ] ;
899 rule apply-default-build ( property-set : default-build )
901 # 1. First, see what properties from default-build are already present in
904 local raw = [ $(property-set).raw ] ;
905 local specified-features = $(raw:G) ;
907 local defaults-to-apply ;
908 for local d in [ $(default-build).raw ]
910 if ! $(d:G) in $(specified-features)
912 defaults-to-apply += $(d) ;
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.
920 if $(defaults-to-apply)
922 # We have to compress subproperties here to prevent property lists like:
923 # <toolset>msvc <toolset-msvc:version>7.1 <threading>multi
925 # from being expanded into:
926 # <toolset-msvc:version>7.1/<threading>multi
927 # <toolset>msvc/<toolset-msvc:version>7.1/<threading>multi
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) ] ;
936 for local p in $(properties)
938 result += [ property-set.create
939 [ feature.expand [ feature.split $(p) ] ] ] ;
944 result = [ property-set.empty ] ;
949 result = $(property-set) ;
955 # Given a build request and requirements, return properties common to dependency
956 # build request and target requirements.
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
965 rule common-properties ( build-request requirements )
967 # For optimization, we add free requirements directly, without using a
968 # complex algorithm. This gives the complex algorithm a better chance of
970 local free = [ $(requirements).free ] ;
971 local non-free = [ property-set.create [ $(requirements).base ]
972 [ $(requirements).incidental ] ] ;
974 local key = .rp.$(build-request)-$(non-free) ;
977 $(key) = [ common-properties2 $(build-request) $(non-free) ] ;
979 return [ $($(key)).add-raw $(free) ] ;
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
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
993 # If 'what' is 'refined' returns context refined with new requirements. If
994 # 'what' is 'added' returns just the requirements to be applied.
996 rule evaluate-requirements ( requirements : context : what )
998 # Apply non-conditional requirements. It is possible that further
999 # conditional requirement change a value set by non-conditional
1000 # requirements. For example:
1002 # exe a : a.cpp : <threading>single <toolset>foo:<threading>multi ;
1004 # I am not sure if this should be an error, or not, especially given that
1008 # might come from project's requirements.
1010 local unconditional = [ feature.expand [ $(requirements).non-conditional ] ]
1013 local raw = [ $(context).raw ] ;
1014 raw = [ property.refine $(raw) : $(unconditional) ] ;
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.
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> ]
1030 local added-requirements ;
1032 local current = $(raw) ;
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
1039 local indirect = [ $(requirements).get <conditional> ] ;
1040 indirect = [ MATCH ^@(.*) : $(indirect) ] ;
1045 # Evaluate conditionals in context of current properties.
1046 local e = [ property.evaluate-conditionals-in-context $(conditionals) :
1049 # Evaluate indirect conditionals.
1050 for local i in $(indirect)
1052 local t = [ current ] ;
1053 local p = [ $(t).project ] ;
1054 local new = [ indirect.call $(i) $(current) ] ;
1055 e += [ property.translate-paths $(new) : [ $(p).location ] ] ;
1058 if $(e) = $(added-requirements)
1060 # If we got the same result, we have found the final properties.
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) ] ] ;
1072 count = $(count[2-]) ;
1077 errors.error Can not evaluate conditional properties $(conditionals) ;
1082 return [ property-set.create $(unconditional) $(added-requirements) ] ;
1084 else if $(what) = refined
1086 return [ property-set.create $(current) ] ;
1091 errors.error "Invalid value of the 'what' parameter." ;
1096 rule common-properties2 ( build-request requirements )
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
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
1109 build-request = [ $(build-request).expand ] ;
1111 return [ evaluate-requirements $(requirements) : $(build-request) :
1116 rule push-target ( target )
1118 .targets = $(target) $(.targets) ;
1123 .targets = $(.targets[2-]) ;
1126 # Return the metatarget that is currently being generated.
1129 return $(.targets[1]) ;
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.
1137 class basic-target : abstract-target
1139 import build-request ;
1140 import build-system ;
1141 import "class" : new ;
1144 import property-set ;
1148 import virtual-target ;
1150 rule __init__ ( name : project : sources * : requirements * :
1151 default-build * : usage-requirements * )
1153 abstract-target.__init__ $(name) : $(project) ;
1155 self.sources = $(sources) ;
1156 if ! $(requirements)
1158 requirements = [ property-set.empty ] ;
1160 self.requirements = $(requirements) ;
1161 if ! $(default-build)
1163 default-build = [ property-set.empty ] ;
1165 self.default-build = $(default-build) ;
1166 if ! $(usage-requirements)
1168 usage-requirements = [ property-set.empty ] ;
1170 self.usage-requirements = $(usage-requirements) ;
1174 import errors : user-error : errors.user-error ;
1175 errors.user-error properties found "in" the 'sources' parameter
1176 "for" [ full-name ] ;
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.
1191 if ! $(self.source-targets)
1193 for local s in $(self.sources)
1195 self.source-targets += [ targets.resolve-reference $(s) :
1199 return $(self.source-targets) ;
1202 rule requirements ( )
1204 return $(self.requirements) ;
1207 rule default-build ( )
1209 return $(self.default-build) ;
1212 # Returns the alternative condition for this alternative, if the condition
1213 # is satisfied by 'property-set'.
1215 rule match ( property-set debug ? )
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
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) ] ;
1229 ECHO " next alternative: required properties:"
1230 $(condition:E=(empty)) ;
1233 if $(condition) in [ $(property-set).raw ]
1239 return $(condition) ;
1245 ECHO " not matched" ;
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
1255 # The results are added to the variable called 'result-var'. Usage
1256 # requirements are added to the variable called 'usage-requirements-var'.
1258 rule generate-dependencies ( dependencies * : property-set : result-var
1259 usage-requirements-var )
1261 for local dependency in $(dependencies)
1263 local grist = $(dependency:G) ;
1264 local id = $(dependency:G=) ;
1265 local result = [ targets.generate-from-reference $(id) :
1266 $(self.project) : $(property-set) ] ;
1268 $(result-var) += $(result[2-]:G=$(grist)) ;
1269 $(usage-requirements-var) += [ $(result[1]).raw ] ;
1273 # Determines final build properties, generates sources, and calls
1274 # 'construct'. This method should not be overridden.
1276 rule generate ( property-set )
1278 if [ modules.peek : .debug-building ]
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 ] ;
1291 targets.push-target $(__name__) ;
1293 # Apply free features from the command line. If user said
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 ] ] ;
1300 if ! $(self.generated.$(property-set))
1302 local rproperties = [ targets.common-properties $(property-set)
1303 $(self.requirements) ] ;
1305 if [ modules.peek : .debug-building ]
1308 ECHO [ targets.indent ] "Common properties: "
1309 [ $(rproperties).raw ] ;
1312 if ( $(rproperties[1]) != "@error" ) && ( [ $(rproperties).get
1315 local source-targets ;
1316 local properties = [ $(rproperties).non-dependency ] ;
1317 local usage-requirements ;
1319 generate-dependencies [ $(rproperties).dependency ] :
1320 $(rproperties) : properties usage-requirements ;
1322 generate-dependencies $(self.sources) : $(rproperties) :
1323 source-targets usage-requirements ;
1325 if [ modules.peek : .debug-building ]
1328 ECHO [ targets.indent ] "Usage requirements for"
1329 $(self.name)": " $(usage-requirements) ;
1332 rproperties = [ property-set.create $(properties)
1333 $(usage-requirements) ] ;
1334 usage-requirements = [ property-set.create $(usage-requirements)
1337 if [ modules.peek : .debug-building ]
1339 ECHO [ targets.indent ] "Build properties: "
1340 [ $(rproperties).raw ] ;
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 ]
1352 local result = [ construct $(self.name) : $(source-targets) :
1357 local gur = $(result[1]) ;
1358 result = $(result[2-]) ;
1362 for local t in $(result)
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 ;
1374 local ur = [ compute-usage-requirements $(s) ] ;
1375 ur = [ $(ur).add $(gur) ] ;
1376 $(s).set-usage-requirements $(ur) ;
1377 if [ modules.peek : .debug-building ]
1379 ECHO [ targets.indent ] "Usage requirements from"
1380 $(self.name)": " [ $(ur).raw ] ;
1383 self.generated.$(property-set) = $(ur) $(result) ;
1388 if $(rproperties[1]) = "@error"
1390 ECHO [ targets.indent ] "Skipping build of:" [ full-name ]
1391 "cannot compute common properties" ;
1393 else if [ $(rproperties).get <build> ] = no
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.
1402 ECHO [ targets.indent ] "Skipping build of: " [ full-name ]
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
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
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
1419 self.generated.$(property-set) = [ property-set.create <build>no
1425 if [ modules.peek : .debug-building ]
1427 ECHO [ targets.indent ] "Already built" ;
1428 local ur = $(self.generated.$(property-set)) ;
1430 targets.increase-indent ;
1431 ECHO [ targets.indent ] "Usage requirements from"
1432 $(self.name)": " [ $(ur).raw ] ;
1433 targets.decrease-indent ;
1437 targets.pop-target ;
1438 targets.decrease-indent ;
1439 return $(self.generated.$(property-set)) ;
1442 # Given the set of generated targets, and refined build properties,
1443 # determines and sets appropriate usage requirements on those targets.
1445 rule compute-usage-requirements ( subvariant )
1447 local rproperties = [ $(subvariant).build-properties ] ;
1448 xusage-requirements = [ targets.evaluate-requirements
1449 $(self.usage-requirements) : $(rproperties) : added ] ;
1451 # We generate all dependency properties and add them, as well as their
1452 # usage requirements, to the result.
1454 generate-dependencies [ $(xusage-requirements).dependency ] :
1455 $(rproperties) : extra extra ;
1457 local result = [ property-set.create
1458 [ $(xusage-requirements).non-dependency ] $(extra) ] ;
1460 # Propagate usage requirements we got from sources, except for the
1461 # <pch-header> and <pch-file> features.
1463 # That feature specifies which pch file to use, and should apply only to
1464 # direct dependents. Consider:
1467 # lib lib1 : ..... pch1 ;
1469 # lib lib2 : pch2 lib1 ;
1471 # Here, lib2 should not get <pch-header> property from pch1.
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.
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
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) ] ] ;
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
1495 local rule create-subvariant ( root-targets * : all-targets * :
1496 build-request : sources * : rproperties : usage-requirements )
1498 for local e in $(root-targets)
1503 # Process all virtual targets that will be created if this main target
1505 local s = [ new subvariant $(__name__) : $(build-request) : $(sources) :
1506 $(rproperties) : $(usage-requirements) : $(all-targets) ] ;
1507 for local v in $(all-targets)
1509 if ! [ $(v).creating-subvariant ]
1511 $(v).creating-subvariant $(s) ;
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.
1521 rule construct ( name : source-targets * : properties * )
1523 import errors : error : errors.error ;
1524 errors.error "method should be defined in derived classes" ;
1529 class typed-target : basic-target
1533 rule __init__ ( name : project : type : sources * : requirements * :
1534 default-build * : usage-requirements * )
1536 basic-target.__init__ $(name) : $(project) : $(sources) :
1537 $(requirements) : $(default-build) : $(usage-requirements) ;
1539 self.type = $(type) ;
1544 return $(self.type) ;
1547 rule construct ( name : source-targets * : property-set )
1549 local r = [ generators.construct $(self.project) $(name:S=)
1551 : [ property-set.create [ $(property-set).raw ]
1552 <main-target-type>$(self.type) ]
1553 : $(source-targets) : true ] ;
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)
1564 ECHO "WARNING:" [ $(gen).id ]
1565 "with source types {" [ $(gen).source-types ] "}"
1566 "and requirements {" [ $(gen).requirements ] "}" ;
1569 # Are there any top-level generators for this type/property set.
1570 if ! [ generators.find-viable-generators $(self.type) :
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."
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.
1592 rule main-target-sources ( sources * : main-target-name : no-renaming ? )
1595 for local t in $(sources)
1597 if [ class.is-instance $(t) ]
1599 local name = [ $(t).name ] ;
1602 name = $(main-target-name)__$(name) ;
1603 $(t).rename $(name) ;
1605 # Inline targets are not built by default.
1606 local p = [ $(t).project ] ;
1607 $(p).mark-target-as-explicit $(name) ;
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.
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.
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"
1634 errors.error "Conflicting requirements for target:" $(requirements) ;
1636 return [ $(requirements).add [ toolset.requirements ] ] ;
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.
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.
1649 local project-usage-requirements = [ $(project).get usage-requirements ] ;
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
1655 local usage-requirements = [ property-set.create-from-user-input
1657 : [ $(project).project-module ] [ $(project).get location ] ] ;
1659 return [ $(project-usage-requirements).add $(usage-requirements) ] ;
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.
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.
1675 result = $(specification) ;
1679 result = [ $(project).get default-build ] ;
1681 return [ property-set.create-with-validation $(result) ] ;
1685 # Registers the specified target as a main target alternative and returns it.
1687 rule main-target-alternative ( target )
1689 local ptarget = [ $(target).project ] ;
1690 $(ptarget).add-alternative $(target) ;
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'.
1700 rule create-metatarget ( klass : project : name : sources * : requirements * :
1701 default-build * : usage-requirements * )
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) :
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'.
1716 rule create-typed-target ( type : project : name : sources * : requirements * :
1717 default-build * : usage-requirements * )
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) :