Exemple #1
0
def make_test(target_type, sources, requirements, target_name=None):
    assert isinstance(target_type, basestring)
    assert is_iterable_typed(sources, basestring)
    assert is_iterable_typed(requirements, basestring)
    assert isinstance(target_type, basestring) or target_type is None
    if not target_name:
        target_name = stem(os.path.basename(sources[0]))

    # Having periods (".") in the target name is problematic because the typed
    # generator will strip the suffix and use the bare name for the file
    # targets. Even though the location-prefix averts problems most times it
    # does not prevent ambiguity issues when referring to the test targets. For
    # example when using the XML log output. So we rename the target to remove
    # the periods, and provide an alias for users.
    real_name = target_name.replace(".", "~")

    project = get_manager().projects().current()
    # The <location-prefix> forces the build system for generate paths in the
    # form '$build_dir/array1.test/gcc/debug'. This is necessary to allow
    # post-processing tools to work.
    t = get_manager().targets().create_typed_target(
        type.type_from_rule_name(target_type), project, real_name, sources,
        requirements + ["<location-prefix>" + real_name + ".test"], [], [])

    # The alias to the real target, per period replacement above.
    if real_name != target_name:
        get_manager().projects().project_rules().all_names_["alias"](
            target_name, [t])

    # Remember the test (for --dump-tests). A good way would be to collect all
    # given a project. This has some technical problems: e.g. we can not call
    # this dump from a Jamfile since projects referred by 'build-project' are
    # not available until the whole Jamfile has been loaded.
    __all_tests.append(t)
    return t
Exemple #2
0
 def use_project(self, id, where):
     # See comment in 'load' for explanation why we record the
     # parameters as opposed to loading the project now.
     assert is_iterable_typed(id, basestring)
     assert is_iterable_typed(where, basestring)
     m = self.registry.current().project_module()
     self.registry.used_projects[m].append((id[0], where[0]))
Exemple #3
0
def refine (properties, requirements):
    """ Refines 'properties' by overriding any non-free properties
        for which a different value is specified in 'requirements'.
        Conditional requirements are just added without modification.
        Returns the resulting list of properties.
    """
    assert is_iterable_typed(properties, Property)
    assert is_iterable_typed(requirements, Property)
    # The result has no duplicates, so we store it in a set
    result = set()

    # Records all requirements.
    required = {}

    # All the elements of requirements should be present in the result
    # Record them so that we can handle 'properties'.
    for r in requirements:
        # Don't consider conditional requirements.
        if not r.condition:
            required[r.feature] = r

    for p in properties:
        # Skip conditional properties
        if p.condition:
            result.add(p)
        # No processing for free properties
        elif p.feature.free:
            result.add(p)
        else:
            if p.feature in required:
                result.add(required[p.feature])
            else:
                result.add(p)

    return sequence.unique(list(result) + requirements)
Exemple #4
0
def inherit_generators (toolset, properties, base, generators_to_ignore = []):
    assert isinstance(toolset, basestring)
    assert is_iterable_typed(properties, basestring)
    assert isinstance(base, basestring)
    assert is_iterable_typed(generators_to_ignore, basestring)
    if not properties:
        properties = [replace_grist (toolset, '<toolset>')]

    base_generators = generators.generators_for_toolset(base)

    for g in base_generators:
        id = g.id()

        if not id in generators_to_ignore:
            # Some generator names have multiple periods in their name, so
            # $(id:B=$(toolset)) doesn't generate the right new_id name.
            # e.g. if id = gcc.compile.c++, $(id:B=darwin) = darwin.c++,
            # which is not what we want. Manually parse the base and suffix
            # (if there's a better way to do this, I'd love to see it.)
            # See also register in module generators.
            (base, suffix) = split_action_id(id)

            new_id = toolset + '.' + suffix

            generators.register(g.clone(new_id, properties))
Exemple #5
0
def construct_types (project, name, target_types, prop_set, sources):

    if __debug__:
        from .targets import ProjectTarget
        assert isinstance(project, ProjectTarget)
        assert isinstance(name, basestring) or name is None
        assert is_iterable_typed(target_types, basestring)
        assert isinstance(prop_set, property_set.PropertySet)
        assert is_iterable_typed(sources, virtual_target.VirtualTarget)

    result = []
    usage_requirements = property_set.empty()

    for t in target_types:
        r = construct (project, name, t, prop_set, sources)

        if r:
            (ur, targets) = r
            usage_requirements = usage_requirements.add(ur)
            result.extend(targets)

    # TODO: have to introduce parameter controlling if
    # several types can be matched and add appropriate
    # checks

    # TODO: need to review the documentation for
    # 'construct' to see if it should return $(source) even
    # if nothing can be done with it. Currents docs seem to
    # imply that, contrary to the behaviour.
    if result:
        return (usage_requirements, result)

    else:
        return (usage_requirements, sources)
Exemple #6
0
    def convert_multiple_sources_to_consumable_types (self, project, prop_set, sources):
        """ Converts several files to consumable types.
        """
        consumed = []
        bypassed = []
        if __debug__:
            from .targets import ProjectTarget

            assert isinstance(project, ProjectTarget)
            assert isinstance(prop_set, property_set.PropertySet)
            assert is_iterable_typed(sources, virtual_target.VirtualTarget)

        assert isinstance(project, ProjectTarget)
        assert isinstance(prop_set, property_set.PropertySet)
        assert is_iterable_typed(sources, virtual_target.VirtualTarget)
        # We process each source one-by-one, trying to convert it to
        # a usable type.
        for s in sources:
            # TODO: need to check for failure on each source.
            (c, b) = self.convert_to_consumable_types (project, None, prop_set, [s], True)
            if not c:
                project.manager ().logger ().log (__name__, " failed to convert ", s)

            consumed.extend (c)
            bypassed.extend (b)

        return (consumed, bypassed)
