summaryrefslogtreecommitdiff
path: root/jam-files/boost-build/build/virtual_target.py
diff options
context:
space:
mode:
authorKenneth Heafield <github@kheafield.com>2012-10-22 12:07:20 +0100
committerKenneth Heafield <github@kheafield.com>2012-10-22 12:07:20 +0100
commitac586bc9b156b4ae687cd5961ba1fe7b20ec57d6 (patch)
tree052473b46d7fa18d51f897cdb9e7c93a7186dafd /jam-files/boost-build/build/virtual_target.py
parent97b85c082b3e55c28a8b0c0eb762483ac84a1577 (diff)
parentad6d4a1b2519896f2b16a282699ce4e64041fab8 (diff)
Merge remote branch 'upstream/master'
Conflicts: Jamroot bjam decoder/Jamfile decoder/cdec.cc dpmert/Jamfile jam-files/sanity.jam klm/lm/Jamfile klm/util/Jamfile mira/Jamfile
Diffstat (limited to 'jam-files/boost-build/build/virtual_target.py')
-rw-r--r--jam-files/boost-build/build/virtual_target.py1118
1 files changed, 0 insertions, 1118 deletions
diff --git a/jam-files/boost-build/build/virtual_target.py b/jam-files/boost-build/build/virtual_target.py
deleted file mode 100644
index 51dff037..00000000
--- a/jam-files/boost-build/build/virtual_target.py
+++ /dev/null
@@ -1,1118 +0,0 @@
-# Status: ported.
-# Base revision: 64488.
-#
-# Copyright (C) Vladimir Prus 2002. Permission to copy, use, modify, sell and
-# distribute this software is granted provided this copyright notice appears in
-# all copies. This software is provided "as is" without express or implied
-# warranty, and with no claim as to its suitability for any purpose.
-
-# Implements virtual targets, which correspond to actual files created during
-# build, but are not yet targets in Jam sense. They are needed, for example,
-# when searching for possible transormation sequences, when it's not known
-# if particular target should be created at all.
-#
-#
-# +--------------------------+
-# | VirtualTarget |
-# +==========================+
-# | actualize |
-# +--------------------------+
-# | actualize_action() = 0 |
-# | actualize_location() = 0 |
-# +----------------+---------+
-# |
-# ^
-# / \
-# +-+-+
-# |
-# +---------------------+ +-------+--------------+
-# | Action | | AbstractFileTarget |
-# +=====================| * +======================+
-# | action_name | +--+ action |
-# | properties | | +----------------------+
-# +---------------------+--+ | actualize_action() |
-# | actualize() |0..1 +-----------+----------+
-# | path() | |
-# | adjust_properties() | sources |
-# | actualize_sources() | targets |
-# +------+--------------+ ^
-# | / \
-# ^ +-+-+
-# / \ |
-# +-+-+ +-------------+-------------+
-# | | |
-# | +------+---------------+ +--------+-------------+
-# | | FileTarget | | SearchedLibTarget |
-# | +======================+ +======================+
-# | | actualize-location() | | actualize-location() |
-# | +----------------------+ +----------------------+
-# |
-# +-+------------------------------+
-# | |
-# +----+----------------+ +---------+-----------+
-# | CompileAction | | LinkAction |
-# +=====================+ +=====================+
-# | adjust_properties() | | adjust_properties() |
-# +---------------------+ | actualize_sources() |
-# +---------------------+
-#
-# The 'CompileAction' and 'LinkAction' classes are defined not here,
-# but in builtin.jam modules. They are shown in the diagram to give
-# the big picture.
-
-import bjam
-
-import re
-import os.path
-import string
-import types
-
-from b2.util import path, utility, set
-from b2.util.utility import add_grist, get_grist, ungrist, replace_grist, get_value
-from b2.util.sequence import unique
-from b2.tools import common
-from b2.exceptions import *
-import b2.build.type
-import b2.build.property_set as property_set
-
-import b2.build.property as property
-
-from b2.manager import get_manager
-from b2.util import bjam_signature
-
-__re_starts_with_at = re.compile ('^@(.*)')
-
-class VirtualTargetRegistry:
- def __init__ (self, manager):
- self.manager_ = manager
-
- # A cache for FileTargets
- self.files_ = {}
-
- # A cache for targets.
- self.cache_ = {}
-
- # A map of actual names to virtual targets.
- # Used to make sure we don't associate same
- # actual target to two virtual targets.
- self.actual_ = {}
-
- self.recent_targets_ = []
-
- # All targets ever registed
- self.all_targets_ = []
-
- self.next_id_ = 0
-
- def register (self, target):
- """ Registers a new virtual target. Checks if there's already registered target, with the same
- name, type, project and subvariant properties, and also with the same sources
- and equal action. If such target is found it is retured and 'target' is not registered.
- Otherwise, 'target' is registered and returned.
- """
- if target.path():
- signature = target.path() + "-" + target.name()
- else:
- signature = "-" + target.name()
-
- result = None
- if not self.cache_.has_key (signature):
- self.cache_ [signature] = []
-
- for t in self.cache_ [signature]:
- a1 = t.action ()
- a2 = target.action ()
-
- # TODO: why are we checking for not result?
- if not result:
- if not a1 and not a2:
- result = t
- else:
- if a1 and a2 and a1.action_name () == a2.action_name () and a1.sources () == a2.sources ():
- ps1 = a1.properties ()
- ps2 = a2.properties ()
- p1 = ps1.base () + ps1.free () +\
- b2.util.set.difference(ps1.dependency(), ps1.incidental())
- p2 = ps2.base () + ps2.free () +\
- b2.util.set.difference(ps2.dependency(), ps2.incidental())
- if p1 == p2:
- result = t
-
- if not result:
- self.cache_ [signature].append (target)
- result = target
-
- # TODO: Don't append if we found pre-existing target?
- self.recent_targets_.append(result)
- self.all_targets_.append(result)
-
- return result
-
- def from_file (self, file, file_location, project):
- """ Creates a virtual target with appropriate name and type from 'file'.
- If a target with that name in that project was already created, returns that already
- created target.
- TODO: more correct way would be to compute path to the file, based on name and source location
- for the project, and use that path to determine if the target was already created.
- TODO: passing project with all virtual targets starts to be annoying.
- """
- # Check if we've created a target corresponding to this file.
- path = os.path.join(os.getcwd(), file_location, file)
- path = os.path.normpath(path)
-
- if self.files_.has_key (path):
- return self.files_ [path]
-
- file_type = b2.build.type.type (file)
-
- result = FileTarget (file, file_type, project,
- None, file_location)
- self.files_ [path] = result
-
- return result
-
- def recent_targets(self):
- """Each target returned by 'register' is added to a list of
- 'recent-target', returned by this function. So, this allows
- us to find all targets created when building a given main
- target, even if the target."""
-
- return self.recent_targets_
-
- def clear_recent_targets(self):
- self.recent_targets_ = []
-
- def all_targets(self):
- # Returns all virtual targets ever created
- return self.all_targets_
-
- # Returns all targets from 'targets' with types
- # equal to 'type' or derived from it.
- def select_by_type(self, type, targets):
- return [t for t in targets if b2.build.type.is_sybtype(t.type(), type)]
-
- def register_actual_name (self, actual_name, virtual_target):
- if self.actual_.has_key (actual_name):
- cs1 = self.actual_ [actual_name].creating_subvariant ()
- cs2 = virtual_target.creating_subvariant ()
- cmt1 = cs1.main_target ()
- cmt2 = cs2.main_target ()
-
- action1 = self.actual_ [actual_name].action ()
- action2 = virtual_target.action ()
-
- properties_added = []
- properties_removed = []
- if action1 and action2:
- p1 = action1.properties ()
- p1 = p1.raw ()
- p2 = action2.properties ()
- p2 = p2.raw ()
-
- properties_removed = set.difference (p1, p2)
- if not properties_removed: properties_removed = "none"
-
- properties_added = set.difference (p2, p1)
- if not properties_added: properties_added = "none"
-
- # FIXME: Revive printing of real location.
- get_manager().errors()(
- "Duplicate name of actual target: '%s'\n"
- "previous virtual target '%s'\n"
- "created from '%s'\n"
- "another virtual target '%s'\n"
- "created from '%s'\n"
- "added properties: '%s'\n"
- "removed properties: '%s'\n"
- % (actual_name,
- self.actual_ [actual_name], "loc", #cmt1.location (),
- virtual_target,
- "loc", #cmt2.location (),
- properties_added, properties_removed))
-
- else:
- self.actual_ [actual_name] = virtual_target
-
-
- def add_suffix (self, specified_name, file_type, prop_set):
- """ Appends the suffix appropriate to 'type/property_set' combination
- to the specified name and returns the result.
- """
- suffix = b2.build.type.generated_target_suffix (file_type, prop_set)
-
- if suffix:
- return specified_name + '.' + suffix
-
- else:
- return specified_name
-
-class VirtualTarget:
- """ Potential target. It can be converted into jam target and used in
- building, if needed. However, it can be also dropped, which allows
- to search for different transformation and select only one.
- name: name of this target.
- project: project to which this target belongs.
- """
- def __init__ (self, name, project):
- self.name_ = name
- self.project_ = project
- self.dependencies_ = []
- self.always_ = False
-
- # Caches if dapendencies for scanners have already been set.
- self.made_ = {}
-
- def manager(self):
- return self.project_.manager()
-
- def virtual_targets(self):
- return self.manager().virtual_targets()
-
- def name (self):
- """ Name of this target.
- """
- return self.name_
-
- def project (self):
- """ Project of this target.
- """
- return self.project_
-
- def depends (self, d):
- """ Adds additional instances of 'VirtualTarget' that this
- one depends on.
- """
- self.dependencies_ = unique (self.dependencies_ + d).sort ()
-
- def dependencies (self):
- return self.dependencies_
-
- def always(self):
- self.always_ = True
-
- def actualize (self, scanner = None):
- """ Generates all the actual targets and sets up build actions for
- this target.
-
- If 'scanner' is specified, creates an additional target
- with the same location as actual target, which will depend on the
- actual target and be associated with 'scanner'. That additional
- target is returned. See the docs (#dependency_scanning) for rationale.
- Target must correspond to a file if 'scanner' is specified.
-
- If scanner is not specified, then actual target is returned.
- """
- actual_name = self.actualize_no_scanner ()
-
- if self.always_:
- bjam.call("ALWAYS", actual_name)
-
- if not scanner:
- return actual_name
-
- else:
- # Add the scanner instance to the grist for name.
- g = '-'.join ([ungrist(get_grist(actual_name)), str(id(scanner))])
-
- name = replace_grist (actual_name, '<' + g + '>')
-
- if not self.made_.has_key (name):
- self.made_ [name] = True
-
- self.project_.manager ().engine ().add_dependency (name, actual_name)
-
- self.actualize_location (name)
-
- self.project_.manager ().scanners ().install (scanner, name, str (self))
-
- return name
-
-# private: (overridables)
-
- def actualize_action (self, target):
- """ Sets up build actions for 'target'. Should call appropriate rules
- and set target variables.
- """
- raise BaseException ("method should be defined in derived classes")
-
- def actualize_location (self, target):
- """ Sets up variables on 'target' which specify its location.
- """
- raise BaseException ("method should be defined in derived classes")
-
- def path (self):
- """ If the target is generated one, returns the path where it will be
- generated. Otherwise, returns empty list.
- """
- raise BaseException ("method should be defined in derived classes")
-
- def actual_name (self):
- """ Return that actual target name that should be used
- (for the case where no scanner is involved)
- """
- raise BaseException ("method should be defined in derived classes")
-
-
-class AbstractFileTarget (VirtualTarget):
- """ Target which correspond to a file. The exact mapping for file
- is not yet specified in this class. (TODO: Actually, the class name
- could be better...)
-
- May be a source file (when no action is specified), or
- derived file (otherwise).
-
- The target's grist is concatenation of project's location,
- properties of action (for derived files), and, optionally,
- value identifying the main target.
-
- exact: If non-empty, the name is exactly the name
- created file should have. Otherwise, the '__init__'
- method will add suffix obtained from 'type' by
- calling 'type.generated-target-suffix'.
-
- type: optional type of this target.
- """
- def __init__ (self, name, type, project, action = None, exact=False):
- VirtualTarget.__init__ (self, name, project)
-
- self.type_ = type
-
- self.action_ = action
- self.exact_ = exact
-
- if action:
- action.add_targets ([self])
-
- if self.type and not exact:
- self.__adjust_name (name)
-
-
- self.actual_name_ = None
- self.path_ = None
- self.intermediate_ = False
- self.creating_subvariant_ = None
-
- # True if this is a root target.
- self.root_ = False
-
- def type (self):
- return self.type_
-
- def set_path (self, path):
- """ Sets the path. When generating target name, it will override any path
- computation from properties.
- """
- self.path_ = path
-
- def action (self):
- """ Returns the action.
- """
- return self.action_
-
- def root (self, set = None):
- """ Sets/gets the 'root' flag. Target is root is it directly correspods to some
- variant of a main target.
- """
- if set:
- self.root_ = True
- return self.root_
-
- def creating_subvariant (self, s = None):
- """ Gets or sets the subvariant which created this target. Subvariant
- is set when target is brought into existance, and is never changed
- after that. In particual, if target is shared by subvariant, only
- the first is stored.
- s: If specified, specified the value to set,
- which should be instance of 'subvariant' class.
- """
- if s and not self.creating_subvariant ():
- if self.creating_subvariant ():
- raise BaseException ("Attempt to change 'dg'")
-
- else:
- self.creating_subvariant_ = s
-
- return self.creating_subvariant_
-
- def actualize_action (self, target):
- if self.action_:
- self.action_.actualize ()
-
- # Return a human-readable representation of this target
- #
- # If this target has an action, that's:
- #
- # { <action-name>-<self.name>.<self.type> <action-sources>... }
- #
- # otherwise, it's:
- #
- # { <self.name>.<self.type> }
- #
- def str(self):
- a = self.action()
-
- name_dot_type = self.name_ + "." + self.type_
-
- if a:
- action_name = a.action_name()
- ss = [ s.str() for s in a.sources()]
-
- return "{ %s-%s %s}" % (action_name, name_dot_type, str(ss))
- else:
- return "{ " + name_dot_type + " }"
-
-# private:
-
- def actual_name (self):
- if not self.actual_name_:
- self.actual_name_ = '<' + self.grist() + '>' + self.name_
-
- return self.actual_name_
-
- def grist (self):
- """Helper to 'actual_name', above. Compute unique prefix used to distinguish
- this target from other targets with the same name which create different
- file.
- """
- # Depending on target, there may be different approaches to generating
- # unique prefixes. We'll generate prefixes in the form
- # <one letter approach code> <the actual prefix>
- path = self.path ()
-
- if path:
- # The target will be generated to a known path. Just use the path
- # for identification, since path is as unique as it can get.
- return 'p' + path
-
- else:
- # File is either source, which will be searched for, or is not a file at
- # all. Use the location of project for distinguishing.
- project_location = self.project_.get ('location')
- path_components = b2.util.path.split(project_location)
- location_grist = '!'.join (path_components)
-
- if self.action_:
- ps = self.action_.properties ()
- property_grist = ps.as_path ()
- # 'property_grist' can be empty when 'ps' is an empty
- # property set.
- if property_grist:
- location_grist = location_grist + '/' + property_grist
-
- return 'l' + location_grist
-
- def __adjust_name(self, specified_name):
- """Given the target name specified in constructor, returns the
- name which should be really used, by looking at the <tag> properties.
- The tag properties come in two flavour:
- - <tag>value,
- - <tag>@rule-name
- In the first case, value is just added to name
- In the second case, the specified rule is called with specified name,
- target type and properties and should return the new name.
- If not <tag> property is specified, or the rule specified by
- <tag> returns nothing, returns the result of calling
- virtual-target.add-suffix"""
-
- if self.action_:
- ps = self.action_.properties()
- else:
- ps = property_set.empty()
-
- # FIXME: I'm not sure how this is used, need to check with
- # Rene to figure out how to implement
- #~ We add ourselves to the properties so that any tag rule can get
- #~ more direct information about the target than just that available
- #~ through the properties. This is useful in implementing
- #~ name changes based on the sources of the target. For example to
- #~ make unique names of object files based on the source file.
- #~ --grafik
- #ps = property_set.create(ps.raw() + ["<target>%s" % "XXXX"])
- #ps = [ property-set.create [ $(ps).raw ] <target>$(__name__) ] ;
-
- tag = ps.get("<tag>")
-
- if tag:
-
- if len(tag) > 1:
- get_manager().errors()(
- """<tag>@rulename is present but is not the only <tag> feature""")
-
- tag = tag[0]
- if callable(tag):
- self.name_ = tag(specified_name, self.type_, ps)
- else:
- if not tag[0] == '@':
- self.manager_.errors()("""The value of the <tag> feature must be '@rule-nane'""")
-
- exported_ps = b2.util.value_to_jam(ps, methods=True)
- self.name_ = b2.util.call_jam_function(
- tag[1:], specified_name, self.type_, exported_ps)
- if self.name_:
- self.name_ = self.name_[0]
-
- # If there's no tag or the tag rule returned nothing.
- if not tag or not self.name_:
- self.name_ = add_prefix_and_suffix(specified_name, self.type_, ps)
-
- def actualize_no_scanner(self):
- name = self.actual_name()
-
- # Do anything only on the first invocation
- if not self.made_:
- self.made_[name] = True
-
- if self.action_:
- # For non-derived target, we don't care if there
- # are several virtual targets that refer to the same name.
- # One case when this is unavoidable is when file name is
- # main.cpp and two targets have types CPP (for compiling)
- # and MOCCABLE_CPP (for convertion to H via Qt tools).
- self.virtual_targets().register_actual_name(name, self)
-
- for i in self.dependencies_:
- self.manager_.engine().add_dependency(name, i.actualize())
-
- self.actualize_location(name)
- self.actualize_action(name)
-
- return name
-
-@bjam_signature((["specified_name"], ["type"], ["property_set"]))
-def add_prefix_and_suffix(specified_name, type, property_set):
- """Appends the suffix appropriate to 'type/property-set' combination
- to the specified name and returns the result."""
-
- property_set = b2.util.jam_to_value_maybe(property_set)
-
- suffix = ""
- if type:
- suffix = b2.build.type.generated_target_suffix(type, property_set)
-
- # Handle suffixes for which no leading dot is desired. Those are
- # specified by enclosing them in <...>. Needed by python so it
- # can create "_d.so" extensions, for example.
- if get_grist(suffix):
- suffix = ungrist(suffix)
- elif suffix:
- suffix = "." + suffix
-
- prefix = ""
- if type:
- prefix = b2.build.type.generated_target_prefix(type, property_set)
-
- if specified_name.startswith(prefix):
- prefix = ""
-
- if not prefix:
- prefix = ""
- if not suffix:
- suffix = ""
- return prefix + specified_name + suffix
-
-
-class FileTarget (AbstractFileTarget):
- """ File target with explicitly known location.
-
- The file path is determined as
- - value passed to the 'set_path' method, if any
- - for derived files, project's build dir, joined with components
- that describe action's properties. If the free properties
- are not equal to the project's reference properties
- an element with name of main target is added.
- - for source files, project's source dir
-
- The file suffix is
- - the value passed to the 'suffix' method, if any, or
- - the suffix which correspond to the target's type.
- """
- def __init__ (self, name, type, project, action = None, path=None, exact=False):
- AbstractFileTarget.__init__ (self, name, type, project, action, exact)
-
- self.path_ = path
-
- def __str__(self):
- if self.type_:
- return self.name_ + "." + self.type_
- else:
- return self.name_
-
- def clone_with_different_type(self, new_type):
- return FileTarget(self.name_, new_type, self.project_,
- self.action_, self.path_, exact=True)
-
- def actualize_location (self, target):
- engine = self.project_.manager_.engine ()
-
- if self.action_:
- # This is a derived file.
- path = self.path ()
- engine.set_target_variable (target, 'LOCATE', path)
-
- # Make sure the path exists.
- engine.add_dependency (target, path)
- common.mkdir(engine, path)
-
- # It's possible that the target name includes a directory
- # too, for example when installing headers. Create that
- # directory.
- d = os.path.dirname(get_value(target))
- if d:
- d = os.path.join(path, d)
- engine.add_dependency(target, d)
- common.mkdir(engine, d)
-
- # For real file target, we create a fake target that
- # depends on the real target. This allows to run
- #
- # bjam hello.o
- #
- # without trying to guess the name of the real target.
- # Note the that target has no directory name, and a special
- # grist <e>.
- #
- # First, that means that "bjam hello.o" will build all
- # known hello.o targets.
- # Second, the <e> grist makes sure this target won't be confused
- # with other targets, for example, if we have subdir 'test'
- # with target 'test' in it that includes 'test.o' file,
- # then the target for directory will be just 'test' the target
- # for test.o will be <ptest/bin/gcc/debug>test.o and the target
- # we create below will be <e>test.o
- engine.add_dependency("<e>%s" % get_value(target), target)
-
- # Allow bjam <path-to-file>/<file> to work. This won't catch all
- # possible ways to refer to the path (relative/absolute, extra ".",
- # various "..", but should help in obvious cases.
- engine.add_dependency("<e>%s" % (os.path.join(path, get_value(target))), target)
-
- else:
- # This is a source file.
- engine.set_target_variable (target, 'SEARCH', self.project_.get ('source-location'))
-
-
- def path (self):
- """ Returns the directory for this target.
- """
- if not self.path_:
- if self.action_:
- p = self.action_.properties ()
- (target_path, relative_to_build_dir) = p.target_path ()
-
- if relative_to_build_dir:
- # Indicates that the path is relative to
- # build dir.
- target_path = os.path.join (self.project_.build_dir (), target_path)
-
- # Store the computed path, so that it's not recomputed
- # any more
- self.path_ = target_path
-
- return self.path_
-
-
-class NotFileTarget(AbstractFileTarget):
-
- def __init__(self, name, project, action):
- AbstractFileTarget.__init__(self, name, None, project, action)
-
- def path(self):
- """Returns nothing, to indicate that target path is not known."""
- return None
-
- def actualize_location(self, target):
- bjam.call("NOTFILE", target)
- bjam.call("ALWAYS", target)
- bjam.call("NOUPDATE", target)
-
-
-class Action:
- """ Class which represents an action.
- Both 'targets' and 'sources' should list instances of 'VirtualTarget'.
- Action name should name a rule with this prototype
- rule action_name ( targets + : sources * : properties * )
- Targets and sources are passed as actual jam targets. The rule may
- not establish dependency relationship, but should do everything else.
- """
- def __init__ (self, manager, sources, action_name, prop_set):
- assert(isinstance(prop_set, property_set.PropertySet))
- assert type(sources) == types.ListType
- self.sources_ = sources
- self.action_name_ = action_name
- if not prop_set:
- prop_set = property_set.empty()
- self.properties_ = prop_set
- if not all(isinstance(v, VirtualTarget) for v in prop_set.get('implicit-dependency')):
- import pdb
- pdb.set_trace()
-
- self.manager_ = manager
- self.engine_ = self.manager_.engine ()
- self.targets_ = []
-
- # Indicates whether this has been actualized or not.
- self.actualized_ = False
-
- self.dependency_only_sources_ = []
- self.actual_sources_ = []
-
-
- def add_targets (self, targets):
- self.targets_ += targets
-
-
- def replace_targets (old_targets, new_targets):
- self.targets_ = [t for t in targets if not t in old_targets] + new_targets
-
- def targets (self):
- return self.targets_
-
- def sources (self):
- return self.sources_
-
- def action_name (self):
- return self.action_name_
-
- def properties (self):
- return self.properties_
-
- def actualize (self):
- """ Generates actual build instructions.
- """
- if self.actualized_:
- return
-
- self.actualized_ = True
-
- ps = self.properties ()
- properties = self.adjust_properties (ps)
-
-
- actual_targets = []
-
- for i in self.targets ():
- actual_targets.append (i.actualize ())
-
- self.actualize_sources (self.sources (), properties)
-
- self.engine_.add_dependency (actual_targets, self.actual_sources_ + self.dependency_only_sources_)
-
- # This works around a bug with -j and actions that
- # produce multiple target, where:
- # - dependency on the first output is found, and
- # the action is started
- # - dependency on the second output is found, and
- # bjam noticed that command is already running
- # - instead of waiting for the command, dependents
- # of the second targets are immediately updated.
- if len(actual_targets) > 1:
- bjam.call("INCLUDES", actual_targets, actual_targets)
-
- # FIXME: check the comment below. Was self.action_name_ [1]
- # Action name can include additional argument to rule, which should not
- # be passed to 'set-target-variables'
- # FIXME: breaking circular dependency
- import toolset
- toolset.set_target_variables (self.manager_, self.action_name_, actual_targets, properties)
-
- engine = self.manager_.engine ()
-
- # FIXME: this is supposed to help --out-xml option, but we don't
- # implement that now, and anyway, we should handle it in Python,
- # not but putting variables on bjam-level targets.
- bjam.call("set-target-variable", actual_targets, ".action", repr(self))
-
- self.manager_.engine ().set_update_action (self.action_name_, actual_targets, self.actual_sources_,
- properties)
-
- # Since we set up creating action here, we also set up
- # action for cleaning up
- self.manager_.engine ().set_update_action ('common.Clean', 'clean-all',
- actual_targets)
-
- return actual_targets
-
- def actualize_source_type (self, sources, prop_set):
- """ Helper for 'actualize_sources'.
- For each passed source, actualizes it with the appropriate scanner.
- Returns the actualized virtual targets.
- """
- result = []
- for i in sources:
- scanner = None
-
-# FIXME: what's this?
-# if isinstance (i, str):
-# i = self.manager_.get_object (i)
-
- if i.type ():
- scanner = b2.build.type.get_scanner (i.type (), prop_set)
-
- r = i.actualize (scanner)
- result.append (r)
-
- return result
-
- def actualize_sources (self, sources, prop_set):
- """ Creates actual jam targets for sources. Initializes two member
- variables:
- 'self.actual_sources_' -- sources which are passed to updating action
- 'self.dependency_only_sources_' -- sources which are made dependencies, but
- are not used otherwise.
-
- New values will be *appended* to the variables. They may be non-empty,
- if caller wants it.
- """
- dependencies = self.properties_.get ('<dependency>')
-
- self.dependency_only_sources_ += self.actualize_source_type (dependencies, prop_set)
- self.actual_sources_ += self.actualize_source_type (sources, prop_set)
-
- # This is used to help bjam find dependencies in generated headers
- # in other main targets.
- # Say:
- #
- # make a.h : ....... ;
- # exe hello : hello.cpp : <implicit-dependency>a.h ;
- #
- # However, for bjam to find the dependency the generated target must
- # be actualized (i.e. have the jam target). In the above case,
- # if we're building just hello ("bjam hello"), 'a.h' won't be
- # actualized unless we do it here.
- implicit = self.properties_.get("<implicit-dependency>")
-
- for i in implicit:
- i.actualize()
-
- def adjust_properties (self, prop_set):
- """ Determines real properties when trying building with 'properties'.
- This is last chance to fix properties, for example to adjust includes
- to get generated headers correctly. Default implementation returns
- its argument.
- """
- return prop_set
-
-
-class NullAction (Action):
- """ Action class which does nothing --- it produces the targets with
- specific properties out of nowhere. It's needed to distinguish virtual
- targets with different properties that are known to exist, and have no
- actions which create them.
- """
- def __init__ (self, manager, prop_set):
- Action.__init__ (self, manager, [], None, prop_set)
-
- def actualize (self):
- if not self.actualized_:
- self.actualized_ = True
-
- for i in self.targets ():
- i.actualize ()
-
-class NonScanningAction(Action):
- """Class which acts exactly like 'action', except that the sources
- are not scanned for dependencies."""
-
- def __init__(self, sources, action_name, property_set):
- #FIXME: should the manager parameter of Action.__init__
- #be removed? -- Steven Watanabe
- Action.__init__(self, b2.manager.get_manager(), sources, action_name, property_set)
-
- def actualize_source_type(self, sources, property_set):
-
- result = []
- for s in sources:
- result.append(s.actualize())
- return result
-
-def traverse (target, include_roots = False, include_sources = False):
- """ Traverses the dependency graph of 'target' and return all targets that will
- be created before this one is created. If root of some dependency graph is
- found during traversal, it's either included or not, dependencing of the
- value of 'include_roots'. In either case, sources of root are not traversed.
- """
- result = []
-
- if target.action ():
- action = target.action ()
-
- # This includes 'target' as well
- result += action.targets ()
-
- for t in action.sources ():
-
- # FIXME:
- # TODO: see comment in Manager.register_object ()
- #if not isinstance (t, VirtualTarget):
- # t = target.project_.manager_.get_object (t)
-
- if not t.root ():
- result += traverse (t, include_roots, include_sources)
-
- elif include_roots:
- result.append (t)
-
- elif include_sources:
- result.append (target)
-
- return result
-
-def clone_action (action, new_project, new_action_name, new_properties):
- """Takes an 'action' instances and creates new instance of it
- and all produced target. The rule-name and properties are set
- to 'new-rule-name' and 'new-properties', if those are specified.
- Returns the cloned action."""
-
- if not new_action_name:
- new_action_name = action.action_name()
-
- if not new_properties:
- new_properties = action.properties()
-
- cloned_action = action.__class__(action.manager_, action.sources(), new_action_name,
- new_properties)
-
- cloned_targets = []
- for target in action.targets():
-
- n = target.name()
- # Don't modify the name of the produced targets. Strip the directory f
- cloned_target = FileTarget(n, target.type(), new_project,
- cloned_action, exact=True)
-
- d = target.dependencies()
- if d:
- cloned_target.depends(d)
- cloned_target.root(target.root())
- cloned_target.creating_subvariant(target.creating_subvariant())
-
- cloned_targets.append(cloned_target)
-
- return cloned_action
-
-class Subvariant:
-
- def __init__ (self, main_target, prop_set, sources, build_properties, sources_usage_requirements, created_targets):
- """
- main_target: The instance of MainTarget class
- prop_set: Properties requested for this target
- sources:
- build_properties: Actually used properties
- sources_usage_requirements: Properties propagated from sources
- created_targets: Top-level created targets
- """
- self.main_target_ = main_target
- self.properties_ = prop_set
- self.sources_ = sources
- self.build_properties_ = build_properties
- self.sources_usage_requirements_ = sources_usage_requirements
- self.created_targets_ = created_targets
-
- self.usage_requirements_ = None
-
- # Pre-compose the list of other dependency graphs, on which this one
- # depends
- deps = build_properties.get('<implicit-dependency>')
-
- self.other_dg_ = []
- for d in deps:
- self.other_dg_.append(d.creating_subvariant ())
-
- self.other_dg_ = unique (self.other_dg_)
-
- self.implicit_includes_cache_ = {}
- self.target_directories_ = None
-
- def main_target (self):
- return self.main_target_
-
- def created_targets (self):
- return self.created_targets_
-
- def requested_properties (self):
- return self.properties_
-
- def build_properties (self):
- return self.build_properties_
-
- def sources_usage_requirements (self):
- return self.sources_usage_requirements_
-
- def set_usage_requirements (self, usage_requirements):
- self.usage_requirements_ = usage_requirements
-
- def usage_requirements (self):
- return self.usage_requirements_
-
- def all_referenced_targets(self, result):
- """Returns all targets referenced by this subvariant,
- either directly or indirectly, and either as sources,
- or as dependency properties. Targets referred with
- dependency property are returned a properties, not targets."""
-
- # Find directly referenced targets.
- deps = self.build_properties().dependency()
- all_targets = self.sources_ + deps
-
- # Find other subvariants.
- r = []
- for e in all_targets:
- if not e in result:
- result.add(e)
- if isinstance(e, property.Property):
- t = e.value()
- else:
- t = e
-
- # FIXME: how can this be?
- cs = t.creating_subvariant()
- if cs:
- r.append(cs)
- r = unique(r)
- for s in r:
- if s != self:
- s.all_referenced_targets(result)
-
-
- def implicit_includes (self, feature, target_type):
- """ Returns the properties which specify implicit include paths to
- generated headers. This traverses all targets in this subvariant,
- and subvariants referred by <implcit-dependecy>properties.
- For all targets which are of type 'target-type' (or for all targets,
- if 'target_type' is not specified), the result will contain
- <$(feature)>path-to-that-target.
- """
-
- if not target_type:
- key = feature
- else:
- key = feature + "-" + target_type
-
-
- result = self.implicit_includes_cache_.get(key)
- if not result:
- target_paths = self.all_target_directories(target_type)
- target_paths = unique(target_paths)
- result = ["<%s>%s" % (feature, p) for p in target_paths]
- self.implicit_includes_cache_[key] = result
-
- return result
-
- def all_target_directories(self, target_type = None):
- # TODO: does not appear to use target_type in deciding
- # if we've computed this already.
- if not self.target_directories_:
- self.target_directories_ = self.compute_target_directories(target_type)
- return self.target_directories_
-
- def compute_target_directories(self, target_type=None):
- result = []
- for t in self.created_targets():
- if not target_type or b2.build.type.is_derived(t.type(), target_type):
- result.append(t.path())
-
- for d in self.other_dg_:
- result.extend(d.all_target_directories(target_type))
-
- result = unique(result)
- return result