Exemple #7
0
def create (raw_properties = []):
    """ Creates a new 'PropertySet' instance for the given raw properties,
        or returns an already existing one.
    """
    assert (is_iterable_typed(raw_properties, property.Property)
            or is_iterable_typed(raw_properties, basestring))
    # FIXME: propagate to callers.
    if len(raw_properties) > 0 and isinstance(raw_properties[0], property.Property):
        x = raw_properties
    else:
        x = [property.create_from_string(ps) for ps in raw_properties]

    # These two lines of code are optimized to the current state
    # of the Property class. Since this function acts as the caching
    # frontend to the PropertySet class modifying these two lines
    # could have a severe performance penalty. Be careful.
    # It would be faster to sort by p.id, but some projects may rely
    # on the fact that the properties are ordered alphabetically. So,
    # we maintain alphabetical sorting so as to maintain backward compatibility.
    x = sorted(set(x), key=lambda p: (p.feature.name, p.value, p.condition))
    key = tuple(p.id for p in x)

    if key not in __cache:
        __cache [key] = PropertySet(x)

    return __cache [key]
Exemple #8
0
def lib(names, sources=[], requirements=[], default_build=[], usage_requirements=[]):
    """The implementation of the 'lib' rule. Beyond standard syntax that rule allows
    simplified: 'lib a b c ;'."""
    assert is_iterable_typed(names, basestring)
    assert is_iterable_typed(sources, basestring)
    assert is_iterable_typed(requirements, basestring)
    assert is_iterable_typed(default_build, basestring)
    assert is_iterable_typed(usage_requirements, basestring)
    if len(names) > 1:
        if any(r.startswith("<name>") for r in requirements):
            get_manager().errors()(
                "When several names are given to the 'lib' rule\n" + "it is not allowed to specify the <name> feature."
            )

        if sources:
            get_manager().errors()(
                "When several names are given to the 'lib' rule\n" + "it is not allowed to specify sources."
            )

    project = get_manager().projects().current()
    result = []

    for name in names:
        r = requirements[:]

        # Support " lib a ; " and " lib a b c ; " syntax.
        if (
            not sources
            and not any(r.startswith("<name>") for r in requirements)
            and not any(r.startswith("<file") for r in requirements)
        ):
            r.append("<name>" + name)

        result.append(targets.create_typed_metatarget(name, "LIB", sources, r, default_build, usage_requirements))
    return result
Exemple #9
0
def get_invocation_command(toolset, tool, user_provided_command = [],
                           additional_paths = [], path_last = False):
    """ Same as get_invocation_command_nodefault, except that if no tool is found,
        returns either the user-provided-command, if present, or the 'tool' parameter.
    """
    assert isinstance(toolset, basestring)
    assert isinstance(tool, basestring)
    assert is_iterable_typed(user_provided_command, basestring)
    assert is_iterable_typed(additional_paths, basestring) or additional_paths is None
    assert isinstance(path_last, (int, bool))

    result = get_invocation_command_nodefault(toolset, tool,
                                              user_provided_command,
                                              additional_paths,
                                              path_last)

    if not result:
        if user_provided_command:
            result = user_provided_command[0]
        else:
            result = tool

    assert(isinstance(result, str))

    return result
Exemple #10
0
 def constant(self, name, value):
     """Declare and set a project global constant.
     Project global constants are normal variables but should
     not be changed. They are applied to every child Jamfile."""
     assert is_iterable_typed(name, basestring)
     assert is_iterable_typed(value, basestring)
     self.registry.current().add_constant(name[0], value)
Exemple #11
0
def take(attributes, properties):
    """Returns a property set which include all
    properties in 'properties' that have any of 'attributes'."""
    assert is_iterable_typed(attributes, basestring)
    assert is_iterable_typed(properties, basestring)
    result = []
    for e in properties:
        if b2.util.set.intersection(attributes, feature.attributes(get_grist(e))):
            result.append(e)
    return result
Exemple #12
0
 def path_constant(self, name, value):
     """Declare and set a project global constant, whose value is a path. The
     path is adjusted to be relative to the invocation directory. The given
     value path is taken to be either absolute, or relative to this project
     root."""
     assert is_iterable_typed(name, basestring)
     assert is_iterable_typed(value, basestring)
     if len(value) > 1:
         self.registry.manager.error()("path constant should have one element")
     self.registry.current().add_constant(name[0], value[0], path=1)
Exemple #13
0
def capture_output_setup(target, sources, ps):
    if __debug__:
        from ..build.property_set import PropertySet
        assert is_iterable_typed(target, basestring)
        assert is_iterable_typed(sources, basestring)
        assert isinstance(ps, PropertySet)
    run_path_setup(target[0], sources, ps)

    if ps.get('preserve-test-targets') == ['off']:
        bjam.call("set-target-variable", target, "REMOVE_TEST_TARGETS", "1")
Exemple #14
0
 def __init__(self, name, values, attributes):
     assert isinstance(name, basestring)
     assert is_iterable_typed(values, basestring)
     assert is_iterable_typed(attributes, basestring)
     self._name = name
     self._values = values
     self._default = None
     self._attributes = 0
     for a in attributes:
         self._attributes = self._attributes | Feature._attribute_name_to_integer[a]
     self._attributes_string_list = attributes
     self._subfeatures = []
     self._parent = None
Exemple #15
0
def register_type (type, suffixes, base_type = None, os = []):
    """ Register the given type on the specified OSes, or on remaining OSes
        if os is not specified.  This rule is injected into each of the type
        modules for the sake of convenience.
    """
    assert isinstance(type, basestring)
    assert is_iterable_typed(suffixes, basestring)
    assert isinstance(base_type, basestring) or base_type is None
    assert is_iterable_typed(os, basestring)
    if registered (type):
        return

    if not os or os_name () in os:
        register (type, suffixes, base_type)
Exemple #16
0
def alias(name, sources=[], requirements=[], default_build=[], usage_requirements=[]):
    assert isinstance(name, basestring)
    assert is_iterable_typed(sources, basestring)
    assert is_iterable_typed(requirements, basestring)
    assert is_iterable_typed(default_build, basestring)
    assert is_iterable_typed(usage_requirements, basestring)
    project = get_manager().projects().current()
    targets = get_manager().targets()

    targets.main_target_alternative(AliasTarget(
        name, project,
        targets.main_target_sources(sources, name, no_renaming=True),
        targets.main_target_requirements(requirements or [], project),
        targets.main_target_default_build(default_build, project),
        targets.main_target_usage_requirements(usage_requirements or [], project)))
Exemple #17
0
    def conditional(self, condition, requirements):
        """Calculates conditional requirements for multiple requirements
        at once. This is a shorthand to be reduce duplication and to
        keep an inline declarative syntax. For example:

            lib x : x.cpp : [ conditional <toolset>gcc <variant>debug :
                <define>DEBUG_EXCEPTION <define>DEBUG_TRACE ] ;
        """
        assert is_iterable_typed(condition, basestring)
        assert is_iterable_typed(requirements, basestring)
        c = string.join(condition, ",")
        if c.find(":") != -1:
            return [c + r for r in requirements]
        else:
            return [c + ":" + r for r in requirements]
Exemple #18
0
    def generated_targets(self, sources, prop_set, project, name):
        assert is_iterable_typed(sources, virtual_target.VirtualTarget)
        assert isinstance(prop_set, property_set.PropertySet)
        assert isinstance(project, targets.ProjectTarget)
        assert isinstance(name, basestring)
        # sources to pass to inherited rule
        sources2 = []
        # sources which are libraries
        libraries = []

        # Searched libraries are not passed as argument to linker
        # but via some option. So, we pass them to the action
        # via property.
        fsa = []
        fst = []
        for s in sources:
            if type.is_derived(s.type(), "SEARCHED_LIB"):
                n = s.name()
                if s.shared():
                    fsa.append(n)

                else:
                    fst.append(n)

            else:
                sources2.append(s)

        add = []
        if fsa:
            add.append("<find-shared-library>" + "&&".join(fsa))
        if fst:
            add.append("<find-static-library>" + "&&".join(fst))

        spawn = generators.Generator.generated_targets(self, sources2, prop_set.add_raw(add), project, name)
        return spawn
Exemple #19
0
def translate_dependencies(properties, project_id, location):
    assert is_iterable_typed(properties, Property)
    assert isinstance(project_id, basestring)
    assert isinstance(location, basestring)
    result = []
    for p in properties:

        if not p.feature.dependency:
            result.append(p)
        else:
            v = p.value
            m = re.match("(.*)//(.*)", v)
            if m:
                rooted = m.group(1)
                if rooted[0] == '/':
                    # Either project id or absolute Linux path, do nothing.
                    pass
                else:
                    rooted = os.path.join(os.getcwd(), location, rooted)

                result.append(Property(p.feature, rooted + "//" + m.group(2), p.condition))

            elif os.path.isabs(v):
                result.append(p)
            else:
                result.append(Property(p.feature, project_id + "//" + v, p.condition))

    return result
Exemple #20
0
    def construct_result (self, consumed, project, name, prop_set):
        """ Constructs the dependency graph that will be returned by this
            generator.
                consumed:        Already prepared list of consumable targets
                                 If generator requires several source files will contain
                                 exactly len $(self.source_types_) targets with matching types
                                 Otherwise, might contain several targets with the type of
                                 self.source_types_ [0]
                project:
                name:
                prop_set:        Properties to be used for all actions create here
        """
        if __debug__:
            from .targets import ProjectTarget
            assert is_iterable_typed(consumed, virtual_target.VirtualTarget)
            assert isinstance(project, ProjectTarget)
            assert isinstance(name, basestring) or name is None
            assert isinstance(prop_set, property_set.PropertySet)
        result = []
        # If this is 1->1 transformation, apply it to all consumed targets in order.
        if len (self.source_types_) < 2 and not self.composing_:

            for r in consumed:
                result.extend (self.generated_targets ([r], prop_set, project, name))

        else:

            if consumed:
                result.extend (self.generated_targets (consumed, prop_set, project, name))

        return result
Exemple #21
0
    def run_really (self, project, name, prop_set, sources):
        if __debug__:
            from .targets import ProjectTarget
            assert isinstance(project, ProjectTarget)
            # intermediary targets don't have names, so None is possible
            assert isinstance(name, basestring) or name is None
            assert isinstance(prop_set, property_set.PropertySet)
            assert is_iterable_typed(sources, virtual_target.VirtualTarget)
        # consumed: Targets that this generator will consume directly.
        # bypassed: Targets that can't be consumed and will be returned as-is.

        if self.composing_:
            (consumed, bypassed) = self.convert_multiple_sources_to_consumable_types (project, prop_set, sources)
        else:
            (consumed, bypassed) = self.convert_to_consumable_types (project, name, prop_set, sources)

        result = []
        if consumed:
            result = self.construct_result (consumed, project, name, prop_set)
            result.extend (bypassed)

        if result:
            if project.manager ().logger ().on ():
                project.manager ().logger ().log (__name__, "  SUCCESS: ", result)

        else:
                project.manager ().logger ().log (__name__, "  FAILURE")

        return result
Exemple #22
0
    def find_replace(self, properties, value=None):
        assert is_iterable_typed(properties, basestring)
        assert isinstance(value, (basestring, type(None)))
        matches = []
        match_ranks = []

        for i in range(0, len(self.__properties)):
            p = self.__properties[i]

            if b2.util.set.contains (p, properties):
                matches.append (i)
                match_ranks.append(len(p))

        best = sequence.select_highest_ranked (matches, match_ranks)

        if not best:
            return None

        if len (best) > 1:
            raise NoBestMatchingAlternative ()

        best = best [0]

        original = self.__values[best]

        if value:
            self.__values[best] = value

        return original
Exemple #23
0
def try_one_generator (project, name, generator, target_type, properties, sources):
    """ Checks if generator invocation can be pruned, because it's guaranteed
        to fail. If so, quickly returns empty list. Otherwise, calls
        try_one_generator_really.
    """
    if __debug__:
        from .targets import ProjectTarget
        assert isinstance(project, ProjectTarget)
        assert isinstance(name, basestring) or name is None
        assert isinstance(generator, Generator)
        assert isinstance(target_type, basestring)
        assert isinstance(properties, property_set.PropertySet)
        assert is_iterable_typed(sources, virtual_target.VirtualTarget)
    source_types = []

    for s in sources:
        source_types.append (s.type ())

    viable_source_types = viable_source_types_for_generator (generator)

    if source_types and viable_source_types != ['*'] and\
           not set_.intersection (source_types, viable_source_types):
        if project.manager ().logger ().on ():
            id = generator.id ()
            project.manager ().logger ().log (__name__, "generator '%s' pruned" % id)
            project.manager ().logger ().log (__name__, "source_types" '%s' % source_types)
            project.manager ().logger ().log (__name__, "viable_source_types '%s'" % viable_source_types)

        return []

    else:
        return try_one_generator_really (project, name, generator, target_type, properties, sources)
Exemple #24
0
    def run(self, project, name, prop_set, sources):
        assert isinstance(project, targets.ProjectTarget)
        assert isinstance(name, basestring) or name is None
        assert isinstance(prop_set, property_set.PropertySet)
        assert is_iterable_typed(sources, virtual_target.VirtualTarget)
        # The lib generator is composing, and can be only invoked with
        # explicit name. This check is present in generator.run (and so in
        # builtin.LinkingGenerator), but duplicate it here to avoid doing
        # extra work.
        if name:
            properties = prop_set.raw()
            # Determine the needed target type
            actual_type = None
            properties_grist = get_grist(properties)
            if "<source>" not in properties_grist and ("<search>" in properties_grist or "<name>" in properties_grist):
                actual_type = "SEARCHED_LIB"
            elif "<file>" in properties_grist:
                # The generator for
                actual_type = "LIB"
            elif "<link>shared" in properties:
                actual_type = "SHARED_LIB"
            else:
                actual_type = "STATIC_LIB"

            prop_set = prop_set.add_raw(["<main-target-type>LIB"])

            # Construct the target.
            return generators.construct(project, name, actual_type, prop_set, sources)
Exemple #25
0
 def insert (self, properties, value):
     """ Associate value with properties.
     """
     assert is_iterable_typed(properties, basestring)
     assert isinstance(value, basestring)
     self.__properties.append(properties)
     self.__values.append(value)
Exemple #26
0
    def determine_output_name(self, sources):
        """Determine the name of the produced target from the
        names of the sources."""
        assert is_iterable_typed(sources, virtual_target.VirtualTarget)

        # The simple case if when a name
        # of source has single dot. Then, we take the part before
        # dot. Several dots can be caused by:
        # - Using source file like a.host.cpp
        # - A type which suffix has a dot. Say, we can
        #   type 'host_cpp' with extension 'host.cpp'.
        # In the first case, we want to take the part till the last
        # dot. In the second case -- no sure, but for now take
        # the part till the last dot too.
        name = os.path.splitext(sources[0].name())[0]

        for s in sources[1:]:
            n2 = os.path.splitext(s.name())
            if n2 != name:
                get_manager().errors()(
                    "%s: source targets have different names: cannot determine target name"
                    % (self.id_))

        # Names of sources might include directory. We should strip it.
        return self.determine_target_name(sources[0].name())
Exemple #27
0
def expand_subfeatures_in_conditions (properties):
    assert is_iterable_typed(properties, Property)
    result = []
    for p in properties:

        if not p.condition:
            result.append(p)
        else:
            expanded = []
            for c in p.condition:
                # It common that condition includes a toolset which
                # was never defined, or mentiones subfeatures which
                # were never defined. In that case, validation will
                # only produce an spirious error, so don't validate.
                expanded.extend(feature.expand_subfeatures ([c], True))

            # we need to keep LazyProperties lazy
            if isinstance(p, LazyProperty):
                value = p.value
                feature_name = get_grist(value)
                value = value.replace(feature_name, '')
                result.append(LazyProperty(feature_name, value, condition=expanded))
            else:
                result.append(Property(p.feature, p.value, expanded))

    return result
Exemple #28
0
def evaluate_conditionals_in_context (properties, context):
    """ Removes all conditional properties which conditions are not met
        For those with met conditions, removes the condition. Properties
        in conditions are looked up in 'context'
    """
    if __debug__:
        from .property_set import PropertySet
        assert is_iterable_typed(properties, Property)
        assert isinstance(context, PropertySet)
    base = []
    conditional = []

    for p in properties:
        if p.condition:
            conditional.append (p)
        else:
            base.append (p)

    result = base[:]
    for p in conditional:

        # Evaluate condition
        # FIXME: probably inefficient
        if all(x in context for x in p.condition):
            result.append(Property(p.feature, p.value))

    return result
Exemple #29
0
 def construct(self, name, source_targets, properties):
     if __debug__:
         from .virtual_target import VirtualTarget
         assert isinstance(name, basestring)
         assert is_iterable_typed(source_targets, VirtualTarget)
         assert isinstance(properties, property_set.PropertySet)
     return [property_set.empty(), source_targets]
Exemple #30
0
    def run(self, project, name, prop_set, sources):
        assert isinstance(project, targets.ProjectTarget)
        assert isinstance(name, basestring) or name is None
        assert isinstance(prop_set, property_set.PropertySet)
        assert is_iterable_typed(sources, virtual_target.VirtualTarget)

        if not name:
            return None

        # If name is empty, it means we're called not from top-level.
        # In this case, we just fail immediately, because SearchedLibGenerator
        # cannot be used to produce intermediate targets.

        properties = prop_set.raw()
        shared = "<link>shared" in properties

        a = virtual_target.NullAction(project.manager(), prop_set)

        real_name = feature.get_values("<name>", properties)
        if real_name:
            real_name = real_name[0]
        else:
            real_name = name
        search = feature.get_values("<search>", properties)
        usage_requirements = property_set.create(["<xdll-path>" + p for p in search])
        t = SearchedLibTarget(real_name, project, shared, search, a)

        # We return sources for a simple reason. If there's
        #    lib png : z : <name>png ;
        # the 'z' target should be returned, so that apps linking to
        # 'png' will link to 'z', too.
        return (usage_requirements, [b2.manager.get_manager().virtual_targets().register(t)] + sources)
Exemple #31
0
def validate(properties):
    """ Exit with error if any of the properties is not valid.
        properties may be a single property or a sequence of properties.
    """
    if isinstance(properties, Property):
        properties = [properties]
    assert is_iterable_typed(properties, Property)
    for p in properties:
        __validate1(p)
Exemple #32
0
def add_requirements(requirements):
    """Adds elements to the list of global 'toolset requirements'. The requirements
    will be automatically added to the requirements for all main targets, as if
    they were specified literally. For best results, all requirements added should
    be conditional or indirect conditional."""
    assert is_iterable_typed(requirements, basestring)

    if _ignore_toolset_requirements:
        __requirements.extend(requirements)
Exemple #33
0
def path_variable_setting_command(variable, paths):
    """
        Returns a command to sets a named shell path variable to the given NATIVE
        paths on the current platform.
    """
    assert isinstance(variable, basestring)
    assert is_iterable_typed(paths, basestring)
    sep = os.path.pathsep
    return variable_setting_command(variable, sep.join(paths))
Exemple #34
0
def prepend_path_variable_command(variable, paths):
    """
        Returns a command that prepends the given paths to the named path variable on
        the current platform.
    """
    assert isinstance(variable, basestring)
    assert is_iterable_typed(paths, basestring)
    return path_variable_setting_command(variable,
                                         paths + [expand_variable(variable)])
Exemple #35
0
def run_path_setup(target, sources, ps):
    if __debug__:
        from ..build.property_set import PropertySet
        assert is_iterable_typed(target, basestring) or isinstance(target, basestring)
        assert is_iterable_typed(sources, basestring)
        assert isinstance(ps, PropertySet)
    # For testing, we need to make sure that all dynamic libraries needed by the
    # test are found. So, we collect all paths from dependency libraries (via
    # xdll-path property) and add whatever explicit dll-path user has specified.
    # The resulting paths are added to the environment on each test invocation.
    dll_paths = ps.get('dll-path')
    dll_paths.extend(ps.get('xdll-path'))
    dll_paths.extend(bjam.call("get-target-variable", sources, "RUN_PATH"))
    dll_paths = unique(dll_paths)
    if dll_paths:
        bjam.call("set-target-variable", target, "PATH_SETUP",
                  common.prepend_path_variable_command(
                     common.shared_library_path_variable(), dll_paths))
Exemple #36
0
def change_generated_target_ps(is_suffix, type, properties, val):
    assert isinstance(is_suffix, (int, bool))
    assert isinstance(type, basestring)
    assert is_iterable_typed(properties, basestring)
    assert isinstance(val, basestring)
    properties.append ('<target-type>' + type)
    prev = __prefixes_suffixes[is_suffix].find_replace(properties, val)
    if not prev:
        set_generated_target_ps(is_suffix, type, properties, val)
Exemple #37
0
 def propagate(self, scanner, targets):
     assert isinstance(scanner, Scanner)
     assert is_iterable_typed(targets, basestring) or isinstance(
         targets, basestring)
     engine = self.manager_.engine()
     engine.set_target_variable(targets, "HDRSCAN", scanner.pattern())
     engine.set_target_variable(targets, "HDRRULE",
                                self.exported_scanners_[scanner])
     engine.set_target_variable(targets, "HDRGRIST", str(id(scanner)))
Exemple #38
0
def __x_product_aux(property_sets, seen_features):
    """Returns non-conflicting combinations of property sets.

    property_sets is a list of PropertySet instances. seen_features is a set of Property
    instances.

    Returns a tuple of:
    - list of lists of Property instances, such that within each list, no two Property instance
    have the same feature, and no Property is for feature in seen_features.
    - set of features we saw in property_sets
    """
    assert is_iterable_typed(property_sets, property_set.PropertySet)
    assert isinstance(seen_features, set)
    if not property_sets:
        return ([], set())

    properties = property_sets[0].all()

    these_features = set()
    for p in property_sets[0].non_free():
        these_features.add(p.feature())

    # Note: the algorithm as implemented here, as in original Jam code, appears to
    # detect conflicts based on features, not properties. For example, if command
    # line build request say:
    #
    # <a>1/<b>1 c<1>/<b>1
    #
    # It will decide that those two property sets conflict, because they both specify
    # a value for 'b' and will not try building "<a>1 <c1> <b1>", but rather two
    # different property sets. This is a topic for future fixing, maybe.
    if these_features & seen_features:

        (inner_result, inner_seen) = __x_product_aux(property_sets[1:],
                                                     seen_features)
        return (inner_result, inner_seen | these_features)

    else:

        result = []
        (inner_result,
         inner_seen) = __x_product_aux(property_sets[1:],
                                       seen_features | these_features)
        if inner_result:
            for inner in inner_result:
                result.append(properties + inner)
        else:
            result.append(properties)

        if inner_seen & these_features:
            # Some of elements in property_sets[1:] conflict with elements of property_sets[0],
            # Try again, this time omitting elements of property_sets[0]
            (inner_result2,
             inner_seen2) = __x_product_aux(property_sets[1:], seen_features)
            result.extend(inner_result2)

        return (result, inner_seen | these_features)
Exemple #39
0
    def run(self, project, name, prop_set, sources):
        assert isinstance(project, targets.ProjectTarget)
        assert isinstance(name, basestring) or name is None
        assert isinstance(prop_set, property_set.PropertySet)
        assert is_iterable_typed(sources, virtual_target.VirtualTarget)

        # create a copy since sources is being modified
        sources = list(sources)
        sources.extend(prop_set.get('<library>'))

        # Add <library-path> properties for all searched libraries
        extra = []
        for s in sources:
            if s.type() == 'SEARCHED_LIB':
                search = s.search()
                extra.extend(
                    property.Property('<library-path>', sp) for sp in search)

        # It's possible that we have libraries in sources which did not came
        # from 'lib' target. For example, libraries which are specified
        # just as filenames as sources. We don't have xdll-path properties
        # for such target, but still need to add proper dll-path properties.
        extra_xdll_path = []
        for s in sources:
            if type.is_derived(s.type(), 'SHARED_LIB') and not s.action():
                # Unfortunately, we don't have a good way to find the path
                # to a file, so use this nasty approach.
                p = s.project()
                location = path.root(s.name(), p.get('source-location')[0])
                extra_xdll_path.append(os.path.dirname(location))

        # Hardcode DLL paths only when linking executables.
        # Pros: do not need to relink libraries when installing.
        # Cons: "standalone" libraries (plugins, python extensions) can not
        # hardcode paths to dependent libraries.
        if prop_set.get('<hardcode-dll-paths>') == ['true'] \
              and type.is_derived(self.target_types_ [0], 'EXE'):
            xdll_path = prop_set.get('<xdll-path>')
            extra.extend(property.Property('<dll-path>', sp) \
                 for sp in extra_xdll_path)
            extra.extend(property.Property('<dll-path>', sp) \
                 for sp in xdll_path)

        if extra:
            prop_set = prop_set.add_raw(extra)
        result = generators.Generator.run(self, project, name, prop_set,
                                          sources)

        if result:
            ur = self.extra_usage_requirements(result, prop_set)
            ur = ur.add(
                property_set.create(
                    ['<xdll-path>' + p for p in extra_xdll_path]))
        else:
            return None
        return (ur, result)
Exemple #40
0
def construct (project, name, target_type, prop_set, sources, top_level=False):
    """ Attempts to create target of 'target-type' with 'properties'
        from 'sources'. The 'sources' are treated as a collection of
        *possible* ingridients -- i.e. it is not required to consume
        them all. If 'multiple' is true, the rule is allowed to return
        several targets of 'target-type'.

        Returns a list of target. When this invocation is first instance of
        'construct' in stack, returns only targets of requested 'target-type',
        otherwise, returns also unused sources and additionally generated
        targets.

        If 'top-level' is set, does not suppress generators that are already
        used in the stack. This may be useful in cases where a generator
        has to build a metatarget -- for example a target corresponding to
        built tool.
    """
    if __debug__:
        from .targets import ProjectTarget
        assert isinstance(project, ProjectTarget)
        assert isinstance(name, basestring) or name is None
        assert isinstance(target_type, basestring)
        assert isinstance(prop_set, property_set.PropertySet)
        assert is_iterable_typed(sources, virtual_target.VirtualTarget)
        assert isinstance(top_level, bool)
    global __active_generators
    if top_level:
        saved_active = __active_generators
        __active_generators = []

    global __construct_stack
    if not __construct_stack:
        __ensure_type (sources)

    __construct_stack.append (1)

    increase_indent ()

    if project.manager().logger().on():
        dout( "*** construct " + target_type)

        for s in sources:
            dout("    from " + str(s))

        project.manager().logger().log (__name__, "    properties: ", prop_set.raw ())

    result = __construct_really(project, name, target_type, prop_set, sources)

    decrease_indent()

    __construct_stack = __construct_stack [1:]

    if top_level:
        __active_generators = saved_active

    return result
Exemple #41
0
def prepend_path_variable_command(variable, paths):
    """
        Returns a command that prepends the given paths to the named path variable on
        the current platform.
    """
    assert isinstance(variable, basestring)
    assert is_iterable_typed(paths, basestring)

    return path_variable_setting_command(
        variable, paths + os.environ.get(variable, "").split(os.pathsep))
Exemple #42
0
def check_tool(command):
    """ Checks that a tool can be invoked by 'command'.
        If command is not an absolute path, checks if it can be found in 'path'.
        If comand is absolute path, check that it exists. Returns 'command'
        if ok and empty string otherwise.
    """
    assert is_iterable_typed(command, basestring)
    #FIXME: why do we check the first and last elements????
    if check_tool_aux(command[0]) or check_tool_aux(command[-1]):
        return command
Exemple #43
0
def create_with_validation (raw_properties):
    """ Creates new 'PropertySet' instances after checking
        that all properties are valid and converting implicit
        properties into gristed form.
    """
    assert is_iterable_typed(raw_properties, basestring)
    properties = [property.create_from_string(s) for s in raw_properties]
    property.validate(properties)

    return create(properties)
Exemple #44
0
    def __init__ (self, id, composing, source_types, target_types_and_names, requirements = []):
        assert isinstance(id, basestring)
        assert isinstance(composing, bool)
        assert is_iterable_typed(source_types, basestring)
        assert is_iterable_typed(target_types_and_names, basestring)
        assert is_iterable_typed(requirements, basestring)
        self.id_ = id
        self.composing_ = composing
        self.source_types_ = source_types
        self.target_types_and_names_ = target_types_and_names
        self.requirements_ = requirements

        self.target_types_ = []
        self.name_prefix_ = []
        self.name_postfix_ = []

        for e in target_types_and_names:
            # Create three parallel lists: one with the list of target types,
            # and two other with prefixes and postfixes to be added to target
            # name. We use parallel lists for prefix and postfix (as opposed
            # to mapping), because given target type might occur several times,
            # for example "H H(%_symbols)".
            m = _re_separate_types_prefix_and_postfix.match (e)

            if not m:
                raise BaseException ("Invalid type and name '%s' in declaration of type '%s'" % (e, id))

            target_type = m.group (1)
            if not target_type: target_type = ''
            prefix = m.group (3)
            if not prefix: prefix = ''
            postfix = m.group (4)
            if not postfix: postfix = ''

            self.target_types_.append (target_type)
            self.name_prefix_.append (prefix)
            self.name_postfix_.append (postfix)

        for x in self.source_types_:
            type.validate (x)

        for x in self.target_types_:
            type.validate (x)
Exemple #45
0
 def __init__(self, variable_name, values, condition, rule=None):
     assert isinstance(variable_name, basestring)
     assert is_iterable(values) and all(
         isinstance(v, (basestring, type(None))) for v in values)
     assert is_iterable_typed(condition, property_set.PropertySet)
     assert isinstance(rule, (basestring, type(None)))
     self.variable_name = variable_name
     self.values = values
     self.condition = condition
     self.rule = rule
Exemple #46
0
def select(features, properties):
    """ Selects properties which correspond to any of the given features.
    """
    assert is_iterable_typed(properties, basestring)
    result = []

    # add any missing angle brackets
    features = add_grist(features)

    return [p for p in properties if get_grist(p) in features]
Exemple #47
0
    def glob_internal(self, project, wildcards, excludes, rule_name):
        if __debug__:
            from .targets import ProjectTarget
            assert isinstance(project, ProjectTarget)
            assert is_iterable_typed(wildcards, basestring)
            assert is_iterable_typed(excludes, basestring) or excludes is None
            assert isinstance(rule_name, basestring)
        location = project.get("source-location")[0]

        result = []
        callable = b2.util.path.__dict__[rule_name]

        paths = callable([location], wildcards, excludes)
        has_dir = 0
        for w in wildcards:
            if os.path.dirname(w):
                has_dir = 1
                break

        if has_dir or rule_name != "glob":
            result = []
            # The paths we've found are relative to current directory,
            # but the names specified in sources list are assumed to
            # be relative to source directory of the corresponding
            # prject. Either translate them or make absolute.

            for p in paths:
                rel = os.path.relpath(p, location)
                # If the path is below source location, use relative path.
                if not ".." in rel:
                    result.append(rel)
                else:
                    # Otherwise, use full path just to avoid any ambiguities.
                    result.append(os.path.abspath(p))

        else:
            # There were not directory in wildcard, so the files are all
            # in the source directory of the project. Just drop the
            # directory, instead of making paths absolute.
            result = [os.path.basename(p) for p in paths]

        return result
Exemple #48
0
def remove(attributes, properties):
    """Returns a property sets which include all the elements
    in 'properties' that do not have attributes listed in 'attributes'."""
    if isinstance(attributes, basestring):
        attributes = [attributes]
    assert is_iterable_typed(attributes, basestring)
    assert is_iterable_typed(properties, basestring)
    result = []
    for e in properties:
        attributes_new = feature.attributes(get_grist(e))
        has_common_features = 0
        for a in attributes_new:
            if a in attributes:
                has_common_features = 1
                break

        if not has_common_features:
            result += e

    return result
Exemple #49
0
def __select_subfeatures(parent_property, features):
    """ Given a property, return the subset of features consisting of all
        ordinary subfeatures of the property's feature, and all specific
        subfeatures of the property's feature which are conditional on the
        property's value.
    """
    if __debug__:
        from .property import Property
        assert isinstance(parent_property, Property)
        assert is_iterable_typed(features, Feature)
    return [f for f in features if is_subfeature_of(parent_property, f)]
Exemple #50
0
def get_invocation_command_nodefault(toolset,
                                     tool,
                                     user_provided_command=[],
                                     additional_paths=[],
                                     path_last=False):
    """
        A helper rule to get the command to invoke some tool. If
        'user-provided-command' is not given, tries to find binary named 'tool' in
        PATH and in the passed 'additional-path'. Otherwise, verifies that the first
        element of 'user-provided-command' is an existing program.

        This rule returns the command to be used when invoking the tool. If we can't
        find the tool, a warning is issued. If 'path-last' is specified, PATH is
        checked after 'additional-paths' when searching for 'tool'.
    """
    assert isinstance(toolset, basestring)
    assert isinstance(tool, basestring)
    assert is_iterable_typed(user_provided_command, basestring)
    assert is_iterable_typed(additional_paths,
                             basestring) or additional_paths is None
    assert isinstance(path_last, (int, bool))

    if not user_provided_command:
        command = find_tool(tool, additional_paths, path_last)
        if not command and __debug_configuration:
            print "warning: toolset", toolset, "initialization: can't find tool, tool"
            #FIXME
            #print "warning: initialized from" [ errors.nearest-user-location ] ;
    else:
        command = check_tool(user_provided_command)
        if not command and __debug_configuration:
            print "warning: toolset", toolset, "initialization:"
            print "warning: can't find user-provided command", user_provided_command
            #FIXME
            #ECHO "warning: initialized from" [ errors.nearest-user-location ]
            command = []
        command = ' '.join(command)

    assert (isinstance(command, str))

    return command
def expand_no_defaults(property_sets):
    """ Expand the given build request by combining all property_sets which don't
        specify conflicting non-free features.
    """
    assert is_iterable_typed(property_sets, property_set.PropertySet)
    # First make all features and subfeatures explicit
    expanded_property_sets = [ps.expand_subfeatures() for ps in property_sets]

    # Now combine all of the expanded property_sets
    product = __x_product(expanded_property_sets)

    return [property_set.create(p) for p in product]
Exemple #52
0
def set_target_variables(manager, rule_or_module, targets, ps):
    """
    """
    assert isinstance(rule_or_module, basestring)
    assert is_iterable_typed(targets, basestring)
    assert isinstance(ps, property_set.PropertySet)
    settings = __set_target_variables_aux(manager, rule_or_module, ps)

    if settings:
        for s in settings:
            for target in targets:
                manager.engine().set_target_variable(target, s[0], s[1], True)
Exemple #53
0
def alias(name,
          sources=[],
          requirements=[],
          default_build=[],
          usage_requirements=[]):
    assert isinstance(name, basestring)
    assert is_iterable_typed(sources, basestring)
    assert is_iterable_typed(requirements, basestring)
    assert is_iterable_typed(default_build, basestring)
    assert is_iterable_typed(usage_requirements, basestring)
    project = get_manager().projects().current()
    targets = get_manager().targets()

    targets.main_target_alternative(
        AliasTarget(
            name, project,
            targets.main_target_sources(sources, name, no_renaming=True),
            targets.main_target_requirements(requirements or [], project),
            targets.main_target_default_build(default_build, project),
            targets.main_target_usage_requirements(usage_requirements or [],
                                                   project)))
    def generated_targets(self, sources, prop_set, project, name):
        """ Constructs targets that are created after consuming 'sources'.
            The result will be the list of virtual-target, which the same length
            as 'target_types' attribute and with corresponding types.

            When 'name' is empty, all source targets must have the same value of
            the 'name' attribute, which will be used instead of the 'name' argument.

            The value of 'name' attribute for each generated target will be equal to
            the 'name' parameter if there's no name pattern for this type. Otherwise,
            the '%' symbol in the name pattern will be replaced with the 'name' parameter
            to obtain the 'name' attribute.

            For example, if targets types are T1 and T2(with name pattern "%_x"), suffixes
            for T1 and T2 are .t1 and t2, and source if foo.z, then created files would
            be "foo.t1" and "foo_x.t2". The 'name' attribute actually determined the
            basename of a file.

            Note that this pattern mechanism has nothing to do with implicit patterns
            in make. It's a way to produce target which name is different for name of
            source.
        """
        if __debug__:
            from .targets import ProjectTarget
            assert is_iterable_typed(sources, virtual_target.VirtualTarget)
            assert isinstance(prop_set, property_set.PropertySet)
            assert isinstance(project, ProjectTarget)
            assert isinstance(name, basestring) or name is None
        if not name:
            name = self.determine_output_name(sources)

        # Assign an action for each target
        action = self.action_class()
        a = action(project.manager(), sources, self.id_, prop_set)

        # Create generated target for each target type.
        targets = []
        pre = self.name_prefix_
        post = self.name_postfix_
        for t in self.target_types_:
            basename = os.path.basename(name)
            generated_name = pre[0] + basename + post[0]
            generated_name = os.path.join(os.path.dirname(name),
                                          generated_name)
            pre = pre[1:]
            post = post[1:]

            targets.append(
                virtual_target.FileTarget(generated_name, t, project, a))

        return [
            project.manager().virtual_targets().register(t) for t in targets
        ]
    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
        """
        if __debug__:
            from .targets import AbstractTarget
            assert isinstance(main_target, AbstractTarget)
            assert isinstance(prop_set, property_set.PropertySet)
            assert is_iterable_typed(sources, VirtualTarget)
            assert isinstance(build_properties, property_set.PropertySet)
            assert isinstance(sources_usage_requirements,
                              property_set.PropertySet)
            assert is_iterable_typed(created_targets, VirtualTarget)
        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
Exemple #56
0
def handle_options(tool, condition, command, options):
    """ Handle common options for toolset, specifically sets the following
        flag variables:
        - CONFIG_COMMAND to 'command'
        - OPTIOns for compile to the value of <compileflags> in options
        - OPTIONS for compile.c to the value of <cflags> in options
        - OPTIONS for compile.c++ to the value of <cxxflags> in options
        - OPTIONS for compile.fortran to the value of <fflags> in options
        - OPTIONs for link to the value of <linkflags> in options
    """
    from b2.build import toolset

    assert isinstance(tool, basestring)
    assert is_iterable_typed(condition, basestring)
    assert command and isinstance(command, basestring)
    assert is_iterable_typed(options, basestring)
    toolset.flags(tool, 'CONFIG_COMMAND', condition, [command])
    toolset.flags(tool + '.compile', 'OPTIONS', condition, feature.get_values('<compileflags>', options))
    toolset.flags(tool + '.compile.c', 'OPTIONS', condition, feature.get_values('<cflags>', options))
    toolset.flags(tool + '.compile.c++', 'OPTIONS', condition, feature.get_values('<cxxflags>', options))
    toolset.flags(tool + '.compile.fortran', 'OPTIONS', condition, feature.get_values('<fflags>', options))
    toolset.flags(tool + '.link', 'OPTIONS', condition, feature.get_values('<linkflags>', options))
Exemple #57
0
def defaults(features):
    """ Returns the default property values for the given features.
    """
    assert is_iterable_typed(features, Feature)
    # FIXME: should merge feature and property modules.
    from . import property

    result = []
    for f in features:
        if not f.free and not f.optional and f.default:
            result.append(property.Property(f, f.default))

    return result
Exemple #58
0
def __validate_feature_attributes (name, attributes):
    assert isinstance(name, basestring)
    assert is_iterable_typed(attributes, basestring)
    for attribute in attributes:
        if attribute not in VALID_ATTRIBUTES:
            raise InvalidAttribute ("unknown attributes: '%s' in feature declaration: '%s'" % (str (b2.util.set.difference (attributes, __all_attributes)), name))

    if name in __all_features:
            raise AlreadyDefined ("feature '%s' already defined" % name)
    elif 'implicit' in attributes and 'free' in attributes:
        raise InvalidAttribute ("free features cannot also be implicit (in declaration of feature '%s')" % name)
    elif 'free' in attributes and 'propagated' in attributes:
        raise InvalidAttribute ("free features cannot also be propagated (in declaration of feature '%s')" % name)
Exemple #59
0
def register_suffixes (suffixes, type):
    """ Specifies that targets with suffix from 'suffixes' have the type 'type'.
        If a different type is already specified for any of syffixes, issues an error.
    """
    assert is_iterable_typed(suffixes, basestring)
    assert isinstance(type, basestring)
    for s in suffixes:
        if s in __suffixes_to_types:
            old_type = __suffixes_to_types [s]
            if old_type != type:
                raise BaseException ('Attempting to specify type for suffix "%s"\nOld type: "%s", New type "%s"' % (s, old_type, type))
        else:
            __suffixes_to_types [s] = type
Exemple #60
0
def create (raw_properties = []):
    """ Creates a new 'PropertySet' instance for the given raw properties,
        or returns an already existing one.
    """
    assert (is_iterable_typed(raw_properties, property.Property)
            or is_iterable_typed(raw_properties, basestring))
    # FIXME: propagate to callers.
    if len(raw_properties) > 0 and isinstance(raw_properties[0], property.Property):
        x = raw_properties
    else:
        x = [property.create_from_string(ps) for ps in raw_properties]
    x.sort()
    x = unique(x, stable=True)

    # FIXME: can we do better, e.g. by directly computing
    # hash value of the list?
    key = tuple(x)

    if not __cache.has_key (key):
        __cache [key] = PropertySet(x)

    return __cache [key]