mirror of
https://github.com/boostorg/build.git
synced 2026-02-14 00:32:11 +00:00
Add type checking to help ease porting.
- Adds python optimization by default with a "-z" disable flag. - Add type checking to bjam_signature and type checking asserts. - Fix a type assertion in testing.
This commit is contained in:
committed by
Vladimir Prus
parent
67d0547451
commit
b04bfcf171
@@ -29,7 +29,7 @@ import targets
|
||||
import property_set
|
||||
from b2.manager import get_manager
|
||||
|
||||
from b2.util import metatarget
|
||||
from b2.util import metatarget, is_iterable_typed
|
||||
|
||||
class AliasTarget(targets.BasicTarget):
|
||||
|
||||
@@ -37,9 +37,17 @@ class AliasTarget(targets.BasicTarget):
|
||||
targets.BasicTarget.__init__(self, *args)
|
||||
|
||||
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]
|
||||
|
||||
def compute_usage_requirements(self, subvariant):
|
||||
if __debug__:
|
||||
from .virtual_target import Subvariant
|
||||
assert isinstance(subvariant, Subvariant)
|
||||
base = targets.BasicTarget.compute_usage_requirements(self, subvariant)
|
||||
# Add source's usage requirement. If we don't do this, "alias" does not
|
||||
# look like 100% alias.
|
||||
@@ -47,7 +55,11 @@ class AliasTarget(targets.BasicTarget):
|
||||
|
||||
@metatarget
|
||||
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()
|
||||
|
||||
|
||||
@@ -11,12 +11,14 @@ import b2.build.feature
|
||||
feature = b2.build.feature
|
||||
|
||||
from b2.util.utility import *
|
||||
from b2.util import is_iterable_typed
|
||||
import b2.build.property_set as property_set
|
||||
|
||||
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]
|
||||
|
||||
@@ -30,6 +32,7 @@ def __x_product (property_sets):
|
||||
""" Return the cross-product of all elements of property_sets, less any
|
||||
that would contain conflicting values for single-valued features.
|
||||
"""
|
||||
assert is_iterable_typed(property_sets, property_set.PropertySet)
|
||||
x_product_seen = set()
|
||||
return __x_product_aux (property_sets, x_product_seen)[0]
|
||||
|
||||
@@ -44,6 +47,8 @@ def __x_product_aux (property_sets, seen_features):
|
||||
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())
|
||||
|
||||
@@ -90,6 +95,7 @@ def __x_product_aux (property_sets, seen_features):
|
||||
def looks_like_implicit_value(v):
|
||||
"""Returns true if 'v' is either implicit value, or
|
||||
the part before the first '-' symbol is implicit value."""
|
||||
assert isinstance(v, basestring)
|
||||
if feature.is_implicit_value(v):
|
||||
return 1
|
||||
else:
|
||||
@@ -104,7 +110,7 @@ def from_command_line(command_line):
|
||||
and constructs build request from it. Returns a list of two
|
||||
lists. First is the set of targets specified in the command line,
|
||||
and second is the set of requested build properties."""
|
||||
|
||||
assert is_iterable_typed(command_line, basestring)
|
||||
targets = []
|
||||
properties = []
|
||||
|
||||
@@ -122,7 +128,7 @@ def from_command_line(command_line):
|
||||
# Converts one element of command line build request specification into
|
||||
# internal form.
|
||||
def convert_command_line_element(e):
|
||||
|
||||
assert isinstance(e, basestring)
|
||||
result = None
|
||||
parts = e.split("/")
|
||||
for p in parts:
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
import b2.build.property as property
|
||||
import b2.build.property_set as property_set
|
||||
|
||||
import b2.build.targets
|
||||
from b2.build import targets as targets_
|
||||
|
||||
from b2.manager import get_manager
|
||||
from b2.util.sequence import unique
|
||||
from b2.util import bjam_signature, value_to_jam
|
||||
from b2.util import bjam_signature, value_to_jam, is_iterable
|
||||
|
||||
import bjam
|
||||
import os
|
||||
@@ -41,17 +41,22 @@ __log_fd = -1
|
||||
|
||||
def register_components(components):
|
||||
"""Declare that the components specified by the parameter exist."""
|
||||
assert is_iterable(components)
|
||||
__components.extend(components)
|
||||
|
||||
|
||||
def components_building(components):
|
||||
"""Declare that the components specified by the parameters will be build."""
|
||||
assert is_iterable(components)
|
||||
__built_components.extend(components)
|
||||
|
||||
def log_component_configuration(component, message):
|
||||
"""Report something about component configuration that the user should better know."""
|
||||
assert isinstance(component, basestring)
|
||||
assert isinstance(message, basestring)
|
||||
__component_logs.setdefault(component, []).append(message)
|
||||
|
||||
def log_check_result(result):
|
||||
assert isinstance(result, basestring)
|
||||
global __announced_checks
|
||||
if not __announced_checks:
|
||||
print "Performing configuration checks"
|
||||
@@ -60,7 +65,9 @@ def log_check_result(result):
|
||||
print result
|
||||
|
||||
def log_library_search_result(library, result):
|
||||
log_check_result((" - %(library)s : %(result)s" % locals()).rjust(width))
|
||||
assert isinstance(library, basestring)
|
||||
assert isinstance(result, basestring)
|
||||
log_check_result((" - %(library)s : %(result)s" % locals()).rjust(__width))
|
||||
|
||||
|
||||
def print_component_configuration():
|
||||
@@ -84,6 +91,10 @@ def builds(metatarget_reference, project, ps, what):
|
||||
# Attempt to build a metatarget named by 'metatarget-reference'
|
||||
# in context of 'project' with properties 'ps'.
|
||||
# Returns non-empty value if build is OK.
|
||||
assert isinstance(metatarget_reference, basestring)
|
||||
assert isinstance(project, targets_.ProjectTarget)
|
||||
assert isinstance(ps, property_set.PropertySet)
|
||||
assert isinstance(what, basestring)
|
||||
|
||||
result = []
|
||||
|
||||
@@ -93,7 +104,7 @@ def builds(metatarget_reference, project, ps, what):
|
||||
result = False
|
||||
__builds_cache[(what, ps)] = False
|
||||
|
||||
targets = b2.build.targets.generate_from_reference(
|
||||
targets = targets_.generate_from_reference(
|
||||
metatarget_reference, project, ps).targets()
|
||||
jam_targets = []
|
||||
for t in targets:
|
||||
@@ -112,6 +123,7 @@ def builds(metatarget_reference, project, ps, what):
|
||||
return existing
|
||||
|
||||
def set_log_file(log_file_name):
|
||||
assert isinstance(log_file_name, basestring)
|
||||
# Called by Boost.Build startup code to specify name of a file
|
||||
# that will receive results of configure checks. This
|
||||
# should never be called by users.
|
||||
@@ -134,7 +146,7 @@ class CheckTargetBuildsWorker:
|
||||
self.false_properties = property.create_from_strings(false_properties, True)
|
||||
|
||||
def check(self, ps):
|
||||
|
||||
assert isinstance(ps, property_set.PropertySet)
|
||||
# FIXME: this should not be hardcoded. Other checks might
|
||||
# want to consider different set of features as relevant.
|
||||
toolset = ps.get('toolset')[0]
|
||||
|
||||
@@ -10,46 +10,50 @@ import operator
|
||||
import re
|
||||
|
||||
import b2.build.property_set as property_set
|
||||
import b2.util
|
||||
|
||||
class BjamAction:
|
||||
from b2.util import set_jam_action, is_iterable
|
||||
|
||||
class BjamAction(object):
|
||||
"""Class representing bjam action defined from Python."""
|
||||
|
||||
def __init__(self, action_name, function):
|
||||
assert isinstance(action_name, basestring)
|
||||
assert callable(function) or function is None
|
||||
self.action_name = action_name
|
||||
self.function = function
|
||||
|
||||
def __call__(self, targets, sources, property_set):
|
||||
|
||||
def __call__(self, targets, sources, property_set_):
|
||||
assert is_iterable(targets)
|
||||
assert is_iterable(sources)
|
||||
assert isinstance(property_set_, property_set.PropertySet)
|
||||
# Bjam actions defined from Python have only the command
|
||||
# to execute, and no associated jam procedural code. So
|
||||
# passing 'property_set' to it is not necessary.
|
||||
bjam_interface.call("set-update-action", self.action_name,
|
||||
targets, sources, [])
|
||||
if self.function:
|
||||
self.function(targets, sources, property_set)
|
||||
self.function(targets, sources, property_set_)
|
||||
|
||||
class BjamNativeAction:
|
||||
class BjamNativeAction(BjamAction):
|
||||
"""Class representing bjam action defined by Jam code.
|
||||
|
||||
We still allow to associate a Python callable that will
|
||||
be called when this action is installed on any target.
|
||||
"""
|
||||
|
||||
def __init__(self, action_name, function):
|
||||
self.action_name = action_name
|
||||
self.function = function
|
||||
|
||||
def __call__(self, targets, sources, property_set):
|
||||
|
||||
def __call__(self, targets, sources, property_set_):
|
||||
assert is_iterable(targets)
|
||||
assert is_iterable(sources)
|
||||
assert isinstance(property_set_, property_set.PropertySet)
|
||||
if self.function:
|
||||
self.function(targets, sources, property_set)
|
||||
|
||||
self.function(targets, sources, property_set_)
|
||||
|
||||
p = []
|
||||
if property_set:
|
||||
p = property_set.raw()
|
||||
p = property_set_.raw()
|
||||
|
||||
set_jam_action(self.action_name, targets, sources, p)
|
||||
|
||||
b2.util.set_jam_action(self.action_name, targets, sources, p)
|
||||
|
||||
action_modifiers = {"updated": 0x01,
|
||||
"together": 0x02,
|
||||
"ignore": 0x04,
|
||||
@@ -77,6 +81,8 @@ class Engine:
|
||||
targets = [targets]
|
||||
if isinstance (sources, str):
|
||||
sources = [sources]
|
||||
assert is_iterable(targets)
|
||||
assert is_iterable(sources)
|
||||
|
||||
for target in targets:
|
||||
for source in sources:
|
||||
@@ -105,6 +111,11 @@ class Engine:
|
||||
echo [ on $(targets) return $(MY-VAR) ] ;
|
||||
"Hello World"
|
||||
"""
|
||||
if isinstance(targets, str):
|
||||
targets = [targets]
|
||||
assert is_iterable(targets)
|
||||
assert isinstance(variable, basestring)
|
||||
|
||||
return bjam_interface.call('get-target-variable', targets, variable)
|
||||
|
||||
def set_target_variable (self, targets, variable, value, append=0):
|
||||
@@ -114,13 +125,19 @@ class Engine:
|
||||
where to generate targets, and will also be available to
|
||||
updating rule for that 'taret'.
|
||||
"""
|
||||
if isinstance (targets, str):
|
||||
if isinstance (targets, str):
|
||||
targets = [targets]
|
||||
if isinstance(value, str):
|
||||
value = [value]
|
||||
|
||||
assert is_iterable(targets)
|
||||
assert isinstance(variable, basestring)
|
||||
assert is_iterable(value)
|
||||
|
||||
for target in targets:
|
||||
self.do_set_target_variable (target, variable, value, append)
|
||||
|
||||
def set_update_action (self, action_name, targets, sources, properties=property_set.empty()):
|
||||
def set_update_action (self, action_name, targets, sources, properties=None):
|
||||
""" Binds a target to the corresponding update action.
|
||||
If target needs to be updated, the action registered
|
||||
with action_name will be used.
|
||||
@@ -128,9 +145,17 @@ class Engine:
|
||||
either 'register_action' or 'register_bjam_action'
|
||||
method.
|
||||
"""
|
||||
assert(isinstance(properties, property_set.PropertySet))
|
||||
if isinstance (targets, str):
|
||||
if isinstance(targets, str):
|
||||
targets = [targets]
|
||||
if isinstance(sources, str):
|
||||
sources = [sources]
|
||||
if properties is None:
|
||||
properties = property_set.empty()
|
||||
assert isinstance(action_name, basestring)
|
||||
assert is_iterable(targets)
|
||||
assert is_iterable(sources)
|
||||
assert(isinstance(properties, property_set.PropertySet))
|
||||
|
||||
self.do_set_update_action (action_name, targets, sources, properties)
|
||||
|
||||
def register_action (self, action_name, command, bound_list = [], flags = [],
|
||||
@@ -149,11 +174,14 @@ class Engine:
|
||||
This function will be called by set_update_action, and can
|
||||
set additional target variables.
|
||||
"""
|
||||
assert isinstance(action_name, basestring)
|
||||
assert isinstance(command, basestring)
|
||||
assert is_iterable(bound_list)
|
||||
assert is_iterable(flags)
|
||||
assert function is None or callable(function)
|
||||
if self.actions.has_key(action_name):
|
||||
raise "Bjam action %s is already defined" % action_name
|
||||
|
||||
assert(isinstance(flags, list))
|
||||
|
||||
bjam_flags = reduce(operator.or_,
|
||||
(action_modifiers[flag] for flag in flags), 0)
|
||||
|
||||
@@ -178,25 +206,37 @@ class Engine:
|
||||
# action name. This way, jamfile rules that take action names
|
||||
# can just register them without specially checking if
|
||||
# action is already registered.
|
||||
assert isinstance(action_name, basestring)
|
||||
assert function is None or callable(function)
|
||||
if not self.actions.has_key(action_name):
|
||||
self.actions[action_name] = BjamNativeAction(action_name, function)
|
||||
|
||||
|
||||
# Overridables
|
||||
|
||||
|
||||
def do_set_update_action (self, action_name, targets, sources, property_set):
|
||||
def do_set_update_action (self, action_name, targets, sources, property_set_):
|
||||
assert isinstance(action_name, basestring)
|
||||
assert is_iterable(targets)
|
||||
assert is_iterable(sources)
|
||||
assert isinstance(property_set_, property_set.PropertySet)
|
||||
action = self.actions.get(action_name)
|
||||
if not action:
|
||||
raise Exception("No action %s was registered" % action_name)
|
||||
action(targets, sources, property_set)
|
||||
action(targets, sources, property_set_)
|
||||
|
||||
def do_set_target_variable (self, target, variable, value, append):
|
||||
assert isinstance(target, basestring)
|
||||
assert isinstance(variable, basestring)
|
||||
assert is_iterable(value)
|
||||
assert isinstance(append, int) # matches bools
|
||||
if append:
|
||||
bjam_interface.call("set-target-variable", target, variable, value, "true")
|
||||
else:
|
||||
bjam_interface.call("set-target-variable", target, variable, value)
|
||||
|
||||
|
||||
def do_add_dependency (self, target, source):
|
||||
assert isinstance(target, basestring)
|
||||
assert isinstance(source, basestring)
|
||||
bjam_interface.call("DEPENDS", target, source)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
import re
|
||||
|
||||
from b2.util import utility, bjam_signature
|
||||
from b2.util import utility, bjam_signature, is_iterable_typed
|
||||
import b2.util.set
|
||||
from b2.util.utility import add_grist, get_grist, ungrist, replace_grist, to_seq
|
||||
from b2.exceptions import *
|
||||
@@ -25,6 +25,9 @@ class Feature(object):
|
||||
_attribute_name_to_integer = {}
|
||||
|
||||
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
|
||||
@@ -42,12 +45,14 @@ class Feature(object):
|
||||
return self._values
|
||||
|
||||
def add_values(self, values):
|
||||
assert is_iterable_typed(values, basestring)
|
||||
self._values.extend(values)
|
||||
|
||||
def attributes(self):
|
||||
return self._attributes
|
||||
|
||||
def set_default(self, value):
|
||||
assert isinstance(value, basestring)
|
||||
for attr in ('free', 'optional'):
|
||||
if getattr(self, attr)():
|
||||
get_manager().errors()('"{}" feature "<{}>" cannot have a default value.'
|
||||
@@ -66,6 +71,7 @@ class Feature(object):
|
||||
return self._subfeatures
|
||||
|
||||
def add_subfeature(self, name):
|
||||
assert isinstance(name, Feature)
|
||||
self._subfeatures.append(name)
|
||||
|
||||
def parent(self):
|
||||
@@ -77,6 +83,8 @@ class Feature(object):
|
||||
return self._parent
|
||||
|
||||
def set_parent(self, feature, value):
|
||||
assert isinstance(feature, Feature)
|
||||
assert isinstance(value, basestring)
|
||||
self._parent = (feature, value)
|
||||
|
||||
def __str__(self):
|
||||
@@ -151,6 +159,7 @@ def get(name):
|
||||
|
||||
Throws if no feature by such name exists
|
||||
"""
|
||||
assert isinstance(name, basestring)
|
||||
return __all_features[name]
|
||||
|
||||
# FIXME: prepare-test/finish-test?
|
||||
@@ -213,9 +222,10 @@ def set_default (feature, value):
|
||||
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.
|
||||
import property
|
||||
|
||||
from . import property
|
||||
|
||||
result = []
|
||||
for f in features:
|
||||
if not f.free() and not f.optional() and f.default():
|
||||
@@ -226,21 +236,22 @@ def defaults(features):
|
||||
def valid (names):
|
||||
""" Returns true iff all elements of names are valid features.
|
||||
"""
|
||||
def valid_one (name): return __all_features.has_key (name)
|
||||
|
||||
if isinstance (names, str):
|
||||
return valid_one (names)
|
||||
else:
|
||||
return all([ valid_one (name) for name in names ])
|
||||
if isinstance(names, str):
|
||||
names = [names]
|
||||
assert is_iterable_typed(names, basestring)
|
||||
|
||||
return all(name in __all_features for name in names)
|
||||
|
||||
def attributes (feature):
|
||||
""" Returns the attributes of the given feature.
|
||||
"""
|
||||
assert isinstance(feature, basestring)
|
||||
return __all_features[feature].attributes_string_list()
|
||||
|
||||
|
||||
def values (feature):
|
||||
""" Return the values of the given feature.
|
||||
"""
|
||||
assert isinstance(feature, basestring)
|
||||
validate_feature (feature)
|
||||
return __all_features[feature].values()
|
||||
|
||||
@@ -248,7 +259,7 @@ def is_implicit_value (value_string):
|
||||
""" Returns true iff 'value_string' is a value_string
|
||||
of an implicit feature.
|
||||
"""
|
||||
|
||||
assert isinstance(value_string, basestring)
|
||||
if __implicit_features.has_key(value_string):
|
||||
return __implicit_features[value_string]
|
||||
|
||||
@@ -268,6 +279,7 @@ def is_implicit_value (value_string):
|
||||
def implied_feature (implicit_value):
|
||||
""" Returns the implicit feature associated with the given implicit value.
|
||||
"""
|
||||
assert isinstance(implicit_value, basestring)
|
||||
components = implicit_value.split('-')
|
||||
|
||||
if not __implicit_features.has_key(components[0]):
|
||||
@@ -276,15 +288,14 @@ def implied_feature (implicit_value):
|
||||
return __implicit_features[components[0]]
|
||||
|
||||
def __find_implied_subfeature (feature, subvalue, value_string):
|
||||
|
||||
#if value_string == None: value_string = ''
|
||||
assert isinstance(feature, Feature)
|
||||
assert isinstance(subvalue, basestring)
|
||||
assert isinstance(value_string, basestring)
|
||||
|
||||
if not __subfeature_from_value.has_key(feature) \
|
||||
or not __subfeature_from_value[feature].has_key(value_string) \
|
||||
or not __subfeature_from_value[feature][value_string].has_key (subvalue):
|
||||
try:
|
||||
return __subfeature_from_value[feature][value_string][subvalue]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
return __subfeature_from_value[feature][value_string][subvalue]
|
||||
|
||||
# Given a feature and a value of one of its subfeatures, find the name
|
||||
# of the subfeature. If value-string is supplied, looks for implied
|
||||
@@ -294,6 +305,9 @@ def __find_implied_subfeature (feature, subvalue, value_string):
|
||||
# value-string # The value of the main feature
|
||||
|
||||
def implied_subfeature (feature, subvalue, value_string):
|
||||
assert isinstance(feature, Feature)
|
||||
assert isinstance(subvalue, basestring)
|
||||
assert isinstance(value_string, basestring)
|
||||
result = __find_implied_subfeature (feature, subvalue, value_string)
|
||||
if not result:
|
||||
raise InvalidValue ("'%s' is not a known subfeature value of '%s%s'" % (subvalue, feature, value_string))
|
||||
@@ -303,28 +317,20 @@ def implied_subfeature (feature, subvalue, value_string):
|
||||
def validate_feature (name):
|
||||
""" Checks if all name is a valid feature. Otherwise, raises an exception.
|
||||
"""
|
||||
assert isinstance(name, basestring)
|
||||
if not __all_features.has_key(name):
|
||||
raise InvalidFeature ("'%s' is not a valid feature name" % name)
|
||||
else:
|
||||
return __all_features[name]
|
||||
|
||||
def valid (names):
|
||||
""" Returns true iff all elements of names are valid features.
|
||||
"""
|
||||
def valid_one (name): return __all_features.has_key (name)
|
||||
|
||||
if isinstance (names, str):
|
||||
return valid_one (names)
|
||||
else:
|
||||
return [ valid_one (name) for name in names ]
|
||||
|
||||
# Uses Property
|
||||
def __expand_subfeatures_aux (property, dont_validate = False):
|
||||
def __expand_subfeatures_aux (property_, dont_validate = False):
|
||||
""" Helper for expand_subfeatures.
|
||||
Given a feature and value, or just a value corresponding to an
|
||||
implicit feature, returns a property set consisting of all component
|
||||
subfeatures and their values. For example:
|
||||
|
||||
|
||||
expand_subfeatures <toolset>gcc-2.95.2-linux-x86
|
||||
-> <toolset>gcc <toolset-version>2.95.2 <toolset-os>linux <toolset-cpu>x86
|
||||
equivalent to:
|
||||
@@ -334,8 +340,12 @@ def __expand_subfeatures_aux (property, dont_validate = False):
|
||||
value: The value of the feature.
|
||||
dont_validate: If True, no validation of value string will be done.
|
||||
"""
|
||||
f = property.feature()
|
||||
v = property.value()
|
||||
from . import property # no __debug__ since Property is used elsewhere
|
||||
assert isinstance(property_, property.Property)
|
||||
assert isinstance(dont_validate, int) # matches bools
|
||||
|
||||
f = property_.feature()
|
||||
v = property_.value()
|
||||
if not dont_validate:
|
||||
validate_value_string(f, v)
|
||||
|
||||
@@ -343,10 +353,8 @@ def __expand_subfeatures_aux (property, dont_validate = False):
|
||||
|
||||
v = components[0]
|
||||
|
||||
import property
|
||||
result = [property.Property(f, components[0])]
|
||||
|
||||
result = [property.Property(f, components[0])]
|
||||
|
||||
subvalues = components[1:]
|
||||
|
||||
while len(subvalues) > 0:
|
||||
@@ -380,6 +388,10 @@ def expand_subfeatures(properties, dont_validate = False):
|
||||
case of implicit features.
|
||||
: dont_validate: If True, no validation of value string will be done.
|
||||
"""
|
||||
if __debug__:
|
||||
from .property import Property
|
||||
assert is_iterable_typed(properties, Property)
|
||||
assert isinstance(dont_validate, int) # matches bools
|
||||
result = []
|
||||
for p in properties:
|
||||
# Don't expand subfeatures in subfeatures
|
||||
@@ -413,6 +425,8 @@ def expand_subfeatures(properties, dont_validate = False):
|
||||
def extend (name, values):
|
||||
""" Adds the given values to the given feature.
|
||||
"""
|
||||
assert isinstance(name, basestring)
|
||||
assert is_iterable_typed(values, basestring)
|
||||
name = add_grist (name)
|
||||
__validate_feature (name)
|
||||
feature = __all_features [name]
|
||||
@@ -434,6 +448,8 @@ def extend (name, values):
|
||||
def validate_value_string (f, value_string):
|
||||
""" Checks that value-string is a valid value-string for the given feature.
|
||||
"""
|
||||
assert isinstance(f, Feature)
|
||||
assert isinstance(value_string, basestring)
|
||||
if f.free() or value_string in f.values():
|
||||
return
|
||||
|
||||
@@ -472,7 +488,10 @@ def validate_value_string (f, value_string):
|
||||
subvalues: The additional values of the subfeature being defined.
|
||||
"""
|
||||
def extend_subfeature (feature_name, value_string, subfeature_name, subvalues):
|
||||
|
||||
assert isinstance(feature_name, basestring)
|
||||
assert isinstance(value_string, basestring)
|
||||
assert isinstance(subfeature_name, basestring)
|
||||
assert is_iterable_typed(subvalues, basestring)
|
||||
feature = validate_feature(feature_name)
|
||||
|
||||
if value_string:
|
||||
@@ -532,7 +551,7 @@ def compose (composite_property_s, component_properties_s):
|
||||
|
||||
All parameters are <feature>value strings
|
||||
"""
|
||||
import property
|
||||
from . import property
|
||||
|
||||
component_properties_s = to_seq (component_properties_s)
|
||||
composite_property = property.create_from_string(composite_property_s)
|
||||
@@ -555,10 +574,13 @@ def compose (composite_property_s, component_properties_s):
|
||||
__composite_properties[composite_property] = component_properties
|
||||
|
||||
|
||||
def expand_composite(property):
|
||||
result = [ property ]
|
||||
if __composite_properties.has_key(property):
|
||||
for p in __composite_properties[property]:
|
||||
def expand_composite(property_):
|
||||
if __debug__:
|
||||
from .property import Property
|
||||
assert isinstance(property_, Property)
|
||||
result = [ property_ ]
|
||||
if __composite_properties.has_key(property_):
|
||||
for p in __composite_properties[property_]:
|
||||
result.extend(expand_composite(p))
|
||||
return result
|
||||
|
||||
@@ -584,6 +606,9 @@ def expand_composites (properties):
|
||||
""" Expand all composite properties in the set so that all components
|
||||
are explicitly expressed.
|
||||
"""
|
||||
if __debug__:
|
||||
from .property import Property
|
||||
assert is_iterable_typed(properties, Property)
|
||||
explicit_features = set(p.feature() for p in properties)
|
||||
|
||||
result = []
|
||||
@@ -622,6 +647,11 @@ def is_subfeature_of (parent_property, f):
|
||||
feature, or if f is a subfeature of the parent_property's feature
|
||||
specific to the parent_property's value.
|
||||
"""
|
||||
if __debug__:
|
||||
from .property import Property
|
||||
assert isinstance(parent_property, Property)
|
||||
assert isinstance(f, Feature)
|
||||
|
||||
if not f.subfeature():
|
||||
return False
|
||||
|
||||
@@ -643,38 +673,27 @@ def is_subfeature_of (parent_property, f):
|
||||
def __is_subproperty_of (parent_property, p):
|
||||
""" As is_subfeature_of, for subproperties.
|
||||
"""
|
||||
if __debug__:
|
||||
from .property import Property
|
||||
assert isinstance(parent_property, Property)
|
||||
assert isinstance(p, Property)
|
||||
return is_subfeature_of (parent_property, p.feature())
|
||||
|
||||
|
||||
|
||||
# Returns true iff the subvalue is valid for the feature. When the
|
||||
# optional value-string is provided, returns true iff the subvalues
|
||||
# are valid for the given value of the feature.
|
||||
def is_subvalue(feature, value_string, subfeature, subvalue):
|
||||
|
||||
assert isinstance(feature, basestring)
|
||||
assert isinstance(value_string, basestring)
|
||||
assert isinstance(subfeature, basestring)
|
||||
assert isinstance(subvalue, basestring)
|
||||
if not value_string:
|
||||
value_string = ''
|
||||
|
||||
if not __subfeature_from_value.has_key(feature):
|
||||
try:
|
||||
return __subfeature_from_value[feature][value_string][subvalue] == subfeature
|
||||
except KeyError:
|
||||
return False
|
||||
|
||||
if not __subfeature_from_value[feature].has_key(value_string):
|
||||
return False
|
||||
|
||||
if not __subfeature_from_value[feature][value_string].has_key(subvalue):
|
||||
return False
|
||||
|
||||
if __subfeature_from_value[feature][value_string][subvalue]\
|
||||
!= subfeature:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def implied_subfeature (feature, subvalue, value_string):
|
||||
result = __find_implied_subfeature (feature, subvalue, value_string)
|
||||
if not result:
|
||||
raise InvalidValue ("'%s' is not a known subfeature value of '%s%s'" % (subvalue, feature, value_string))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# Uses Property
|
||||
@@ -689,6 +708,9 @@ def expand (properties):
|
||||
two values of a given non-free feature are directly expressed in the
|
||||
input, an error is issued.
|
||||
"""
|
||||
if __debug__:
|
||||
from .property import Property
|
||||
assert is_iterable_typed(properties, Property)
|
||||
expanded = expand_subfeatures(properties)
|
||||
return expand_composites (expanded)
|
||||
|
||||
@@ -711,6 +733,10 @@ def add_defaults (properties):
|
||||
|
||||
and that's kind of strange.
|
||||
"""
|
||||
if __debug__:
|
||||
from .property import Property
|
||||
assert is_iterable_typed(properties, Property)
|
||||
|
||||
result = [x for x in properties]
|
||||
|
||||
handled_features = set()
|
||||
@@ -744,8 +770,10 @@ def minimize (properties):
|
||||
Implicit properties will be expressed without feature
|
||||
grist, and sub-property values will be expressed as elements joined
|
||||
to the corresponding main property.
|
||||
"""
|
||||
|
||||
"""
|
||||
if __debug__:
|
||||
from .property import Property
|
||||
assert is_iterable_typed(properties, Property)
|
||||
# remove properties implied by composite features
|
||||
components = []
|
||||
for property in properties:
|
||||
@@ -807,7 +835,7 @@ def split (properties):
|
||||
substitution of backslashes for slashes, since Jam, unbidden,
|
||||
sometimes swaps slash direction on NT.
|
||||
"""
|
||||
|
||||
assert isinstance(properties, basestring)
|
||||
def split_one (properties):
|
||||
pieces = re.split (__re_slash_or_backslash, properties)
|
||||
result = []
|
||||
@@ -839,6 +867,8 @@ def compress_subproperties (properties):
|
||||
build-request.expand-no-defaults is being abused for unintended
|
||||
purposes and it needs help
|
||||
"""
|
||||
from .property import Property
|
||||
assert is_iterable_typed(properties, Property)
|
||||
result = []
|
||||
matched_subs = set()
|
||||
all_subs = set()
|
||||
@@ -852,7 +882,7 @@ def compress_subproperties (properties):
|
||||
matched_subs.update(subs)
|
||||
|
||||
subvalues = '-'.join (sub.value() for sub in subs)
|
||||
result.append(b2.build.property.Property(
|
||||
result.append(Property(
|
||||
p.feature(), p.value() + '-' + subvalues,
|
||||
p.condition()))
|
||||
else:
|
||||
@@ -870,10 +900,16 @@ def compress_subproperties (properties):
|
||||
# Private methods
|
||||
|
||||
def __select_subproperties (parent_property, properties):
|
||||
if __debug__:
|
||||
from .property import Property
|
||||
assert is_iterable_typed(properties, Property)
|
||||
assert isinstance(parent_property, Property)
|
||||
return [ x for x in properties if __is_subproperty_of (parent_property, x) ]
|
||||
|
||||
def __get_subfeature_name (subfeature, value_string):
|
||||
if value_string == None:
|
||||
assert isinstance(subfeature, basestring)
|
||||
assert isinstance(value_string, basestring) or value_string is None
|
||||
if value_string == None:
|
||||
prefix = ''
|
||||
else:
|
||||
prefix = value_string + ':'
|
||||
@@ -882,10 +918,12 @@ def __get_subfeature_name (subfeature, value_string):
|
||||
|
||||
|
||||
def __validate_feature_attributes (name, attributes):
|
||||
assert isinstance(name, basestring)
|
||||
assert is_iterable_typed(attributes, basestring)
|
||||
for attribute in attributes:
|
||||
if not attribute in __all_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:
|
||||
@@ -897,6 +935,7 @@ def __validate_feature_attributes (name, attributes):
|
||||
def __validate_feature (feature):
|
||||
""" Generates an error if the feature is unknown.
|
||||
"""
|
||||
assert isinstance(feature, basestring)
|
||||
if not __all_features.has_key (feature):
|
||||
raise BaseException ('unknown feature "%s"' % feature)
|
||||
|
||||
@@ -907,6 +946,10 @@ def __select_subfeatures (parent_property, features):
|
||||
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)]
|
||||
|
||||
# FIXME: copy over tests.
|
||||
|
||||
@@ -52,10 +52,10 @@ import cStringIO
|
||||
import os.path
|
||||
|
||||
from virtual_target import Subvariant
|
||||
import virtual_target, type, property_set, property
|
||||
from . import virtual_target, type, property_set, property
|
||||
from b2.util.logger import *
|
||||
from b2.util.utility import *
|
||||
from b2.util import set
|
||||
from b2.util import set as set_, is_iterable_typed, is_iterable
|
||||
from b2.util.sequence import unique
|
||||
import b2.util.sequence as sequence
|
||||
from b2.manager import get_manager
|
||||
@@ -114,7 +114,7 @@ def decrease_indent():
|
||||
# same generator. Does nothing if a non-derived target type is passed to it.
|
||||
#
|
||||
def update_cached_information_with_a_new_type(type):
|
||||
|
||||
assert isinstance(type, basestring)
|
||||
base_type = b2.build.type.base(type)
|
||||
|
||||
if base_type:
|
||||
@@ -184,8 +184,11 @@ class Generator:
|
||||
NOTE: all subclasses must have a similar signature for clone to work!
|
||||
"""
|
||||
def __init__ (self, id, composing, source_types, target_types_and_names, requirements = []):
|
||||
assert(not isinstance(source_types, str))
|
||||
assert(not isinstance(target_types_and_names, str))
|
||||
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
|
||||
@@ -229,9 +232,11 @@ class Generator:
|
||||
- id
|
||||
- value to <toolset> feature in properties
|
||||
"""
|
||||
return self.__class__ (new_id,
|
||||
self.composing_,
|
||||
self.source_types_,
|
||||
assert isinstance(new_id, basestring)
|
||||
assert is_iterable_typed(new_toolset_properties, basestring)
|
||||
return self.__class__ (new_id,
|
||||
self.composing_,
|
||||
self.source_types_,
|
||||
self.target_types_and_names_,
|
||||
# Note: this does not remove any subfeatures of <toolset>
|
||||
# which might cause problems
|
||||
@@ -241,6 +246,8 @@ class Generator:
|
||||
"""Creates another generator that is the same as $(self), except that
|
||||
if 'base' is in target types of $(self), 'type' will in target types
|
||||
of the new generator."""
|
||||
assert isinstance(base, basestring)
|
||||
assert isinstance(type, basestring)
|
||||
target_types = []
|
||||
for t in self.target_types_and_names_:
|
||||
m = _re_match_type.match(t)
|
||||
@@ -291,6 +298,7 @@ class Generator:
|
||||
# 'properties'. Treat a feature name in requirements
|
||||
# (i.e. grist-only element), as matching any value of the
|
||||
# feature.
|
||||
assert isinstance(ps, property_set.PropertySet)
|
||||
all_requirements = self.requirements ()
|
||||
|
||||
property_requirements = []
|
||||
@@ -321,7 +329,13 @@ class Generator:
|
||||
|
||||
sources: Source targets.
|
||||
"""
|
||||
|
||||
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)
|
||||
if project.manager ().logger ().on ():
|
||||
project.manager ().logger ().log (__name__, " generator '%s'" % self.id_)
|
||||
project.manager ().logger ().log (__name__, " composing: '%s'" % self.composing_)
|
||||
@@ -345,7 +359,13 @@ class Generator:
|
||||
return []
|
||||
|
||||
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.
|
||||
|
||||
@@ -380,6 +400,12 @@ class Generator:
|
||||
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_:
|
||||
@@ -395,6 +421,7 @@ class Generator:
|
||||
return result
|
||||
|
||||
def determine_target_name(self, fullname):
|
||||
assert isinstance(fullname, basestring)
|
||||
# Determine target name from fullname (maybe including path components)
|
||||
# Place optional prefix and postfix around basename
|
||||
|
||||
@@ -415,7 +442,7 @@ class Generator:
|
||||
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:
|
||||
@@ -460,6 +487,12 @@ class Generator:
|
||||
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)
|
||||
|
||||
@@ -494,6 +527,13 @@ class Generator:
|
||||
consumed: all targets that can be consumed.
|
||||
bypassed: all targets that cannot be consumed.
|
||||
"""
|
||||
if __debug__:
|
||||
from .targets import ProjectTarget
|
||||
assert isinstance(name, basestring) or name is None
|
||||
assert isinstance(project, ProjectTarget)
|
||||
assert isinstance(prop_set, property_set.PropertySet)
|
||||
assert is_iterable_typed(sources, virtual_target.VirtualTarget)
|
||||
assert isinstance(only_one, bool)
|
||||
consumed = []
|
||||
bypassed = []
|
||||
missing_types = []
|
||||
@@ -563,7 +603,16 @@ class Generator:
|
||||
"""
|
||||
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:
|
||||
@@ -578,6 +627,7 @@ class Generator:
|
||||
return (consumed, bypassed)
|
||||
|
||||
def consume_directly (self, source):
|
||||
assert isinstance(source, virtual_target.VirtualTarget)
|
||||
real_source_type = source.type ()
|
||||
|
||||
# If there are no source types, we can consume anything
|
||||
@@ -607,11 +657,13 @@ class Generator:
|
||||
def find (id):
|
||||
""" Finds the generator with id. Returns None if not found.
|
||||
"""
|
||||
assert isinstance(id, basestring)
|
||||
return __generators.get (id, None)
|
||||
|
||||
def register (g):
|
||||
""" Registers new generator instance 'g'.
|
||||
"""
|
||||
assert isinstance(g, Generator)
|
||||
id = g.id()
|
||||
|
||||
__generators [id] = g
|
||||
@@ -660,6 +712,19 @@ def register (g):
|
||||
invalidate_extendable_viable_source_target_type_cache()
|
||||
|
||||
|
||||
def check_register_types(fn):
|
||||
def wrapper(id, source_types, target_types, requirements=[]):
|
||||
assert isinstance(id, basestring)
|
||||
assert is_iterable_typed(source_types, basestring)
|
||||
assert is_iterable_typed(target_types, basestring)
|
||||
assert is_iterable_typed(requirements, basestring)
|
||||
return fn(id, source_types, target_types, requirements=requirements)
|
||||
wrapper.__name__ = fn.__name__
|
||||
wrapper.__doc__ = fn.__doc__
|
||||
return wrapper
|
||||
|
||||
|
||||
@check_register_types
|
||||
def register_standard (id, source_types, target_types, requirements = []):
|
||||
""" Creates new instance of the 'generator' class and registers it.
|
||||
Returns the creates instance.
|
||||
@@ -671,6 +736,8 @@ def register_standard (id, source_types, target_types, requirements = []):
|
||||
register (g)
|
||||
return g
|
||||
|
||||
|
||||
@check_register_types
|
||||
def register_composing (id, source_types, target_types, requirements = []):
|
||||
g = Generator (id, True, source_types, target_types, requirements)
|
||||
register (g)
|
||||
@@ -679,6 +746,7 @@ def register_composing (id, source_types, target_types, requirements = []):
|
||||
def generators_for_toolset (toolset):
|
||||
""" Returns all generators which belong to 'toolset'.
|
||||
"""
|
||||
assert isinstance(toolset, basestring)
|
||||
return __generators_for_toolset.get(toolset, [])
|
||||
|
||||
def override (overrider_id, overridee_id):
|
||||
@@ -691,7 +759,8 @@ def override (overrider_id, overridee_id):
|
||||
The overridden generators are discarded immediately
|
||||
after computing the list of viable generators, before
|
||||
running any of them."""
|
||||
|
||||
assert isinstance(overrider_id, basestring)
|
||||
assert isinstance(overridee_id, basestring)
|
||||
__overrides.setdefault(overrider_id, []).append(overridee_id)
|
||||
|
||||
def __viable_source_types_real (target_type):
|
||||
@@ -702,6 +771,7 @@ def __viable_source_types_real (target_type):
|
||||
returns union of source types for those generators and result
|
||||
of calling itself recusrively on source types.
|
||||
"""
|
||||
assert isinstance(target_type, basestring)
|
||||
generators = []
|
||||
|
||||
# 't0' is the initial list of target types we need to process to get a list
|
||||
@@ -750,13 +820,14 @@ def __viable_source_types_real (target_type):
|
||||
if not n in t0:
|
||||
t.append (n)
|
||||
result.append (n)
|
||||
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def viable_source_types (target_type):
|
||||
""" Helper rule, caches the result of '__viable_source_types_real'.
|
||||
"""
|
||||
assert isinstance(target_type, basestring)
|
||||
if not __viable_source_types_cache.has_key(target_type):
|
||||
__vst_cached_types.append(target_type)
|
||||
__viable_source_types_cache [target_type] = __viable_source_types_real (target_type)
|
||||
@@ -767,6 +838,7 @@ def viable_source_types_for_generator_real (generator):
|
||||
method of 'generator', has some change of being eventually used
|
||||
(probably after conversion by other generators)
|
||||
"""
|
||||
assert isinstance(generator, Generator)
|
||||
source_types = generator.source_types ()
|
||||
|
||||
if not source_types:
|
||||
@@ -791,6 +863,7 @@ def viable_source_types_for_generator_real (generator):
|
||||
def viable_source_types_for_generator (generator):
|
||||
""" Caches the result of 'viable_source_types_for_generator'.
|
||||
"""
|
||||
assert isinstance(generator, Generator)
|
||||
if not __viable_source_types_cache.has_key(generator):
|
||||
__vstg_cached_generators.append(generator)
|
||||
__viable_source_types_cache[generator] = viable_source_types_for_generator_real (generator)
|
||||
@@ -800,6 +873,14 @@ def viable_source_types_for_generator (generator):
|
||||
def try_one_generator_really (project, name, generator, target_type, properties, sources):
|
||||
""" Returns usage requirements + list of created targets.
|
||||
"""
|
||||
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)
|
||||
targets = generator.run (project, name, properties, sources)
|
||||
|
||||
usage_requirements = []
|
||||
@@ -834,6 +915,14 @@ def try_one_generator (project, name, generator, target_type, properties, source
|
||||
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:
|
||||
@@ -842,7 +931,7 @@ def try_one_generator (project, name, generator, target_type, properties, source
|
||||
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):
|
||||
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)
|
||||
@@ -856,10 +945,16 @@ def try_one_generator (project, name, generator, target_type, properties, source
|
||||
|
||||
|
||||
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)
|
||||
|
||||
@@ -886,6 +981,7 @@ def __ensure_type (targets):
|
||||
""" Ensures all 'targets' have types. If this is not so, exists with
|
||||
error.
|
||||
"""
|
||||
assert is_iterable_typed(targets, virtual_target.VirtualTarget)
|
||||
for t in targets:
|
||||
if not t.type ():
|
||||
get_manager().errors()("target '%s' has no type" % str (t))
|
||||
@@ -902,11 +998,13 @@ def find_viable_generators_aux (target_type, prop_set):
|
||||
Note: this algorithm explicitly ignores generators for base classes if there's
|
||||
at least one generator for requested target_type.
|
||||
"""
|
||||
assert isinstance(target_type, basestring)
|
||||
assert isinstance(prop_set, property_set.PropertySet)
|
||||
# Select generators that can create the required target type.
|
||||
viable_generators = []
|
||||
initial_generators = []
|
||||
|
||||
import type
|
||||
from . import type
|
||||
|
||||
# Try all-type generators first. Assume they have
|
||||
# quite specific requirements.
|
||||
@@ -949,6 +1047,8 @@ def find_viable_generators_aux (target_type, prop_set):
|
||||
return viable_generators
|
||||
|
||||
def find_viable_generators (target_type, prop_set):
|
||||
assert isinstance(target_type, basestring)
|
||||
assert isinstance(prop_set, property_set.PropertySet)
|
||||
key = target_type + '.' + str (prop_set)
|
||||
|
||||
l = __viable_generators_cache.get (key, None)
|
||||
@@ -994,6 +1094,13 @@ def __construct_really (project, name, target_type, prop_set, sources):
|
||||
""" Attempts to construct target by finding viable generators, running them
|
||||
and selecting the dependency graph.
|
||||
"""
|
||||
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)
|
||||
viable_generators = find_viable_generators (target_type, prop_set)
|
||||
|
||||
result = []
|
||||
@@ -1048,7 +1155,14 @@ def construct (project, name, target_type, prop_set, sources, top_level=False):
|
||||
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
|
||||
@@ -1086,7 +1200,7 @@ def add_usage_requirements (result, raw_properties):
|
||||
if isinstance (result[0], property_set.PropertySet):
|
||||
return (result[0].add_raw(raw_properties), result[1])
|
||||
else:
|
||||
return (propery_set.create(raw-properties), result)
|
||||
return (property_set.create(raw_properties), result)
|
||||
#if [ class.is-a $(result[1]) : property-set ]
|
||||
#{
|
||||
# return [ $(result[1]).add-raw $(raw-properties) ] $(result[2-]) ;
|
||||
|
||||
@@ -40,9 +40,10 @@
|
||||
# their project id.
|
||||
|
||||
import b2.util.path
|
||||
import b2.build.targets
|
||||
from b2.build import property_set, property
|
||||
from b2.build.errors import ExceptionWithUserContext
|
||||
import b2.build.targets
|
||||
from b2.manager import get_manager
|
||||
|
||||
import bjam
|
||||
import b2
|
||||
@@ -56,7 +57,10 @@ import imp
|
||||
import traceback
|
||||
import b2.util.option as option
|
||||
|
||||
from b2.util import record_jam_to_value_mapping, qualify_jam_action
|
||||
from b2.util import (
|
||||
record_jam_to_value_mapping, qualify_jam_action, is_iterable_typed, bjam_signature,
|
||||
is_iterable)
|
||||
|
||||
|
||||
class ProjectRegistry:
|
||||
|
||||
@@ -130,6 +134,7 @@ class ProjectRegistry:
|
||||
file and jamfile needed by the loaded one will be loaded recursively.
|
||||
If the jamfile at that location is loaded already, does nothing.
|
||||
Returns the project module for the Jamfile."""
|
||||
assert isinstance(jamfile_location, basestring)
|
||||
|
||||
absolute = os.path.join(os.getcwd(), jamfile_location)
|
||||
absolute = os.path.normpath(absolute)
|
||||
@@ -159,6 +164,7 @@ class ProjectRegistry:
|
||||
return mname
|
||||
|
||||
def load_used_projects(self, module_name):
|
||||
assert isinstance(module_name, basestring)
|
||||
# local used = [ modules.peek $(module-name) : .used-projects ] ;
|
||||
used = self.used_projects[module_name]
|
||||
|
||||
@@ -172,7 +178,7 @@ class ProjectRegistry:
|
||||
def load_parent(self, location):
|
||||
"""Loads parent of Jamfile at 'location'.
|
||||
Issues an error if nothing is found."""
|
||||
|
||||
assert isinstance(location, basestring)
|
||||
found = b2.util.path.glob_in_parents(
|
||||
location, self.JAMROOT + self.JAMFILE)
|
||||
|
||||
@@ -187,6 +193,8 @@ class ProjectRegistry:
|
||||
"""Given 'name' which can be project-id or plain directory name,
|
||||
return project module corresponding to that id or directory.
|
||||
Returns nothing of project is not found."""
|
||||
assert isinstance(name, basestring)
|
||||
assert isinstance(current_location, basestring)
|
||||
|
||||
project_module = None
|
||||
|
||||
@@ -214,6 +222,7 @@ class ProjectRegistry:
|
||||
"""Returns the name of module corresponding to 'jamfile-location'.
|
||||
If no module corresponds to location yet, associates default
|
||||
module name with that location."""
|
||||
assert isinstance(jamfile_location, basestring)
|
||||
module = self.location2module.get(jamfile_location)
|
||||
if not module:
|
||||
# Root the path, so that locations are always umbiguious.
|
||||
@@ -230,6 +239,9 @@ class ProjectRegistry:
|
||||
exact names of all the Jamfiles in the given directory. The optional
|
||||
parent-root argument causes this to search not the given directory
|
||||
but the ones above it up to the directory given in it."""
|
||||
assert isinstance(dir, basestring)
|
||||
assert isinstance(parent_root, (int, bool))
|
||||
assert isinstance(no_errors, (int, bool))
|
||||
|
||||
# Glob for all the possible Jamfiles according to the match pattern.
|
||||
#
|
||||
@@ -280,6 +292,8 @@ Please consult the documentation at 'http://boost.org/boost-build2'."""
|
||||
"""Load a Jamfile at the given directory. Returns nothing.
|
||||
Will attempt to load the file as indicated by the JAMFILE patterns.
|
||||
Effect of calling this rule twice with the same 'dir' is underfined."""
|
||||
assert isinstance(dir, basestring)
|
||||
assert isinstance(jamfile_module, basestring)
|
||||
|
||||
# See if the Jamfile is where it should be.
|
||||
is_jamroot = False
|
||||
@@ -359,12 +373,15 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project))
|
||||
The caller is required to never call this method twice on
|
||||
the same file.
|
||||
"""
|
||||
assert isinstance(jamfile_module, basestring)
|
||||
assert isinstance(file, basestring)
|
||||
|
||||
self.used_projects[jamfile_module] = []
|
||||
bjam.call("load", jamfile_module, file)
|
||||
self.load_used_projects(jamfile_module)
|
||||
|
||||
def is_jamroot(self, basename):
|
||||
assert isinstance(basename, basestring)
|
||||
match = [ pat for pat in self.JAMROOT if re.match(pat, basename)]
|
||||
if match:
|
||||
return 1
|
||||
@@ -378,7 +395,9 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project))
|
||||
location is the location (directory) of the project to initialize.
|
||||
If not specified, standalone project will be initialized
|
||||
"""
|
||||
|
||||
assert isinstance(module_name, basestring)
|
||||
assert isinstance(location, basestring) or location is None
|
||||
assert isinstance(basename, basestring) or basename is None
|
||||
if "--debug-loading" in self.manager.argv():
|
||||
print "Initializing project '%s'" % module_name
|
||||
|
||||
@@ -465,6 +484,8 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project))
|
||||
def inherit_attributes(self, project_module, parent_module):
|
||||
"""Make 'project-module' inherit attributes of project
|
||||
root and parent module."""
|
||||
assert isinstance(project_module, basestring)
|
||||
assert isinstance(parent_module, basestring)
|
||||
|
||||
attributes = self.module2attributes[project_module]
|
||||
pattributes = self.module2attributes[parent_module]
|
||||
@@ -502,6 +523,8 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project))
|
||||
|
||||
def register_id(self, id, module):
|
||||
"""Associate the given id with the given project module."""
|
||||
assert isinstance(id, basestring)
|
||||
assert isinstance(module, basestring)
|
||||
self.id2module[id] = module
|
||||
|
||||
def current(self):
|
||||
@@ -509,11 +532,17 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project))
|
||||
return self.current_project
|
||||
|
||||
def set_current(self, c):
|
||||
if __debug__:
|
||||
from .targets import ProjectTarget
|
||||
assert isinstance(c, ProjectTarget)
|
||||
self.current_project = c
|
||||
|
||||
def push_current(self, project):
|
||||
"""Temporary changes the current project to 'project'. Should
|
||||
be followed by 'pop-current'."""
|
||||
if __debug__:
|
||||
from .targets import ProjectTarget
|
||||
assert isinstance(project, ProjectTarget)
|
||||
self.saved_current_project.append(self.current_project)
|
||||
self.current_project = project
|
||||
|
||||
@@ -524,11 +553,14 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project))
|
||||
def attributes(self, project):
|
||||
"""Returns the project-attribute instance for the
|
||||
specified jamfile module."""
|
||||
assert isinstance(project, basestring)
|
||||
return self.module2attributes[project]
|
||||
|
||||
def attribute(self, project, attribute):
|
||||
"""Returns the value of the specified attribute in the
|
||||
specified jamfile module."""
|
||||
assert isinstance(project, basestring)
|
||||
assert isinstance(attribute, basestring)
|
||||
try:
|
||||
return self.module2attributes[project].get(attribute)
|
||||
except:
|
||||
@@ -537,10 +569,14 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project))
|
||||
def attributeDefault(self, project, attribute, default):
|
||||
"""Returns the value of the specified attribute in the
|
||||
specified jamfile module."""
|
||||
assert isinstance(project, basestring)
|
||||
assert isinstance(attribute, basestring)
|
||||
assert isinstance(default, basestring) or default is None
|
||||
return self.module2attributes[project].getDefault(attribute, default)
|
||||
|
||||
def target(self, project_module):
|
||||
"""Returns the project target corresponding to the 'project-module'."""
|
||||
assert isinstance(project_module, basestring)
|
||||
if not self.module2target.has_key(project_module):
|
||||
self.module2target[project_module] = \
|
||||
b2.build.targets.ProjectTarget(project_module, project_module,
|
||||
@@ -550,6 +586,8 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project))
|
||||
|
||||
def use(self, id, location):
|
||||
# Use/load a project.
|
||||
assert isinstance(id, basestring)
|
||||
assert isinstance(location, basestring)
|
||||
saved_project = self.current_project
|
||||
project_module = self.load(location)
|
||||
declared_id = self.attributeDefault(project_module, "id", "")
|
||||
@@ -564,16 +602,24 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project))
|
||||
|
||||
self.current_module = saved_project
|
||||
|
||||
def add_rule(self, name, callable):
|
||||
def add_rule(self, name, callable_):
|
||||
"""Makes rule 'name' available to all subsequently loaded Jamfiles.
|
||||
|
||||
Calling that rule wil relay to 'callable'."""
|
||||
self.project_rules_.add_rule(name, callable)
|
||||
assert isinstance(name, basestring)
|
||||
assert callable(callable_)
|
||||
self.project_rules_.add_rule(name, callable_)
|
||||
|
||||
def project_rules(self):
|
||||
return self.project_rules_
|
||||
|
||||
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 = []
|
||||
@@ -656,6 +702,8 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project))
|
||||
since then we might get naming conflicts between standard
|
||||
Python modules and those.
|
||||
"""
|
||||
assert isinstance(name, basestring)
|
||||
assert is_iterable_typed(extra_path, basestring) or extra_path is None
|
||||
# See if we loaded module of this name already
|
||||
existing = self.loaded_tool_modules_.get(name)
|
||||
if existing:
|
||||
@@ -774,7 +822,20 @@ class ProjectAttributes:
|
||||
def set(self, attribute, specification, exact=False):
|
||||
"""Set the named attribute from the specification given by the user.
|
||||
The value actually set may be different."""
|
||||
|
||||
assert isinstance(attribute, basestring)
|
||||
assert isinstance(exact, (int, bool))
|
||||
if __debug__ and not exact:
|
||||
if attribute == 'requirements':
|
||||
assert (isinstance(specification, property_set.PropertySet)
|
||||
or all(isinstance(s, basestring) for s in specification))
|
||||
elif attribute in (
|
||||
'usage-requirements', 'default-build', 'source-location', 'build-dir', 'id'):
|
||||
assert is_iterable_typed(specification, basestring)
|
||||
elif __debug__:
|
||||
assert (
|
||||
isinstance(specification, (property_set.PropertySet, type(None), basestring))
|
||||
or all(isinstance(s, basestring) for s in specification)
|
||||
)
|
||||
if exact:
|
||||
self.__dict__[attribute] = specification
|
||||
|
||||
@@ -838,9 +899,11 @@ for project at '%s'""" % (attribute, self.location))
|
||||
self.__dict__[attribute] = specification
|
||||
|
||||
def get(self, attribute):
|
||||
assert isinstance(attribute, basestring)
|
||||
return self.__dict__[attribute]
|
||||
|
||||
def getDefault(self, attribute, default):
|
||||
assert isinstance(attribute, basestring)
|
||||
return self.__dict__.get(attribute, default)
|
||||
|
||||
def dump(self):
|
||||
@@ -876,41 +939,51 @@ class ProjectRules:
|
||||
"error_reporting_wrapper", "add_rule_for_type", "reverse"]]
|
||||
self.all_names_ = [x for x in self.local_names]
|
||||
|
||||
def _import_rule(self, bjam_module, name, callable):
|
||||
if hasattr(callable, "bjam_signature"):
|
||||
bjam.import_rule(bjam_module, name, self.make_wrapper(callable), callable.bjam_signature)
|
||||
def _import_rule(self, bjam_module, name, callable_):
|
||||
assert isinstance(bjam_module, basestring)
|
||||
assert isinstance(name, basestring)
|
||||
assert callable(callable_)
|
||||
if hasattr(callable_, "bjam_signature"):
|
||||
bjam.import_rule(bjam_module, name, self.make_wrapper(callable_), callable_.bjam_signature)
|
||||
else:
|
||||
bjam.import_rule(bjam_module, name, self.make_wrapper(callable))
|
||||
bjam.import_rule(bjam_module, name, self.make_wrapper(callable_))
|
||||
|
||||
|
||||
def add_rule_for_type(self, type):
|
||||
assert isinstance(type, basestring)
|
||||
rule_name = type.lower().replace("_", "-")
|
||||
|
||||
def xpto (name, sources = [], requirements = [], default_build = [], usage_requirements = []):
|
||||
@bjam_signature([['name'], ['sources', '*'], ['requirements', '*'],
|
||||
['default_build', '*'], ['usage_requirements', '*']])
|
||||
def xpto (name, sources=[], requirements=[], default_build=[], usage_requirements=[]):
|
||||
|
||||
return self.manager_.targets().create_typed_target(
|
||||
type, self.registry.current(), name[0], sources,
|
||||
type, self.registry.current(), name, sources,
|
||||
requirements, default_build, usage_requirements)
|
||||
|
||||
self.add_rule(rule_name, xpto)
|
||||
|
||||
def add_rule(self, name, callable):
|
||||
self.rules[name] = callable
|
||||
def add_rule(self, name, callable_):
|
||||
assert isinstance(name, basestring)
|
||||
assert callable(callable_)
|
||||
self.rules[name] = callable_
|
||||
self.all_names_.append(name)
|
||||
|
||||
# Add new rule at global bjam scope. This might not be ideal,
|
||||
# added because if a jamroot does 'import foo' where foo calls
|
||||
# add_rule, we need to import new rule to jamroot scope, and
|
||||
# I'm lazy to do this now.
|
||||
self._import_rule("", name, callable)
|
||||
self._import_rule("", name, callable_)
|
||||
|
||||
def all_names(self):
|
||||
return self.all_names_
|
||||
|
||||
def call_and_report_errors(self, callable, *args, **kw):
|
||||
def call_and_report_errors(self, callable_, *args, **kw):
|
||||
assert callable(callable_)
|
||||
result = None
|
||||
try:
|
||||
self.manager_.errors().push_jamfile_context()
|
||||
result = callable(*args, **kw)
|
||||
result = callable_(*args, **kw)
|
||||
except ExceptionWithUserContext, e:
|
||||
e.report()
|
||||
except Exception, e:
|
||||
@@ -923,16 +996,18 @@ class ProjectRules:
|
||||
|
||||
return result
|
||||
|
||||
def make_wrapper(self, callable):
|
||||
def make_wrapper(self, callable_):
|
||||
"""Given a free-standing function 'callable', return a new
|
||||
callable that will call 'callable' and report all exceptins,
|
||||
using 'call_and_report_errors'."""
|
||||
assert callable(callable_)
|
||||
def wrapper(*args, **kw):
|
||||
return self.call_and_report_errors(callable, *args, **kw)
|
||||
return self.call_and_report_errors(callable_, *args, **kw)
|
||||
return wrapper
|
||||
|
||||
def init_project(self, project_module, python_standalone=False):
|
||||
|
||||
assert isinstance(project_module, basestring)
|
||||
assert isinstance(python_standalone, bool)
|
||||
if python_standalone:
|
||||
m = sys.modules[project_module]
|
||||
|
||||
@@ -961,7 +1036,7 @@ class ProjectRules:
|
||||
self._import_rule(project_module, n, self.rules[n])
|
||||
|
||||
def project(self, *args):
|
||||
|
||||
assert is_iterable(args) and all(is_iterable(arg) for arg in args)
|
||||
jamfile_module = self.registry.current().project_module()
|
||||
attributes = self.registry.attributes(jamfile_module)
|
||||
|
||||
@@ -1017,7 +1092,8 @@ attribute is allowed only for top-level 'project' invocations""")
|
||||
"""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."""
|
||||
m = "Jamfile</home/ghost/Work/Boost/boost-svn/tools/build/v2_python/python/tests/bjam/make>"
|
||||
assert is_iterable_typed(name, basestring)
|
||||
assert is_iterable_typed(value, basestring)
|
||||
self.registry.current().add_constant(name[0], value)
|
||||
|
||||
def path_constant(self, name, value):
|
||||
@@ -1025,6 +1101,8 @@ attribute is allowed only for top-level 'project' invocations""")
|
||||
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)
|
||||
@@ -1032,27 +1110,35 @@ attribute is allowed only for top-level 'project' invocations""")
|
||||
def use_project(self, id, where):
|
||||
# See comment in 'load' for explanation why we record the
|
||||
# parameters as opposed to loading the project now.
|
||||
m = self.registry.current().project_module();
|
||||
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]))
|
||||
|
||||
def build_project(self, dir):
|
||||
assert(isinstance(dir, list))
|
||||
assert is_iterable_typed(dir, basestring)
|
||||
jamfile_module = self.registry.current().project_module()
|
||||
attributes = self.registry.attributes(jamfile_module)
|
||||
now = attributes.get("projects-to-build")
|
||||
attributes.set("projects-to-build", now + dir, exact=True)
|
||||
|
||||
def explicit(self, target_names):
|
||||
assert is_iterable_typed(target_names, basestring)
|
||||
self.registry.current().mark_targets_as_explicit(target_names)
|
||||
|
||||
def always(self, target_names):
|
||||
assert is_iterable_typed(target_names, basestring)
|
||||
self.registry.current().mark_targets_as_alays(target_names)
|
||||
|
||||
def glob(self, wildcards, excludes=None):
|
||||
assert is_iterable_typed(wildcards, basestring)
|
||||
assert is_iterable_typed(excludes, basestring)or excludes is None
|
||||
return self.registry.glob_internal(self.registry.current(),
|
||||
wildcards, excludes, "glob")
|
||||
|
||||
def glob_tree(self, wildcards, excludes=None):
|
||||
assert is_iterable_typed(wildcards, basestring)
|
||||
assert is_iterable_typed(excludes, basestring) or excludes is None
|
||||
bad = 0
|
||||
for p in wildcards:
|
||||
if os.path.dirname(p):
|
||||
@@ -1076,6 +1162,7 @@ attribute is allowed only for top-level 'project' invocations""")
|
||||
# will expect the module to be found even though
|
||||
# the directory is not in BOOST_BUILD_PATH.
|
||||
# So temporary change the search path.
|
||||
assert is_iterable_typed(toolset, basestring)
|
||||
current = self.registry.current()
|
||||
location = current.get('location')
|
||||
|
||||
@@ -1090,7 +1177,9 @@ attribute is allowed only for top-level 'project' invocations""")
|
||||
self.registry.set_current(current)
|
||||
|
||||
def import_(self, name, names_to_import=None, local_names=None):
|
||||
|
||||
assert is_iterable_typed(name, basestring)
|
||||
assert is_iterable_typed(names_to_import, basestring) or names_to_import is None
|
||||
assert is_iterable_typed(local_names, basestring)or local_names is None
|
||||
name = name[0]
|
||||
py_name = name
|
||||
if py_name == "os":
|
||||
@@ -1133,7 +1222,8 @@ attribute is allowed only for top-level 'project' invocations""")
|
||||
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]
|
||||
@@ -1141,6 +1231,8 @@ attribute is allowed only for top-level 'project' invocations""")
|
||||
return [c + ":" + r for r in requirements]
|
||||
|
||||
def option(self, name, value):
|
||||
assert is_iterable(name) and isinstance(name[0], basestring)
|
||||
assert is_iterable(value) and isinstance(value[0], basestring)
|
||||
name = name[0]
|
||||
if not name in ["site-config", "user-config", "project-config"]:
|
||||
get_manager().errors()("The 'option' rule may be used only in site-config or user-config")
|
||||
|
||||
@@ -11,7 +11,7 @@ import re
|
||||
import sys
|
||||
from b2.util.utility import *
|
||||
from b2.build import feature
|
||||
from b2.util import sequence, qualify_jam_action
|
||||
from b2.util import sequence, qualify_jam_action, is_iterable_typed
|
||||
import b2.util.set
|
||||
from b2.manager import get_manager
|
||||
|
||||
@@ -70,7 +70,9 @@ class Property(object):
|
||||
|
||||
|
||||
def create_from_string(s, allow_condition=False,allow_missing_value=False):
|
||||
|
||||
assert isinstance(s, basestring)
|
||||
assert isinstance(allow_condition, bool)
|
||||
assert isinstance(allow_missing_value, bool)
|
||||
condition = []
|
||||
import types
|
||||
if not isinstance(s, types.StringType):
|
||||
@@ -119,11 +121,11 @@ def create_from_string(s, allow_condition=False,allow_missing_value=False):
|
||||
|
||||
if condition:
|
||||
condition = [create_from_string(x) for x in condition.split(',')]
|
||||
|
||||
|
||||
return Property(f, value, condition)
|
||||
|
||||
def create_from_strings(string_list, allow_condition=False):
|
||||
|
||||
assert is_iterable_typed(string_list, basestring)
|
||||
return [create_from_string(s, allow_condition) for s in string_list]
|
||||
|
||||
def reset ():
|
||||
@@ -185,6 +187,8 @@ def refine (properties, 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()
|
||||
|
||||
@@ -242,6 +246,8 @@ def translate_indirect(properties, context_module):
|
||||
names of rules, used in 'context-module'. Such rules can be
|
||||
either local to the module or global. Qualified local rules
|
||||
with the name of the module."""
|
||||
assert is_iterable_typed(properties, Property)
|
||||
assert isinstance(context_module, basestring)
|
||||
result = []
|
||||
for p in properties:
|
||||
if p.value()[0] == '@':
|
||||
@@ -257,15 +263,14 @@ 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, str):
|
||||
__validate1 (properties)
|
||||
else:
|
||||
for p in properties:
|
||||
__validate1 (p)
|
||||
if isinstance(properties, Property):
|
||||
properties = [properties]
|
||||
assert is_iterable_typed(properties, Property)
|
||||
for p in properties:
|
||||
__validate1(p)
|
||||
|
||||
def expand_subfeatures_in_conditions (properties):
|
||||
|
||||
assert is_iterable_typed(properties, Property)
|
||||
result = []
|
||||
for p in properties:
|
||||
|
||||
@@ -296,6 +301,7 @@ def split_conditional (property):
|
||||
<variant>debug,<toolset>gcc <inlining>full.
|
||||
Otherwise, returns empty string.
|
||||
"""
|
||||
assert isinstance(property, basestring)
|
||||
m = __re_split_conditional.match (property)
|
||||
|
||||
if m:
|
||||
@@ -307,6 +313,7 @@ def split_conditional (property):
|
||||
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
|
||||
@@ -315,6 +322,9 @@ def select (features, properties):
|
||||
return [p for p in properties if get_grist(p) in features]
|
||||
|
||||
def validate_property_sets (sets):
|
||||
if __debug__:
|
||||
from .property_set import PropertySet
|
||||
assert is_iterable_typed(sets, PropertySet)
|
||||
for s in sets:
|
||||
validate(s.all())
|
||||
|
||||
@@ -323,6 +333,10 @@ def evaluate_conditionals_in_context (properties, context):
|
||||
For those with met conditions, removes the condition. Properies
|
||||
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 = []
|
||||
|
||||
@@ -348,8 +362,11 @@ def change (properties, feature, value = None):
|
||||
given feature replaced by the given value.
|
||||
If 'value' is None the feature will be removed.
|
||||
"""
|
||||
assert is_iterable_typed(properties, basestring)
|
||||
assert isinstance(feature, basestring)
|
||||
assert isinstance(value, (basestring, type(None)))
|
||||
result = []
|
||||
|
||||
|
||||
feature = add_grist (feature)
|
||||
|
||||
for p in properties:
|
||||
@@ -368,7 +385,8 @@ def change (properties, feature, value = None):
|
||||
|
||||
def __validate1 (property):
|
||||
""" Exit with error if property is not valid.
|
||||
"""
|
||||
"""
|
||||
assert isinstance(property, Property)
|
||||
msg = None
|
||||
|
||||
if not property.feature().free():
|
||||
@@ -405,7 +423,10 @@ def __validate1 (property):
|
||||
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))
|
||||
@@ -424,6 +445,8 @@ def remove(attributes, properties):
|
||||
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))):
|
||||
@@ -431,7 +454,9 @@ def take(attributes, properties):
|
||||
return result
|
||||
|
||||
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:
|
||||
|
||||
@@ -464,10 +489,12 @@ class PropertyMap:
|
||||
def __init__ (self):
|
||||
self.__properties = []
|
||||
self.__values = []
|
||||
|
||||
|
||||
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)
|
||||
|
||||
@@ -477,9 +504,12 @@ class PropertyMap:
|
||||
subset has value assigned to it, return the
|
||||
value for the longest subset, if it's unique.
|
||||
"""
|
||||
assert is_iterable_typed(properties, basestring)
|
||||
return self.find_replace (properties)
|
||||
|
||||
def find_replace(self, properties, value=None):
|
||||
assert is_iterable_typed(properties, basestring)
|
||||
assert isinstance(value, (basestring, type(None)))
|
||||
matches = []
|
||||
match_ranks = []
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
import hashlib
|
||||
|
||||
import bjam
|
||||
from b2.util.utility import *
|
||||
import property, feature
|
||||
import b2.build.feature
|
||||
@@ -15,7 +16,7 @@ from b2.exceptions import *
|
||||
from b2.build.property import get_abbreviated_paths
|
||||
from b2.util.sequence import unique
|
||||
from b2.util.set import difference
|
||||
from b2.util import cached, abbreviate_dashed
|
||||
from b2.util import cached, abbreviate_dashed, is_iterable_typed
|
||||
|
||||
from b2.manager import get_manager
|
||||
|
||||
@@ -36,6 +37,8 @@ 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
|
||||
@@ -58,6 +61,7 @@ def create_with_validation (raw_properties):
|
||||
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)
|
||||
|
||||
@@ -71,7 +75,9 @@ def empty ():
|
||||
def create_from_user_input(raw_properties, jamfile_module, location):
|
||||
"""Creates a property-set from the input given by the user, in the
|
||||
context of 'jamfile-module' at 'location'"""
|
||||
|
||||
assert is_iterable_typed(raw_properties, basestring)
|
||||
assert isinstance(jamfile_module, basestring)
|
||||
assert isinstance(location, basestring)
|
||||
properties = property.create_from_strings(raw_properties, True)
|
||||
properties = property.translate_paths(properties, location)
|
||||
properties = property.translate_indirect(properties, jamfile_module)
|
||||
@@ -95,7 +101,10 @@ def refine_from_user_input(parent_requirements, specification, jamfile_module,
|
||||
- project-module -- the module to which context indirect features
|
||||
will be bound.
|
||||
- location -- the path to which path features are relative."""
|
||||
|
||||
assert isinstance(parent_requirements, PropertySet)
|
||||
assert is_iterable_typed(specification, basestring)
|
||||
assert isinstance(jamfile_module, basestring)
|
||||
assert isinstance(location, basestring)
|
||||
|
||||
if not specification:
|
||||
return parent_requirements
|
||||
@@ -146,7 +155,7 @@ class PropertySet:
|
||||
caching whenever possible.
|
||||
"""
|
||||
def __init__ (self, properties = []):
|
||||
|
||||
assert is_iterable_typed(properties, property.Property)
|
||||
|
||||
raw_properties = []
|
||||
for p in properties:
|
||||
@@ -304,6 +313,7 @@ class PropertySet:
|
||||
return self.subfeatures_
|
||||
|
||||
def evaluate_conditionals(self, context=None):
|
||||
assert isinstance(context, (PropertySet, type(None)))
|
||||
if not context:
|
||||
context = self
|
||||
|
||||
@@ -410,6 +420,7 @@ class PropertySet:
|
||||
""" Creates a new property set containing the properties in this one,
|
||||
plus the ones of the property set passed as argument.
|
||||
"""
|
||||
assert isinstance(ps, PropertySet)
|
||||
if not self.added_.has_key(ps):
|
||||
self.added_[ps] = create(self.all_ + ps.all())
|
||||
return self.added_[ps]
|
||||
@@ -428,6 +439,7 @@ class PropertySet:
|
||||
feature = feature[0]
|
||||
if not isinstance(feature, b2.build.feature.Feature):
|
||||
feature = b2.build.feature.get(feature)
|
||||
assert isinstance(feature, b2.build.feature.Feature)
|
||||
|
||||
if not self.feature_map_:
|
||||
self.feature_map_ = {}
|
||||
@@ -442,9 +454,9 @@ class PropertySet:
|
||||
@cached
|
||||
def get_properties(self, feature):
|
||||
"""Returns all contained properties associated with 'feature'"""
|
||||
|
||||
if not isinstance(feature, b2.build.feature.Feature):
|
||||
feature = b2.build.feature.get(feature)
|
||||
assert isinstance(feature, b2.build.feature.Feature)
|
||||
|
||||
result = []
|
||||
for p in self.all_:
|
||||
|
||||
@@ -34,6 +34,8 @@ import bjam
|
||||
import os
|
||||
from b2.exceptions import *
|
||||
from b2.manager import get_manager
|
||||
from b2.util import is_iterable_typed
|
||||
|
||||
|
||||
def reset ():
|
||||
""" Clear the module state. This is mainly for testing purposes.
|
||||
@@ -56,6 +58,8 @@ def register(scanner_class, relevant_properties):
|
||||
properties relevant to this scanner. Ctor for that class
|
||||
should have one parameter: list of properties.
|
||||
"""
|
||||
assert issubclass(scanner_class, Scanner)
|
||||
assert isinstance(relevant_properties, basestring)
|
||||
__scanners[str(scanner_class)] = relevant_properties
|
||||
|
||||
def registered(scanner_class):
|
||||
@@ -67,6 +71,8 @@ def get(scanner_class, properties):
|
||||
""" Returns an instance of previously registered scanner
|
||||
with the specified properties.
|
||||
"""
|
||||
assert issubclass(scanner_class, Scanner)
|
||||
assert is_iterable_typed(properties, basestring)
|
||||
scanner_name = str(scanner_class)
|
||||
|
||||
if not registered(scanner_name):
|
||||
@@ -130,6 +136,9 @@ class ScannerRegistry:
|
||||
""" Installs the specified scanner on actual target 'target'.
|
||||
vtarget: virtual target from which 'target' was actualized.
|
||||
"""
|
||||
assert isinstance(scanner, Scanner)
|
||||
assert isinstance(target, basestring)
|
||||
assert isinstance(vtarget, basestring)
|
||||
engine = self.manager_.engine()
|
||||
engine.set_target_variable(target, "HDRSCAN", scanner.pattern())
|
||||
if not self.exported_scanners_.has_key(scanner):
|
||||
@@ -150,6 +159,8 @@ class ScannerRegistry:
|
||||
pass
|
||||
|
||||
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",
|
||||
|
||||
@@ -81,7 +81,7 @@ import property, project, virtual_target, property_set, feature, generators, too
|
||||
from virtual_target import Subvariant
|
||||
from b2.exceptions import *
|
||||
from b2.util.sequence import unique
|
||||
from b2.util import path, bjam_signature
|
||||
from b2.util import path, bjam_signature, safe_isinstance, is_iterable_typed
|
||||
from b2.build.errors import user_error_checkpoint
|
||||
|
||||
import b2.build.build_request as build_request
|
||||
@@ -107,6 +107,7 @@ class TargetRegistry:
|
||||
""" Registers the specified target as a main target alternatives.
|
||||
Returns 'target'.
|
||||
"""
|
||||
assert isinstance(target, AbstractTarget)
|
||||
target.project ().add_alternative (target)
|
||||
return target
|
||||
|
||||
@@ -116,6 +117,9 @@ class TargetRegistry:
|
||||
as main target instances, and the name of such targets are adjusted to
|
||||
be '<name_of_this_target>__<name_of_source_target>'. Such renaming
|
||||
is disabled is non-empty value is passed for 'no-renaming' parameter."""
|
||||
assert is_iterable_typed(sources, basestring)
|
||||
assert isinstance(main_target_name, basestring)
|
||||
assert isinstance(no_renaming, (int, bool))
|
||||
result = []
|
||||
|
||||
for t in sources:
|
||||
@@ -149,7 +153,8 @@ class TargetRegistry:
|
||||
'specification' are the properties xplicitly specified for a
|
||||
main target
|
||||
'project' is the project where the main taret is to be declared."""
|
||||
|
||||
assert is_iterable_typed(specification, basestring)
|
||||
assert isinstance(project, ProjectTarget)
|
||||
specification.extend(toolset.requirements())
|
||||
|
||||
requirements = property_set.refine_from_user_input(
|
||||
@@ -166,6 +171,8 @@ class TargetRegistry:
|
||||
specification: Use-properties explicitly specified for a main target
|
||||
project: Project where the main target is to be declared
|
||||
"""
|
||||
assert is_iterable_typed(specification, basestring)
|
||||
assert isinstance(project, ProjectTarget)
|
||||
project_usage_requirements = project.get ('usage-requirements')
|
||||
|
||||
# We don't use 'refine-from-user-input' because I'm not sure if:
|
||||
@@ -184,6 +191,8 @@ class TargetRegistry:
|
||||
specification: Default build explicitly specified for a main target
|
||||
project: Project where the main target is to be declared
|
||||
"""
|
||||
assert is_iterable_typed(specification, basestring)
|
||||
assert isinstance(project, ProjectTarget)
|
||||
if specification:
|
||||
return property_set.create_with_validation(specification)
|
||||
else:
|
||||
@@ -192,6 +201,7 @@ class TargetRegistry:
|
||||
def start_building (self, main_target_instance):
|
||||
""" Helper rules to detect cycles in main target references.
|
||||
"""
|
||||
assert isinstance(main_target_instance, MainTarget)
|
||||
if self.targets_being_built_.has_key(id(main_target_instance)):
|
||||
names = []
|
||||
for t in self.targets_being_built_.values() + [main_target_instance]:
|
||||
@@ -202,6 +212,7 @@ class TargetRegistry:
|
||||
self.targets_being_built_[id(main_target_instance)] = main_target_instance
|
||||
|
||||
def end_building (self, main_target_instance):
|
||||
assert isinstance(main_target_instance, MainTarget)
|
||||
assert (self.targets_being_built_.has_key (id (main_target_instance)))
|
||||
del self.targets_being_built_ [id (main_target_instance)]
|
||||
|
||||
@@ -211,6 +222,11 @@ class TargetRegistry:
|
||||
'usage_requirements' are assumed to be in the form specified
|
||||
by the user in Jamfile corresponding to 'project'.
|
||||
"""
|
||||
assert isinstance(type, basestring)
|
||||
assert isinstance(project, ProjectTarget)
|
||||
assert is_iterable_typed(sources, basestring)
|
||||
assert is_iterable_typed(requirements, basestring)
|
||||
assert is_iterable_typed(default_build, basestring)
|
||||
return self.main_target_alternative (TypedTarget (name, project, type,
|
||||
self.main_target_sources (sources, name),
|
||||
self.main_target_requirements (requirements, project),
|
||||
@@ -231,6 +247,7 @@ class TargetRegistry:
|
||||
print self.indent_ + message
|
||||
|
||||
def push_target(self, target):
|
||||
assert isinstance(target, AbstractTarget)
|
||||
self.targets_.append(target)
|
||||
|
||||
def pop_target(self):
|
||||
@@ -245,10 +262,10 @@ class GenerateResult:
|
||||
def __init__ (self, ur=None, targets=None):
|
||||
if not targets:
|
||||
targets = []
|
||||
|
||||
assert isinstance(ur, property_set.PropertySet) or ur is None
|
||||
assert is_iterable_typed(targets, virtual_target.VirtualTarget)
|
||||
self.__usage_requirements = ur
|
||||
self.__targets = targets
|
||||
assert all(isinstance(t, virtual_target.VirtualTarget) for t in targets)
|
||||
|
||||
if not self.__usage_requirements:
|
||||
self.__usage_requirements = property_set.empty ()
|
||||
@@ -274,6 +291,7 @@ class AbstractTarget:
|
||||
project: the project target to which this one belongs
|
||||
manager:the manager object. If none, uses project.manager ()
|
||||
"""
|
||||
assert isinstance(name, basestring)
|
||||
assert (isinstance (project, ProjectTarget))
|
||||
# Note: it might seem that we don't need either name or project at all.
|
||||
# However, there are places where we really need it. One example is error
|
||||
@@ -329,6 +347,7 @@ class AbstractTarget:
|
||||
raise BaseException ("method should be defined in derived classes")
|
||||
|
||||
def rename (self, new_name):
|
||||
assert isinstance(new_name, basestring)
|
||||
self.name_ = new_name
|
||||
|
||||
class ProjectTarget (AbstractTarget):
|
||||
@@ -346,6 +365,10 @@ class ProjectTarget (AbstractTarget):
|
||||
all alternatives are enumerated an main targets are created.
|
||||
"""
|
||||
def __init__ (self, manager, name, project_module, parent_project, requirements, default_build):
|
||||
assert isinstance(project_module, basestring)
|
||||
assert isinstance(parent_project, (ProjectTarget, type(None)))
|
||||
assert isinstance(requirements, (type(None), property_set.PropertySet))
|
||||
assert isinstance(default_build, (type(None), property_set.PropertySet))
|
||||
AbstractTarget.__init__ (self, name, self, manager)
|
||||
|
||||
self.project_module_ = project_module
|
||||
@@ -390,6 +413,7 @@ class ProjectTarget (AbstractTarget):
|
||||
return self.project_module_
|
||||
|
||||
def get (self, attribute):
|
||||
assert isinstance(attribute, basestring)
|
||||
return self.manager().projects().attribute(
|
||||
self.project_module_, attribute)
|
||||
|
||||
@@ -404,6 +428,7 @@ class ProjectTarget (AbstractTarget):
|
||||
def generate (self, ps):
|
||||
""" Generates all possible targets contained in this project.
|
||||
"""
|
||||
assert isinstance(ps, property_set.PropertySet)
|
||||
self.manager_.targets().log(
|
||||
"Building project '%s' with '%s'" % (self.name (), str(ps)))
|
||||
self.manager_.targets().increase_indent ()
|
||||
@@ -444,20 +469,24 @@ class ProjectTarget (AbstractTarget):
|
||||
|
||||
# Record the name of the target, not instance, since this
|
||||
# rule is called before main target instaces are created.
|
||||
assert is_iterable_typed(target_names, basestring)
|
||||
self.explicit_targets_.update(target_names)
|
||||
|
||||
def mark_targets_as_always(self, target_names):
|
||||
assert is_iterable_typed(target_names, basestring)
|
||||
self.always_targets_.update(target_names)
|
||||
|
||||
def add_alternative (self, target_instance):
|
||||
""" Add new target alternative.
|
||||
"""
|
||||
assert isinstance(target_instance, AbstractTarget)
|
||||
if self.built_main_targets_:
|
||||
raise IllegalOperation ("add-alternative called when main targets are already created for project '%s'" % self.full_name ())
|
||||
|
||||
self.alternatives_.append (target_instance)
|
||||
|
||||
def main_target (self, name):
|
||||
assert isinstance(name, basestring)
|
||||
if not self.built_main_targets_:
|
||||
self.build_main_targets()
|
||||
|
||||
@@ -465,6 +494,7 @@ class ProjectTarget (AbstractTarget):
|
||||
|
||||
def has_main_target (self, name):
|
||||
"""Tells if a main target with the specified name exists."""
|
||||
assert isinstance(name, basestring)
|
||||
if not self.built_main_targets_:
|
||||
self.build_main_targets()
|
||||
|
||||
@@ -473,6 +503,7 @@ class ProjectTarget (AbstractTarget):
|
||||
def create_main_target (self, name):
|
||||
""" Returns a 'MainTarget' class instance corresponding to the 'name'.
|
||||
"""
|
||||
assert isinstance(name, basestring)
|
||||
if not self.built_main_targets_:
|
||||
self.build_main_targets ()
|
||||
|
||||
@@ -483,7 +514,8 @@ class ProjectTarget (AbstractTarget):
|
||||
""" Find and return the target with the specified id, treated
|
||||
relative to self.
|
||||
"""
|
||||
result = None
|
||||
assert isinstance(id, basestring)
|
||||
result = None
|
||||
current_location = self.get ('location')
|
||||
|
||||
__re_split_project_target = re.compile (r'(.*)//(.*)')
|
||||
@@ -542,6 +574,8 @@ class ProjectTarget (AbstractTarget):
|
||||
return result
|
||||
|
||||
def find (self, id, no_error = False):
|
||||
assert isinstance(id, basestring)
|
||||
assert isinstance(no_error, int) # also matches bools
|
||||
v = self.ids_cache_.get (id, None)
|
||||
|
||||
if not v:
|
||||
@@ -576,7 +610,9 @@ class ProjectTarget (AbstractTarget):
|
||||
the constant will be interpreted relatively
|
||||
to the location of project.
|
||||
"""
|
||||
|
||||
assert isinstance(name, basestring)
|
||||
assert isinstance(value, basestring)
|
||||
assert isinstance(path, int) # will also match bools
|
||||
if path:
|
||||
l = self.location_
|
||||
if not l:
|
||||
@@ -585,8 +621,8 @@ class ProjectTarget (AbstractTarget):
|
||||
# It might be more reasonable to make every project have
|
||||
# a location and use some other approach to prevent buildable
|
||||
# targets in config files, but that's for later.
|
||||
l = get('source-location')
|
||||
|
||||
l = self.get('source-location')
|
||||
|
||||
value = os.path.join(l, value)
|
||||
# Now make the value absolute path. Constants should be in
|
||||
# platform-native form.
|
||||
@@ -596,6 +632,7 @@ class ProjectTarget (AbstractTarget):
|
||||
bjam.call("set-variable", self.project_module(), name, value)
|
||||
|
||||
def inherit(self, parent_project):
|
||||
assert isinstance(parent_project, ProjectTarget)
|
||||
for c in parent_project.constants_:
|
||||
# No need to pass the type. Path constants were converted to
|
||||
# absolute paths already by parent.
|
||||
@@ -624,6 +661,7 @@ class MainTarget (AbstractTarget):
|
||||
def add_alternative (self, target):
|
||||
""" Add a new alternative for this target.
|
||||
"""
|
||||
assert isinstance(target, AbstractTarget)
|
||||
d = target.default_build ()
|
||||
|
||||
if self.alternatives_ and self.default_build_ != d:
|
||||
@@ -637,7 +675,7 @@ class MainTarget (AbstractTarget):
|
||||
|
||||
self.alternatives_.append (target)
|
||||
|
||||
def __select_alternatives (self, property_set, debug):
|
||||
def __select_alternatives (self, property_set_, debug):
|
||||
""" Returns the best viable alternative for this property_set
|
||||
See the documentation for selection rules.
|
||||
# TODO: shouldn't this be 'alternative' (singular)?
|
||||
@@ -647,8 +685,10 @@ class MainTarget (AbstractTarget):
|
||||
# lib l : l.cpp : <variant>debug ;
|
||||
# lib l : l_opt.cpp : <variant>release ;
|
||||
# won't work unless we add default value <variant>debug.
|
||||
property_set = property_set.add_defaults ()
|
||||
|
||||
assert isinstance(property_set_, property_set.PropertySet)
|
||||
assert isinstance(debug, int) # also matches bools
|
||||
property_set_ = property_set_.add_defaults ()
|
||||
|
||||
# The algorithm: we keep the current best viable alternative.
|
||||
# When we've got new best viable alternative, we compare it
|
||||
# with the current one.
|
||||
@@ -662,11 +702,11 @@ class MainTarget (AbstractTarget):
|
||||
return self.alternatives_ [0]
|
||||
|
||||
if debug:
|
||||
print "Property set for selection:", property_set
|
||||
print "Property set for selection:", property_set_
|
||||
|
||||
for v in self.alternatives_:
|
||||
properties = v.match (property_set, debug)
|
||||
|
||||
properties = v.match (property_set_, debug)
|
||||
|
||||
if properties is not None:
|
||||
if not best:
|
||||
best = v
|
||||
@@ -689,8 +729,9 @@ class MainTarget (AbstractTarget):
|
||||
|
||||
return best
|
||||
|
||||
def apply_default_build (self, property_set):
|
||||
return apply_default_build(property_set, self.default_build_)
|
||||
def apply_default_build (self, property_set_):
|
||||
assert isinstance(property_set_, property_set.PropertySet)
|
||||
return apply_default_build(property_set_, self.default_build_)
|
||||
|
||||
def generate (self, ps):
|
||||
""" Select an alternative for this main target, by finding all alternatives
|
||||
@@ -698,6 +739,7 @@ class MainTarget (AbstractTarget):
|
||||
longest requirements set.
|
||||
Returns the result of calling 'generate' on that alternative.
|
||||
"""
|
||||
assert isinstance(ps, property_set.PropertySet)
|
||||
self.manager_.targets ().start_building (self)
|
||||
|
||||
# We want composite properties in build request act as if
|
||||
@@ -722,6 +764,7 @@ class MainTarget (AbstractTarget):
|
||||
generated virtual target in other elements. It's possible
|
||||
that no targets are generated.
|
||||
"""
|
||||
assert isinstance(prop_set, property_set.PropertySet)
|
||||
best_alternative = self.__select_alternatives (prop_set, debug=0)
|
||||
|
||||
if not best_alternative:
|
||||
@@ -737,6 +780,7 @@ class MainTarget (AbstractTarget):
|
||||
return result
|
||||
|
||||
def rename(self, new_name):
|
||||
assert isinstance(new_name, basestring)
|
||||
AbstractTarget.rename(self, new_name)
|
||||
for a in self.alternatives_:
|
||||
a.rename(new_name)
|
||||
@@ -783,6 +827,8 @@ def resolve_reference(target_reference, project):
|
||||
as properties explicitly specified for this reference.
|
||||
"""
|
||||
# Separate target name from properties override
|
||||
assert isinstance(target_reference, basestring)
|
||||
assert isinstance(project, ProjectTarget)
|
||||
split = _re_separate_target_from_properties.match (target_reference)
|
||||
if not split:
|
||||
raise BaseException ("Invalid reference: '%s'" % target_reference)
|
||||
@@ -800,7 +846,7 @@ def resolve_reference(target_reference, project):
|
||||
|
||||
return (target, property_set.create(sproperties))
|
||||
|
||||
def generate_from_reference(target_reference, project, property_set):
|
||||
def generate_from_reference(target_reference, project, property_set_):
|
||||
""" Attempts to generate the target given by target reference, which
|
||||
can refer both to a main target or to a file.
|
||||
Returns a list consisting of
|
||||
@@ -810,11 +856,14 @@ def generate_from_reference(target_reference, project, property_set):
|
||||
project: Project where the reference is made
|
||||
property_set: Properties of the main target that makes the reference
|
||||
"""
|
||||
assert isinstance(target_reference, basestring)
|
||||
assert isinstance(project, ProjectTarget)
|
||||
assert isinstance(property_set_, property_set.PropertySet)
|
||||
target, sproperties = resolve_reference(target_reference, project)
|
||||
|
||||
# Take properties which should be propagated and refine them
|
||||
# with source-specific requirements.
|
||||
propagated = property_set.propagated()
|
||||
propagated = property_set_.propagated()
|
||||
rproperties = propagated.refine(sproperties)
|
||||
|
||||
return target.generate(rproperties)
|
||||
@@ -828,6 +877,10 @@ class BasicTarget (AbstractTarget):
|
||||
targets.
|
||||
"""
|
||||
def __init__ (self, name, project, sources, requirements = None, default_build = None, usage_requirements = None):
|
||||
assert is_iterable_typed(sources, basestring)
|
||||
assert isinstance(requirements, property_set.PropertySet)
|
||||
assert isinstance(default_build, property_set.PropertySet)
|
||||
assert isinstance(usage_requirements, property_set.PropertySet)
|
||||
AbstractTarget.__init__ (self, name, project)
|
||||
|
||||
for s in sources:
|
||||
@@ -894,6 +947,8 @@ class BasicTarget (AbstractTarget):
|
||||
# without using complex algorithsm.
|
||||
# This gives the complex algorithm better chance of caching results.
|
||||
# The exact effect of this "optimization" is no longer clear
|
||||
assert isinstance(build_request, property_set.PropertySet)
|
||||
assert isinstance(requirements, property_set.PropertySet)
|
||||
free_unconditional = []
|
||||
other = []
|
||||
for p in requirements.all():
|
||||
@@ -934,6 +989,9 @@ class BasicTarget (AbstractTarget):
|
||||
# <threading>single
|
||||
#
|
||||
# might come from project's requirements.
|
||||
assert isinstance(requirements, property_set.PropertySet)
|
||||
assert isinstance(context, property_set.PropertySet)
|
||||
assert isinstance(what, basestring)
|
||||
unconditional = feature.expand(requirements.non_conditional())
|
||||
|
||||
context = context.refine(property_set.create(unconditional))
|
||||
@@ -1013,6 +1071,8 @@ class BasicTarget (AbstractTarget):
|
||||
# and expands to <foo2>bar2, but default value of <foo2> is not bar2,
|
||||
# in which case it's not clear what to do.
|
||||
#
|
||||
assert isinstance(build_request, property_set.PropertySet)
|
||||
assert isinstance(requirements, property_set.PropertySet)
|
||||
build_request = build_request.add_defaults()
|
||||
# Featured added by 'add-default' can be composite and expand
|
||||
# to features without default values -- so they are not added yet.
|
||||
@@ -1022,8 +1082,8 @@ class BasicTarget (AbstractTarget):
|
||||
|
||||
return self.evaluate_requirements(requirements, build_request,
|
||||
"refined")
|
||||
|
||||
def match (self, property_set, debug):
|
||||
|
||||
def match (self, property_set_, debug):
|
||||
""" Returns the alternative condition for this alternative, if
|
||||
the condition is satisfied by 'property_set'.
|
||||
"""
|
||||
@@ -1035,14 +1095,15 @@ class BasicTarget (AbstractTarget):
|
||||
# On the other hand, if we have <variant>release in condition it
|
||||
# does not make sense to require <optimization>full to be in
|
||||
# build request just to select this variant.
|
||||
assert isinstance(property_set_, property_set.PropertySet)
|
||||
bcondition = self.requirements_.base ()
|
||||
ccondition = self.requirements_.conditional ()
|
||||
condition = b2.util.set.difference (bcondition, ccondition)
|
||||
|
||||
if debug:
|
||||
print " next alternative: required properties:", [str(p) for p in condition]
|
||||
|
||||
if b2.util.set.contains (condition, property_set.all()):
|
||||
|
||||
if b2.util.set.contains (condition, property_set_.all()):
|
||||
|
||||
if debug:
|
||||
print " matched"
|
||||
@@ -1053,12 +1114,14 @@ class BasicTarget (AbstractTarget):
|
||||
return None
|
||||
|
||||
|
||||
def generate_dependency_targets (self, target_ids, property_set):
|
||||
def generate_dependency_targets (self, target_ids, property_set_):
|
||||
assert is_iterable_typed(target_ids, basestring)
|
||||
assert isinstance(property_set_, property_set.PropertySet)
|
||||
targets = []
|
||||
usage_requirements = []
|
||||
for id in target_ids:
|
||||
|
||||
result = generate_from_reference(id, self.project_, property_set)
|
||||
|
||||
result = generate_from_reference(id, self.project_, property_set_)
|
||||
targets += result.targets()
|
||||
usage_requirements += result.usage_requirements().all()
|
||||
|
||||
@@ -1071,6 +1134,8 @@ class BasicTarget (AbstractTarget):
|
||||
|
||||
Returns a tuple (result, usage_requirements).
|
||||
"""
|
||||
assert is_iterable_typed(properties, property.Property)
|
||||
assert isinstance(ps, property_set.PropertySet)
|
||||
result_properties = []
|
||||
usage_requirements = []
|
||||
for p in properties:
|
||||
@@ -1093,6 +1158,7 @@ class BasicTarget (AbstractTarget):
|
||||
and calls 'construct'. This method should not be
|
||||
overridden.
|
||||
"""
|
||||
assert isinstance(ps, property_set.PropertySet)
|
||||
self.manager_.errors().push_user_context(
|
||||
"Generating target " + self.full_name(), self.user_context_)
|
||||
|
||||
@@ -1215,6 +1281,7 @@ class BasicTarget (AbstractTarget):
|
||||
properties, determines and sets appripriate usage requirements
|
||||
on those targets.
|
||||
"""
|
||||
assert isinstance(subvariant, virtual_target.Subvariant)
|
||||
rproperties = subvariant.build_properties ()
|
||||
xusage_requirements =self.evaluate_requirements(
|
||||
self.usage_requirements_, rproperties, "added")
|
||||
@@ -1257,7 +1324,12 @@ class BasicTarget (AbstractTarget):
|
||||
targets created while building this main target
|
||||
- 'build-request' is property-set instance with
|
||||
requested build properties"""
|
||||
|
||||
assert is_iterable_typed(root_targets, virtual_target.VirtualTarget)
|
||||
assert is_iterable_typed(all_targets, virtual_target.VirtualTarget)
|
||||
assert isinstance(build_request, property_set.PropertySet)
|
||||
assert is_iterable_typed(sources, virtual_target.VirtualTarget)
|
||||
assert isinstance(rproperties, property_set.PropertySet)
|
||||
assert isinstance(usage_requirements, property_set.PropertySet)
|
||||
for e in root_targets:
|
||||
e.root (True)
|
||||
|
||||
@@ -1282,6 +1354,7 @@ class TypedTarget (BasicTarget):
|
||||
import generators
|
||||
|
||||
def __init__ (self, name, project, type, sources, requirements, default_build, usage_requirements):
|
||||
assert isinstance(type, basestring)
|
||||
BasicTarget.__init__ (self, name, project, sources, requirements, default_build, usage_requirements)
|
||||
self.type_ = type
|
||||
|
||||
@@ -1290,9 +1363,11 @@ class TypedTarget (BasicTarget):
|
||||
|
||||
def type (self):
|
||||
return self.type_
|
||||
|
||||
def construct (self, name, source_targets, prop_set):
|
||||
|
||||
def construct (self, name, source_targets, prop_set):
|
||||
assert isinstance(name, basestring)
|
||||
assert is_iterable_typed(source_targets, virtual_target.VirtualTarget)
|
||||
assert isinstance(prop_set, property_set.PropertySet)
|
||||
r = generators.construct (self.project_, os.path.splitext(name)[0],
|
||||
self.type_,
|
||||
prop_set.add_raw(['<main-target-type>' + self.type_]),
|
||||
@@ -1313,11 +1388,12 @@ class TypedTarget (BasicTarget):
|
||||
|
||||
return r
|
||||
|
||||
def apply_default_build(property_set, default_build):
|
||||
def apply_default_build(property_set_, default_build):
|
||||
# 1. First, see what properties from default_build
|
||||
# are already present in property_set.
|
||||
|
||||
specified_features = set(p.feature() for p in property_set.all())
|
||||
# are already present in property_set.
|
||||
assert isinstance(property_set_, property_set.PropertySet)
|
||||
assert isinstance(default_build, property_set.PropertySet)
|
||||
specified_features = set(p.feature() for p in property_set_.all())
|
||||
|
||||
defaults_to_apply = []
|
||||
for d in default_build.all():
|
||||
@@ -1345,19 +1421,23 @@ def apply_default_build(property_set, default_build):
|
||||
# be an indication that
|
||||
# build_request.expand-no-defaults is the wrong rule
|
||||
# to use here.
|
||||
compressed = feature.compress_subproperties(property_set.all())
|
||||
compressed = feature.compress_subproperties(property_set_.all())
|
||||
|
||||
result = build_request.expand_no_defaults(
|
||||
b2.build.property_set.create(feature.expand([p])) for p in (compressed + defaults_to_apply))
|
||||
|
||||
else:
|
||||
result.append (property_set)
|
||||
result.append (property_set_)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def create_typed_metatarget(name, type, sources, requirements, default_build, usage_requirements):
|
||||
|
||||
assert isinstance(name, basestring)
|
||||
assert isinstance(type, basestring)
|
||||
assert is_iterable_typed(requirements, basestring)
|
||||
assert is_iterable_typed(default_build, basestring)
|
||||
assert is_iterable_typed(usage_requirements, basestring)
|
||||
from b2.manager import get_manager
|
||||
t = get_manager().targets()
|
||||
|
||||
@@ -1372,6 +1452,11 @@ def create_typed_metatarget(name, type, sources, requirements, default_build, us
|
||||
|
||||
|
||||
def create_metatarget(klass, 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)
|
||||
from b2.manager import get_manager
|
||||
t = get_manager().targets()
|
||||
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
|
||||
import feature, property, generators, property_set
|
||||
import b2.util.set
|
||||
from b2.util import cached, qualify_jam_action
|
||||
import bjam
|
||||
|
||||
from b2.util import cached, qualify_jam_action, is_iterable_typed, is_iterable
|
||||
from b2.util.utility import *
|
||||
from b2.util import bjam_signature
|
||||
from b2.manager import get_manager
|
||||
@@ -34,6 +36,11 @@ __re_first_group = re.compile (r'[^.]*\.(.*)')
|
||||
class Flag:
|
||||
|
||||
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
|
||||
@@ -117,6 +124,10 @@ def flags(rule_or_module, variable_name, condition, values = []):
|
||||
is specified, then the value of 'feature'
|
||||
will be added.
|
||||
"""
|
||||
assert isinstance(rule_or_module, basestring)
|
||||
assert isinstance(variable_name, basestring)
|
||||
assert is_iterable_typed(condition, basestring)
|
||||
assert is_iterable(values) and all(isinstance(v, (basestring, type(None))) for v in values)
|
||||
caller = bjam.caller()
|
||||
if not '.' in rule_or_module and caller and caller[:-1].startswith("Jamfile"):
|
||||
# Unqualified rule name, used inside Jamfile. Most likely used with
|
||||
@@ -156,6 +167,9 @@ def flags(rule_or_module, variable_name, condition, values = []):
|
||||
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:
|
||||
@@ -166,7 +180,8 @@ def set_target_variables (manager, rule_or_module, targets, ps):
|
||||
def find_satisfied_condition(conditions, ps):
|
||||
"""Returns the first element of 'property-sets' which is a subset of
|
||||
'properties', or an empty list if no such element exists."""
|
||||
|
||||
assert is_iterable_typed(conditions, property_set.PropertySet)
|
||||
assert isinstance(ps, property_set.PropertySet)
|
||||
features = set(p.feature() for p in ps.all())
|
||||
|
||||
for condition in conditions:
|
||||
@@ -202,9 +217,14 @@ def find_satisfied_condition(conditions, ps):
|
||||
def register (toolset):
|
||||
""" Registers a new toolset.
|
||||
"""
|
||||
assert isinstance(toolset, basestring)
|
||||
feature.extend('toolset', [toolset])
|
||||
|
||||
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>')]
|
||||
|
||||
@@ -237,6 +257,9 @@ def inherit_flags(toolset, base, prohibited_properties = []):
|
||||
or version of a base toolset, it won't ever match the inheriting toolset. When
|
||||
such flag settings must be inherited, define a rule in base toolset module and
|
||||
call it as needed."""
|
||||
assert isinstance(toolset, basestring)
|
||||
assert isinstance(base, basestring)
|
||||
assert is_iterable_typed(prohibited_properties, basestring)
|
||||
for f in __module_flags.get(base, []):
|
||||
|
||||
if not f.condition or b2.util.set.difference(f.condition, prohibited_properties):
|
||||
@@ -296,6 +319,8 @@ def __set_target_variables_aux (manager, rule_or_module, ps):
|
||||
variables names and values, which must be set on targets for that
|
||||
rule/properties combination.
|
||||
"""
|
||||
assert isinstance(rule_or_module, basestring)
|
||||
assert isinstance(ps, property_set.PropertySet)
|
||||
result = []
|
||||
|
||||
for f in __flags.get(rule_or_module, []):
|
||||
@@ -320,6 +345,8 @@ def __set_target_variables_aux (manager, rule_or_module, ps):
|
||||
return result
|
||||
|
||||
def __handle_flag_value (manager, value, ps):
|
||||
assert isinstance(value, basestring)
|
||||
assert isinstance(ps, property_set.PropertySet)
|
||||
result = []
|
||||
|
||||
if get_grist (value):
|
||||
@@ -355,8 +382,13 @@ def __add_flag (rule_or_module, variable_name, condition, values):
|
||||
""" Adds a new flag setting with the specified values.
|
||||
Does no checking.
|
||||
"""
|
||||
assert isinstance(rule_or_module, basestring)
|
||||
assert isinstance(variable_name, basestring)
|
||||
assert is_iterable_typed(condition, property_set.PropertySet)
|
||||
assert is_iterable(values) and all(
|
||||
isinstance(v, (basestring, type(None))) for v in values)
|
||||
f = Flag(variable_name, values, condition, rule_or_module)
|
||||
|
||||
|
||||
# Grab the name of the module
|
||||
m = __re_first_segment.match (rule_or_module)
|
||||
assert m
|
||||
@@ -377,7 +409,7 @@ def add_requirements(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-requirements)
|
||||
#{
|
||||
__requirements.extend(requirements)
|
||||
@@ -392,6 +424,8 @@ def add_requirements(requirements):
|
||||
# 3. All flags are inherited
|
||||
# 4. All rules are imported.
|
||||
def inherit(toolset, base):
|
||||
assert isinstance(toolset, basestring)
|
||||
assert isinstance(base, basestring)
|
||||
get_manager().projects().load_module(base, []);
|
||||
|
||||
inherit_generators(toolset, [], base)
|
||||
|
||||
@@ -14,7 +14,7 @@ import os.path
|
||||
from b2.util.utility import replace_grist, os_name
|
||||
from b2.exceptions import *
|
||||
from b2.build import feature, property, scanner
|
||||
from b2.util import bjam_signature
|
||||
from b2.util import bjam_signature, is_iterable_typed
|
||||
|
||||
|
||||
__re_hyphen = re.compile ('-')
|
||||
@@ -87,17 +87,17 @@ def register (type, suffixes = [], base_type = None):
|
||||
# Generated targets of 'type' will use the first of 'suffixes'
|
||||
# (this may be overriden)
|
||||
set_generated_target_suffix (type, [], suffixes [0])
|
||||
|
||||
|
||||
# Specify mapping from suffixes to type
|
||||
register_suffixes (suffixes, type)
|
||||
|
||||
|
||||
feature.extend('target-type', [type])
|
||||
feature.extend('main-target-type', [type])
|
||||
feature.extend('base-target-type', [type])
|
||||
|
||||
if base_type:
|
||||
feature.compose ('<target-type>' + type, replace_grist (base_type, '<base-target-type>'))
|
||||
feature.compose ('<base-target-type>' + type, '<base-target-type>' + base_type)
|
||||
feature.compose ('<target-type>' + type, [replace_grist (base_type, '<base-target-type>')])
|
||||
feature.compose ('<base-target-type>' + type, ['<base-target-type>' + base_type])
|
||||
|
||||
import b2.build.generators as generators
|
||||
# Adding a new derived type affects generator selection so we need to
|
||||
@@ -111,6 +111,7 @@ def register (type, suffixes = [], base_type = None):
|
||||
|
||||
# FIXME: quick hack.
|
||||
def type_from_rule_name(rule_name):
|
||||
assert isinstance(rule_name, basestring)
|
||||
return rule_name.upper().replace("-", "_")
|
||||
|
||||
|
||||
@@ -118,6 +119,8 @@ 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 __suffixes_to_types.has_key (s):
|
||||
old_type = __suffixes_to_types [s]
|
||||
@@ -129,23 +132,33 @@ def register_suffixes (suffixes, type):
|
||||
def registered (type):
|
||||
""" Returns true iff type has been registered.
|
||||
"""
|
||||
assert isinstance(type, basestring)
|
||||
return __types.has_key (type)
|
||||
|
||||
def validate (type):
|
||||
""" Issues an error if 'type' is unknown.
|
||||
"""
|
||||
assert isinstance(type, basestring)
|
||||
if not registered (type):
|
||||
raise BaseException ("Unknown target type '%s'" % type)
|
||||
|
||||
def set_scanner (type, scanner):
|
||||
""" Sets a scanner class that will be used for this 'type'.
|
||||
"""
|
||||
if __debug__:
|
||||
from .scanner import Scanner
|
||||
assert isinstance(type, basestring)
|
||||
assert issubclass(scanner, Scanner)
|
||||
validate (type)
|
||||
__types [type]['scanner'] = scanner
|
||||
|
||||
def get_scanner (type, prop_set):
|
||||
""" Returns a scanner instance appropriate to 'type' and 'property_set'.
|
||||
"""
|
||||
if __debug__:
|
||||
from .property_set import PropertySet
|
||||
assert isinstance(type, basestring)
|
||||
assert isinstance(prop_set, PropertySet)
|
||||
if registered (type):
|
||||
scanner_type = __types [type]['scanner']
|
||||
if scanner_type:
|
||||
@@ -157,12 +170,13 @@ def get_scanner (type, prop_set):
|
||||
def base(type):
|
||||
"""Returns a base type for the given type or nothing in case the given type is
|
||||
not derived."""
|
||||
|
||||
assert isinstance(type, basestring)
|
||||
return __types[type]['base']
|
||||
|
||||
def all_bases (type):
|
||||
""" Returns type and all of its bases, in the order of their distance from type.
|
||||
"""
|
||||
assert isinstance(type, basestring)
|
||||
result = []
|
||||
while type:
|
||||
result.append (type)
|
||||
@@ -173,6 +187,7 @@ def all_bases (type):
|
||||
def all_derived (type):
|
||||
""" Returns type and all classes that derive from it, in the order of their distance from type.
|
||||
"""
|
||||
assert isinstance(type, basestring)
|
||||
result = [type]
|
||||
for d in __types [type]['derived']:
|
||||
result.extend (all_derived (d))
|
||||
@@ -182,6 +197,8 @@ def all_derived (type):
|
||||
def is_derived (type, base):
|
||||
""" Returns true if 'type' is 'base' or has 'base' as its direct or indirect base.
|
||||
"""
|
||||
assert isinstance(type, basestring)
|
||||
assert isinstance(base, basestring)
|
||||
# TODO: this isn't very efficient, especially for bases close to type
|
||||
if base in all_bases (type):
|
||||
return True
|
||||
@@ -191,6 +208,8 @@ def is_derived (type, base):
|
||||
def is_subtype (type, base):
|
||||
""" Same as is_derived. Should be removed.
|
||||
"""
|
||||
assert isinstance(type, basestring)
|
||||
assert isinstance(base, basestring)
|
||||
# TODO: remove this method
|
||||
return is_derived (type, base)
|
||||
|
||||
@@ -208,6 +227,9 @@ def set_generated_target_suffix (type, properties, suffix):
|
||||
The 'suffix' parameter can be empty string ("") to indicate that
|
||||
no suffix should be used.
|
||||
"""
|
||||
assert isinstance(type, basestring)
|
||||
assert is_iterable_typed(properties, basestring)
|
||||
assert isinstance(suffix, basestring)
|
||||
set_generated_target_ps(1, type, properties, suffix)
|
||||
|
||||
|
||||
@@ -216,9 +238,16 @@ def change_generated_target_suffix (type, properties, suffix):
|
||||
""" Change the suffix previously registered for this type/properties
|
||||
combination. If suffix is not yet specified, sets it.
|
||||
"""
|
||||
assert isinstance(type, basestring)
|
||||
assert is_iterable_typed(properties, basestring)
|
||||
assert isinstance(suffix, basestring)
|
||||
change_generated_target_ps(1, type, properties, suffix)
|
||||
|
||||
def generated_target_suffix(type, properties):
|
||||
if __debug__:
|
||||
from .property_set import PropertySet
|
||||
assert isinstance(type, basestring)
|
||||
assert isinstance(properties, PropertySet)
|
||||
return generated_target_ps(1, type, properties)
|
||||
|
||||
# Sets a target prefix that should be used when generating targets of 'type'
|
||||
@@ -236,16 +265,31 @@ def set_generated_target_prefix(type, properties, prefix):
|
||||
# Change the prefix previously registered for this type/properties combination.
|
||||
# If prefix is not yet specified, sets it.
|
||||
def change_generated_target_prefix(type, properties, prefix):
|
||||
assert isinstance(type, basestring)
|
||||
assert is_iterable_typed(properties, basestring)
|
||||
assert isinstance(prefix, basestring)
|
||||
change_generated_target_ps(0, type, properties, prefix)
|
||||
|
||||
def generated_target_prefix(type, properties):
|
||||
if __debug__:
|
||||
from .property_set import PropertySet
|
||||
assert isinstance(type, basestring)
|
||||
assert isinstance(properties, PropertySet)
|
||||
return generated_target_ps(0, type, properties)
|
||||
|
||||
def set_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)
|
||||
__prefixes_suffixes[is_suffix].insert (properties, val)
|
||||
|
||||
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:
|
||||
@@ -256,7 +300,9 @@ def change_generated_target_ps(is_suffix, type, properties, val):
|
||||
# If no prefix/suffix is specified for 'type', returns prefix/suffix for
|
||||
# base type, if any.
|
||||
def generated_target_ps_real(is_suffix, type, properties):
|
||||
|
||||
assert isinstance(is_suffix, (int, bool))
|
||||
assert isinstance(type, basestring)
|
||||
assert is_iterable_typed(properties, basestring)
|
||||
result = ''
|
||||
found = False
|
||||
while type and not found:
|
||||
@@ -278,6 +324,11 @@ def generated_target_ps(is_suffix, type, prop_set):
|
||||
with the specified properties. If not suffix were specified for
|
||||
'type', returns suffix for base type, if any.
|
||||
"""
|
||||
if __debug__:
|
||||
from .property_set import PropertySet
|
||||
assert isinstance(is_suffix, (int, bool))
|
||||
assert isinstance(type, basestring)
|
||||
assert isinstance(prop_set, PropertySet)
|
||||
key = (is_suffix, type, prop_set)
|
||||
v = __target_suffixes_cache.get(key, None)
|
||||
|
||||
@@ -292,6 +343,7 @@ def type(filename):
|
||||
tries each suffix. E.g. for name of "file.so.1.2" suffixes "2", "1", and
|
||||
"so" will be tried.
|
||||
"""
|
||||
assert isinstance(filename, basestring)
|
||||
while 1:
|
||||
filename, suffix = os.path.splitext (filename)
|
||||
if not suffix: return None
|
||||
@@ -306,6 +358,10 @@ def register_type (type, suffixes, base_type = None, os = []):
|
||||
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
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ import os.path
|
||||
import string
|
||||
import types
|
||||
|
||||
from b2.util import path, utility, set
|
||||
from b2.util import path, utility, set, is_iterable_typed
|
||||
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
|
||||
@@ -110,6 +110,7 @@ class VirtualTargetRegistry:
|
||||
and equal action. If such target is found it is retured and 'target' is not registered.
|
||||
Otherwise, 'target' is registered and returned.
|
||||
"""
|
||||
assert isinstance(target, VirtualTarget)
|
||||
if target.path():
|
||||
signature = target.path() + "-" + target.name()
|
||||
else:
|
||||
@@ -156,6 +157,11 @@ class VirtualTargetRegistry:
|
||||
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.
|
||||
"""
|
||||
if __debug__:
|
||||
from .targets import ProjectTarget
|
||||
assert isinstance(file, basestring)
|
||||
assert isinstance(file_location, basestring)
|
||||
assert isinstance(project, ProjectTarget)
|
||||
# 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)
|
||||
@@ -192,6 +198,8 @@ class VirtualTargetRegistry:
|
||||
return [t for t in targets if b2.build.type.is_sybtype(t.type(), type)]
|
||||
|
||||
def register_actual_name (self, actual_name, virtual_target):
|
||||
assert isinstance(actual_name, basestring)
|
||||
assert isinstance(virtual_target, VirtualTarget)
|
||||
if self.actual_.has_key (actual_name):
|
||||
cs1 = self.actual_ [actual_name].creating_subvariant ()
|
||||
cs2 = virtual_target.creating_subvariant ()
|
||||
@@ -238,6 +246,9 @@ class VirtualTargetRegistry:
|
||||
""" Appends the suffix appropriate to 'type/property_set' combination
|
||||
to the specified name and returns the result.
|
||||
"""
|
||||
assert isinstance(specified_name, basestring)
|
||||
assert isinstance(file_type, basestring)
|
||||
assert isinstance(prop_set, property_set.PropertySet)
|
||||
suffix = b2.build.type.generated_target_suffix (file_type, prop_set)
|
||||
|
||||
if suffix:
|
||||
@@ -254,6 +265,10 @@ class VirtualTarget:
|
||||
project: project to which this target belongs.
|
||||
"""
|
||||
def __init__ (self, name, project):
|
||||
if __debug__:
|
||||
from .targets import ProjectTarget
|
||||
assert isinstance(name, basestring)
|
||||
assert isinstance(project, ProjectTarget)
|
||||
self.name_ = name
|
||||
self.project_ = project
|
||||
self.dependencies_ = []
|
||||
@@ -302,6 +317,9 @@ class VirtualTarget:
|
||||
|
||||
If scanner is not specified, then actual target is returned.
|
||||
"""
|
||||
if __debug__:
|
||||
from .scanner import Scanner
|
||||
assert scanner is None or isinstance(scanner, Scanner)
|
||||
actual_name = self.actualize_no_scanner ()
|
||||
|
||||
if self.always_:
|
||||
@@ -373,6 +391,9 @@ class AbstractFileTarget (VirtualTarget):
|
||||
type: optional type of this target.
|
||||
"""
|
||||
def __init__ (self, name, type, project, action = None, exact=False):
|
||||
assert isinstance(type, basestring) or type is None
|
||||
assert action is None or isinstance(action, Action)
|
||||
assert isinstance(exact, (int, bool))
|
||||
VirtualTarget.__init__ (self, name, project)
|
||||
|
||||
self.type_ = type
|
||||
@@ -402,6 +423,7 @@ class AbstractFileTarget (VirtualTarget):
|
||||
""" Sets the path. When generating target name, it will override any path
|
||||
computation from properties.
|
||||
"""
|
||||
assert isinstance(path, basestring)
|
||||
self.path_ = os.path.normpath(path)
|
||||
|
||||
def action (self):
|
||||
@@ -413,6 +435,7 @@ class AbstractFileTarget (VirtualTarget):
|
||||
""" Sets/gets the 'root' flag. Target is root is it directly correspods to some
|
||||
variant of a main target.
|
||||
"""
|
||||
assert isinstance(set, (int, bool, type(None)))
|
||||
if set:
|
||||
self.root_ = True
|
||||
return self.root_
|
||||
@@ -425,6 +448,7 @@ class AbstractFileTarget (VirtualTarget):
|
||||
s: If specified, specified the value to set,
|
||||
which should be instance of 'subvariant' class.
|
||||
"""
|
||||
assert s is None or isinstance(s, Subvariant)
|
||||
if s and not self.creating_subvariant ():
|
||||
if self.creating_subvariant ():
|
||||
raise BaseException ("Attempt to change 'dg'")
|
||||
@@ -435,6 +459,7 @@ class AbstractFileTarget (VirtualTarget):
|
||||
return self.creating_subvariant_
|
||||
|
||||
def actualize_action (self, target):
|
||||
assert isinstance(target, basestring)
|
||||
if self.action_:
|
||||
self.action_.actualize ()
|
||||
|
||||
@@ -513,7 +538,7 @@ class AbstractFileTarget (VirtualTarget):
|
||||
If not <tag> property is specified, or the rule specified by
|
||||
<tag> returns nothing, returns the result of calling
|
||||
virtual-target.add-suffix"""
|
||||
|
||||
assert isinstance(specified_name, basestring)
|
||||
if self.action_:
|
||||
ps = self.action_.properties()
|
||||
else:
|
||||
@@ -627,6 +652,9 @@ class FileTarget (AbstractFileTarget):
|
||||
- the suffix which correspond to the target's type.
|
||||
"""
|
||||
def __init__ (self, name, type, project, action = None, path=None, exact=False):
|
||||
assert isinstance(type, basestring) or type is None
|
||||
assert action is None or isinstance(action, Action)
|
||||
assert isinstance(exact, (int, bool))
|
||||
AbstractFileTarget.__init__ (self, name, type, project, action, exact)
|
||||
|
||||
self.path_ = path
|
||||
@@ -638,10 +666,12 @@ class FileTarget (AbstractFileTarget):
|
||||
return self.name_
|
||||
|
||||
def clone_with_different_type(self, new_type):
|
||||
assert isinstance(new_type, basestring)
|
||||
return FileTarget(self.name_, new_type, self.project_,
|
||||
self.action_, self.path_, exact=True)
|
||||
|
||||
def actualize_location (self, target):
|
||||
assert isinstance(target, basestring)
|
||||
engine = self.project_.manager_.engine ()
|
||||
|
||||
if self.action_:
|
||||
@@ -714,6 +744,7 @@ class FileTarget (AbstractFileTarget):
|
||||
class NotFileTarget(AbstractFileTarget):
|
||||
|
||||
def __init__(self, name, project, action):
|
||||
assert isinstance(action, Action)
|
||||
AbstractFileTarget.__init__(self, name, None, project, action)
|
||||
|
||||
def path(self):
|
||||
@@ -721,6 +752,7 @@ class NotFileTarget(AbstractFileTarget):
|
||||
return None
|
||||
|
||||
def actualize_location(self, target):
|
||||
assert isinstance(target, basestring)
|
||||
bjam.call("NOTFILE", target)
|
||||
bjam.call("ALWAYS", target)
|
||||
bjam.call("NOUPDATE", target)
|
||||
@@ -735,8 +767,9 @@ class Action:
|
||||
not establish dependency relationship, but should do everything else.
|
||||
"""
|
||||
def __init__ (self, manager, sources, action_name, prop_set):
|
||||
assert is_iterable_typed(sources, VirtualTarget)
|
||||
assert isinstance(action_name, basestring) or action_name is None
|
||||
assert(isinstance(prop_set, property_set.PropertySet))
|
||||
assert type(sources) == types.ListType
|
||||
self.sources_ = sources
|
||||
self.action_name_ = action_name
|
||||
if not prop_set:
|
||||
@@ -758,11 +791,14 @@ class Action:
|
||||
|
||||
|
||||
def add_targets (self, targets):
|
||||
assert is_iterable_typed(targets, VirtualTarget)
|
||||
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 replace_targets(self, old_targets, new_targets):
|
||||
assert is_iterable_typed(old_targets, VirtualTarget)
|
||||
assert is_iterable_typed(new_targets, VirtualTarget)
|
||||
self.targets_ = [t for t in self.targets_ if not t in old_targets] + new_targets
|
||||
|
||||
def targets (self):
|
||||
return self.targets_
|
||||
@@ -826,6 +862,8 @@ class Action:
|
||||
For each passed source, actualizes it with the appropriate scanner.
|
||||
Returns the actualized virtual targets.
|
||||
"""
|
||||
assert is_iterable_typed(sources, VirtualTarget)
|
||||
assert isinstance(prop_set, property_set.PropertySet)
|
||||
result = []
|
||||
for i in sources:
|
||||
scanner = None
|
||||
@@ -852,6 +890,8 @@ class Action:
|
||||
New values will be *appended* to the variables. They may be non-empty,
|
||||
if caller wants it.
|
||||
"""
|
||||
assert is_iterable_typed(sources, VirtualTarget)
|
||||
assert isinstance(prop_set, property_set.PropertySet)
|
||||
dependencies = self.properties_.get ('<dependency>')
|
||||
|
||||
self.dependency_only_sources_ += self.actualize_source_type (dependencies, prop_set)
|
||||
@@ -879,6 +919,7 @@ class Action:
|
||||
to get generated headers correctly. Default implementation returns
|
||||
its argument.
|
||||
"""
|
||||
assert isinstance(prop_set, property_set.PropertySet)
|
||||
return prop_set
|
||||
|
||||
|
||||
@@ -889,6 +930,7 @@ class NullAction (Action):
|
||||
actions which create them.
|
||||
"""
|
||||
def __init__ (self, manager, prop_set):
|
||||
assert isinstance(prop_set, property_set.PropertySet)
|
||||
Action.__init__ (self, manager, [], None, prop_set)
|
||||
|
||||
def actualize (self):
|
||||
@@ -908,7 +950,8 @@ class NonScanningAction(Action):
|
||||
Action.__init__(self, b2.manager.get_manager(), sources, action_name, property_set)
|
||||
|
||||
def actualize_source_type(self, sources, property_set):
|
||||
|
||||
assert is_iterable_typed(sources, VirtualTarget)
|
||||
assert isinstance(property_set, property_set.PropertySet)
|
||||
result = []
|
||||
for s in sources:
|
||||
result.append(s.actualize())
|
||||
@@ -920,6 +963,9 @@ def traverse (target, include_roots = False, include_sources = False):
|
||||
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.
|
||||
"""
|
||||
assert isinstance(target, VirtualTarget)
|
||||
assert isinstance(include_roots, (int, bool))
|
||||
assert isinstance(include_sources, (int, bool))
|
||||
result = []
|
||||
|
||||
if target.action ():
|
||||
@@ -951,7 +997,12 @@ def clone_action (action, new_project, new_action_name, new_properties):
|
||||
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 __debug__:
|
||||
from .targets import ProjectTarget
|
||||
assert isinstance(action, Action)
|
||||
assert isinstance(new_project, ProjectTarget)
|
||||
assert isinstance(new_action_name, basestring)
|
||||
assert isinstance(new_properties, property_set.PropertySet)
|
||||
if not new_action_name:
|
||||
new_action_name = action.action_name()
|
||||
|
||||
@@ -990,6 +1041,14 @@ class Subvariant:
|
||||
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
|
||||
@@ -1028,6 +1087,7 @@ class Subvariant:
|
||||
return self.sources_usage_requirements_
|
||||
|
||||
def set_usage_requirements (self, usage_requirements):
|
||||
assert isinstance(usage_requirements, property_set.PropertySet)
|
||||
self.usage_requirements_ = usage_requirements
|
||||
|
||||
def usage_requirements (self):
|
||||
@@ -1038,7 +1098,9 @@ class Subvariant:
|
||||
either directly or indirectly, and either as sources,
|
||||
or as dependency properties. Targets referred with
|
||||
dependency property are returned a properties, not targets."""
|
||||
|
||||
if __debug__:
|
||||
from .targets import GenerateResult
|
||||
assert isinstance(result, GenerateResult)
|
||||
# Find directly referenced targets.
|
||||
deps = self.build_properties().dependency()
|
||||
all_targets = self.sources_ + deps
|
||||
@@ -1071,7 +1133,8 @@ class Subvariant:
|
||||
if 'target_type' is not specified), the result will contain
|
||||
<$(feature)>path-to-that-target.
|
||||
"""
|
||||
|
||||
assert isinstance(feature, basestring)
|
||||
assert isinstance(target_type, basestring)
|
||||
if not target_type:
|
||||
key = feature
|
||||
else:
|
||||
@@ -1088,6 +1151,7 @@ class Subvariant:
|
||||
return result
|
||||
|
||||
def all_target_directories(self, target_type = None):
|
||||
assert isinstance(target_type, (basestring, type(None)))
|
||||
# TODO: does not appear to use target_type in deciding
|
||||
# if we've computed this already.
|
||||
if not self.target_directories_:
|
||||
@@ -1095,6 +1159,7 @@ class Subvariant:
|
||||
return self.target_directories_
|
||||
|
||||
def compute_target_directories(self, target_type=None):
|
||||
assert isinstance(target_type, (basestring, type(None)))
|
||||
result = []
|
||||
for t in self.created_targets():
|
||||
if not target_type or b2.build.type.is_derived(t.type(), target_type):
|
||||
|
||||
@@ -206,6 +206,7 @@ int anyhow = 0;
|
||||
extern PyObject * bjam_variable ( PyObject * self, PyObject * args );
|
||||
extern PyObject * bjam_backtrace ( PyObject * self, PyObject * args );
|
||||
extern PyObject * bjam_caller ( PyObject * self, PyObject * args );
|
||||
int python_optimize = 1; /* Set Python optimzation on by default */
|
||||
#endif
|
||||
|
||||
void regex_done();
|
||||
@@ -235,7 +236,13 @@ int main( int argc, char * * argv, char * * arg_environ )
|
||||
--argc;
|
||||
++argv;
|
||||
|
||||
if ( getoptions( argc, argv, "-:l:m:d:j:p:f:gs:t:ano:qv", optv ) < 0 )
|
||||
#ifdef HAVE_PYTHON
|
||||
#define OPTSTRING "-:l:m:d:j:p:f:gs:t:ano:qvz"
|
||||
#else
|
||||
#define OPTSTRING "-:l:m:d:j:p:f:gs:t:ano:qv"
|
||||
#endif
|
||||
|
||||
if ( getoptions( argc, argv, OPTSTRING, optv ) < 0 )
|
||||
{
|
||||
err_printf( "\nusage: %s [ options ] targets...\n\n", progname );
|
||||
|
||||
@@ -253,6 +260,9 @@ int main( int argc, char * * argv, char * * arg_environ )
|
||||
err_printf( "-sx=y Set variable x=y, overriding environment.\n" );
|
||||
err_printf( "-tx Rebuild x, even if it is up-to-date.\n" );
|
||||
err_printf( "-v Print the version of jam and exit.\n" );
|
||||
#ifdef HAVE_PYTHON
|
||||
err_printf( "-z Disable Python Optimization and enable asserts\n" );
|
||||
#endif
|
||||
err_printf( "--x Option is ignored.\n\n" );
|
||||
|
||||
exit( EXITBAD );
|
||||
@@ -318,6 +328,11 @@ int main( int argc, char * * argv, char * * arg_environ )
|
||||
if ( ( s = getoptval( optv, 'm', 0 ) ) )
|
||||
globs.max_buf = atoi( s ) * 1024; /* convert to kb */
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
if ( ( s = getoptval( optv, 'z', 0 ) ) )
|
||||
python_optimize = 0; /* disable python optimization */
|
||||
#endif
|
||||
|
||||
/* Turn on/off debugging */
|
||||
for ( n = 0; ( s = getoptval( optv, 'd', n ) ); ++n )
|
||||
{
|
||||
@@ -364,6 +379,7 @@ int main( int argc, char * * argv, char * * arg_environ )
|
||||
#ifdef HAVE_PYTHON
|
||||
{
|
||||
PROFILE_ENTER( MAIN_PYTHON );
|
||||
Py_OptimizeFlag = python_optimize;
|
||||
Py_Initialize();
|
||||
{
|
||||
static PyMethodDef BjamMethods[] = {
|
||||
|
||||
@@ -13,7 +13,7 @@ import b2.build.targets as targets
|
||||
import sys
|
||||
from b2.build import feature, property, virtual_target, generators, type, property_set, scanner
|
||||
from b2.util.utility import *
|
||||
from b2.util import path, regex, bjam_signature
|
||||
from b2.util import path, regex, bjam_signature, is_iterable_typed
|
||||
import b2.tools.types
|
||||
from b2.manager import get_manager
|
||||
|
||||
@@ -413,9 +413,12 @@ class LibGenerator (generators.Generator):
|
||||
|
||||
def __init__(self, id, composing = True, source_types = [], target_types_and_names = ['LIB'], requirements = []):
|
||||
generators.Generator.__init__(self, id, composing, source_types, target_types_and_names, requirements)
|
||||
|
||||
def run(self, project, name, prop_set, sources):
|
||||
|
||||
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
|
||||
@@ -451,7 +454,11 @@ generators.override("builtin.prebuilt", "builtin.lib-generator")
|
||||
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" +
|
||||
@@ -490,8 +497,12 @@ class SearchedLibGenerator (generators.Generator):
|
||||
# is make sure SearchedLibGenerator is not invoked deep in transformation
|
||||
# search.
|
||||
generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements)
|
||||
|
||||
|
||||
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
|
||||
@@ -525,9 +536,14 @@ generators.register (SearchedLibGenerator ())
|
||||
class PrebuiltLibGenerator(generators.Generator):
|
||||
|
||||
def __init__(self, id, composing, source_types, target_types_and_names, requirements):
|
||||
generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements)
|
||||
generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements)
|
||||
|
||||
def run(self, project, name, properties, sources):
|
||||
assert isinstance(project, targets.ProjectTarget)
|
||||
assert isinstance(name, basestring)
|
||||
assert isinstance(properties, property_set.PropertySet)
|
||||
assert is_iterable_typed(sources, virtual_target.VirtualTarget)
|
||||
|
||||
f = properties.get("file")
|
||||
return f + sources
|
||||
|
||||
@@ -546,6 +562,7 @@ class CompileAction (virtual_target.Action):
|
||||
i.e. which belong to the same main target, add their directories
|
||||
to include path.
|
||||
"""
|
||||
assert isinstance(prop_set, property_set.PropertySet)
|
||||
s = self.targets () [0].creating_subvariant ()
|
||||
|
||||
return prop_set.add_raw (s.implicit_includes ('include', 'H'))
|
||||
@@ -576,6 +593,10 @@ class LinkingGenerator (generators.Generator):
|
||||
generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements)
|
||||
|
||||
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)
|
||||
|
||||
sources.extend(prop_set.get('<library>'))
|
||||
|
||||
@@ -623,7 +644,8 @@ class LinkingGenerator (generators.Generator):
|
||||
return (ur, result)
|
||||
|
||||
def extra_usage_requirements (self, created_targets, prop_set):
|
||||
|
||||
assert is_iterable_typed(created_targets, virtual_target.VirtualTarget)
|
||||
assert isinstance(prop_set, property_set.PropertySet)
|
||||
result = property_set.empty ()
|
||||
extra = []
|
||||
|
||||
@@ -659,7 +681,10 @@ class LinkingGenerator (generators.Generator):
|
||||
return result
|
||||
|
||||
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
|
||||
|
||||
@@ -25,18 +25,22 @@
|
||||
# > cast, as defining a new target type + generator for that type is somewhat
|
||||
# > simpler than defining a main target rule.
|
||||
|
||||
import b2.build.targets as targets
|
||||
import b2.build.virtual_target as virtual_target
|
||||
from b2.build import targets, virtual_target, property_set
|
||||
|
||||
from b2.manager import get_manager
|
||||
from b2.util import bjam_signature
|
||||
from b2.util import bjam_signature, is_iterable_typed
|
||||
|
||||
|
||||
class CastTargetClass(targets.TypedTarget):
|
||||
|
||||
def construct(name, source_targets, ps):
|
||||
def construct(self, name, source_targets, ps):
|
||||
assert isinstance(name, basestring)
|
||||
assert is_iterable_typed(source_targets, virtual_target.VirtualTarget)
|
||||
assert isinstance(ps, property_set.PropertySet)
|
||||
|
||||
result = []
|
||||
for s in source_targets:
|
||||
if not isinstance(s, virtual_targets.FileTarget):
|
||||
if not isinstance(s, virtual_target.FileTarget):
|
||||
get_manager().errors()("Source to the 'cast' metatager is not a file")
|
||||
|
||||
if s.action():
|
||||
@@ -46,8 +50,8 @@ class CastTargetClass(targets.TypedTarget):
|
||||
r = s.clone_with_different_type(self.type())
|
||||
result.append(get_manager().virtual_targets().register(r))
|
||||
|
||||
return result
|
||||
|
||||
return property_set.empty(), result
|
||||
|
||||
|
||||
@bjam_signature((["name", "type"], ["sources", "*"], ["requirements", "*"],
|
||||
["default_build", "*"], ["usage_requirements", "*"]))
|
||||
|
||||
@@ -21,7 +21,7 @@ import sys
|
||||
import b2.build.virtual_target
|
||||
from b2.build import feature, type
|
||||
from b2.util.utility import *
|
||||
from b2.util import path
|
||||
from b2.util import path, is_iterable_typed
|
||||
|
||||
__re__before_first_dash = re.compile ('([^-]*)-')
|
||||
|
||||
@@ -112,6 +112,7 @@ class Configurations(object):
|
||||
Returns True if the configuration has been added and False if
|
||||
it already exists. Reports an error if the configuration is 'used'.
|
||||
"""
|
||||
assert isinstance(id, basestring)
|
||||
if id in self.used_:
|
||||
#FIXME
|
||||
errors.error("common: the configuration '$(id)' is in use")
|
||||
@@ -132,6 +133,7 @@ class Configurations(object):
|
||||
'used' and False if it the state wasn't changed. Reports an error
|
||||
if the configuration isn't known.
|
||||
"""
|
||||
assert isinstance(id, basestring)
|
||||
if id not in self.all_:
|
||||
#FIXME:
|
||||
errors.error("common: the configuration '$(id)' is not known")
|
||||
@@ -154,10 +156,15 @@ class Configurations(object):
|
||||
|
||||
def get(self, id, param):
|
||||
""" Returns the value of a configuration parameter. """
|
||||
assert isinstance(id, basestring)
|
||||
assert isinstance(param, basestring)
|
||||
return self.params_.get(param, {}).get(id)
|
||||
|
||||
def set (self, id, param, value):
|
||||
""" Sets the value of a configuration parameter. """
|
||||
assert isinstance(id, basestring)
|
||||
assert isinstance(param, basestring)
|
||||
assert is_iterable_typed(value, basestring)
|
||||
self.params_.setdefault(param, {})[id] = value
|
||||
|
||||
# Ported from trunk@47174
|
||||
@@ -174,14 +181,11 @@ def check_init_parameters(toolset, requirement, *args):
|
||||
|
||||
The return value from this rule is a condition to be used for flags settings.
|
||||
"""
|
||||
assert isinstance(toolset, basestring)
|
||||
assert is_iterable_typed(requirement, basestring)
|
||||
from b2.build import toolset as b2_toolset
|
||||
if requirement is None:
|
||||
requirement = []
|
||||
# The type checking here is my best guess about
|
||||
# what the types should be.
|
||||
assert(isinstance(toolset, str))
|
||||
# iterable and not a string, allows for future support of sets
|
||||
assert(not isinstance(requirement, basestring) and hasattr(requirement, '__contains__'))
|
||||
sig = toolset
|
||||
condition = replace_grist(toolset, '<toolset>')
|
||||
subcondition = []
|
||||
@@ -290,15 +294,12 @@ def get_invocation_command_nodefault(
|
||||
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, str))
|
||||
assert(isinstance(tool, str))
|
||||
assert(isinstance(user_provided_command, list))
|
||||
if additional_paths is not None:
|
||||
assert(isinstance(additional_paths, list))
|
||||
assert(all([isinstance(path, str) for path in additional_paths]))
|
||||
assert(all(isinstance(path, str) for path in additional_paths))
|
||||
assert(isinstance(path_last, bool))
|
||||
|
||||
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:
|
||||
@@ -307,13 +308,13 @@ def get_invocation_command_nodefault(
|
||||
#print "warning: initialized from" [ errors.nearest-user-location ] ;
|
||||
else:
|
||||
command = check_tool(user_provided_command)
|
||||
assert(isinstance(command, list))
|
||||
command=' '.join(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))
|
||||
|
||||
@@ -325,14 +326,11 @@ def get_invocation_command(toolset, tool, user_provided_command = [],
|
||||
""" 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, str))
|
||||
assert(isinstance(tool, str))
|
||||
assert(isinstance(user_provided_command, list))
|
||||
if additional_paths is not None:
|
||||
assert(isinstance(additional_paths, list))
|
||||
assert(all([isinstance(path, str) for path in additional_paths]))
|
||||
assert(isinstance(path_last, bool))
|
||||
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,
|
||||
@@ -356,6 +354,7 @@ def get_absolute_tool_path(command):
|
||||
return the absolute path to the command. This works even if commnad
|
||||
has not path element and is present in PATH.
|
||||
"""
|
||||
assert isinstance(command, basestring)
|
||||
if os.path.dirname(command):
|
||||
return os.path.dirname(command)
|
||||
else:
|
||||
@@ -376,9 +375,9 @@ def find_tool(name, additional_paths = [], path_last = False):
|
||||
Otherwise, returns the empty string. If 'path_last' is specified,
|
||||
path is checked after 'additional_paths'.
|
||||
"""
|
||||
assert(isinstance(name, str))
|
||||
assert(isinstance(additional_paths, list))
|
||||
assert(isinstance(path_last, bool))
|
||||
assert isinstance(name, basestring)
|
||||
assert is_iterable_typed(additional_paths, basestring)
|
||||
assert isinstance(path_last, (int, bool))
|
||||
|
||||
programs = path.programs_path()
|
||||
match = path.glob(programs, [name, name + '.exe'])
|
||||
@@ -407,7 +406,7 @@ def check_tool_aux(command):
|
||||
""" Checks if 'command' can be found either in path
|
||||
or is a full name to an existing file.
|
||||
"""
|
||||
assert(isinstance(command, str))
|
||||
assert isinstance(command, basestring)
|
||||
dirname = os.path.dirname(command)
|
||||
if dirname:
|
||||
if os.path.exists(command):
|
||||
@@ -430,8 +429,7 @@ def check_tool(command):
|
||||
If comand is absolute path, check that it exists. Returns 'command'
|
||||
if ok and empty string otherwise.
|
||||
"""
|
||||
assert(isinstance(command, list))
|
||||
assert(all(isinstance(c, str) for c in command))
|
||||
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
|
||||
@@ -449,11 +447,10 @@ def handle_options(tool, condition, command, options):
|
||||
"""
|
||||
from b2.build import toolset
|
||||
|
||||
assert(isinstance(tool, str))
|
||||
assert(isinstance(condition, list))
|
||||
assert(isinstance(command, str))
|
||||
assert(isinstance(options, list))
|
||||
assert(command)
|
||||
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))
|
||||
@@ -490,8 +487,8 @@ def variable_setting_command(variable, value):
|
||||
words, on Unix systems, the variable is exported, which is consistent with the
|
||||
only possible behavior on Windows systems.
|
||||
"""
|
||||
assert(isinstance(variable, str))
|
||||
assert(isinstance(value, str))
|
||||
assert isinstance(variable, basestring)
|
||||
assert isinstance(value, basestring)
|
||||
|
||||
if os_name() == 'NT':
|
||||
return "set " + variable + "=" + value + os.linesep
|
||||
@@ -533,8 +530,8 @@ 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, str))
|
||||
assert(isinstance(paths, list))
|
||||
assert isinstance(variable, basestring)
|
||||
assert is_iterable_typed(paths, basestring)
|
||||
sep = os.path.pathsep
|
||||
return variable_setting_command(variable, sep.join(paths))
|
||||
|
||||
@@ -542,7 +539,9 @@ 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))
|
||||
|
||||
@@ -562,6 +561,7 @@ __mkdir_set = set()
|
||||
__re_windows_drive = re.compile(r'^.*:\$')
|
||||
|
||||
def mkdir(engine, target):
|
||||
assert isinstance(target, basestring)
|
||||
# If dir exists, do not update it. Do this even for $(DOT).
|
||||
bjam.call('NOUPDATE', target)
|
||||
|
||||
@@ -642,9 +642,12 @@ def format_name(format, name, target_type, prop_set):
|
||||
The returned name also has the target type specific prefix and suffix which
|
||||
puts it in a ready form to use as the value from a custom tag rule.
|
||||
"""
|
||||
assert(isinstance(format, list))
|
||||
assert(isinstance(name, str))
|
||||
assert(isinstance(target_type, str) or not type)
|
||||
if __debug__:
|
||||
from ..build.property_set import PropertySet
|
||||
assert is_iterable_typed(format, basestring)
|
||||
assert isinstance(name, basestring)
|
||||
assert isinstance(target_type, basestring)
|
||||
assert isinstance(prop_set, PropertySet)
|
||||
# assert(isinstance(prop_set, property_set.PropertySet))
|
||||
if type.is_derived(target_type, 'LIB'):
|
||||
result = "" ;
|
||||
@@ -690,6 +693,8 @@ def format_name(format, name, target_type, prop_set):
|
||||
return result
|
||||
|
||||
def join_tag(joiner, tag):
|
||||
assert isinstance(joiner, basestring)
|
||||
assert isinstance(tag, basestring)
|
||||
if tag:
|
||||
if not joiner: joiner = '-'
|
||||
return joiner + tag
|
||||
@@ -698,6 +703,11 @@ def join_tag(joiner, tag):
|
||||
__re_toolset_version = re.compile(r"<toolset.*version>(\d+)[.](\d*)")
|
||||
|
||||
def toolset_tag(name, target_type, prop_set):
|
||||
if __debug__:
|
||||
from ..build.property_set import PropertySet
|
||||
assert isinstance(name, basestring)
|
||||
assert isinstance(target_type, basestring)
|
||||
assert isinstance(prop_set, PropertySet)
|
||||
tag = ''
|
||||
|
||||
properties = prop_set.raw()
|
||||
@@ -708,7 +718,7 @@ def toolset_tag(name, target_type, prop_set):
|
||||
elif tools.startswith('como'): tag += 'como'
|
||||
elif tools.startswith('cw'): tag += 'cw'
|
||||
elif tools.startswith('darwin'): tag += 'xgcc'
|
||||
elif tools.startswith('edg'): tag += edg
|
||||
elif tools.startswith('edg'): tag += 'edg'
|
||||
elif tools.startswith('gcc'):
|
||||
flavor = prop_set.get('<toolset-gcc:flavor>')
|
||||
''.find
|
||||
@@ -764,6 +774,11 @@ def toolset_tag(name, target_type, prop_set):
|
||||
|
||||
|
||||
def threading_tag(name, target_type, prop_set):
|
||||
if __debug__:
|
||||
from ..build.property_set import PropertySet
|
||||
assert isinstance(name, basestring)
|
||||
assert isinstance(target_type, basestring)
|
||||
assert isinstance(prop_set, PropertySet)
|
||||
tag = ''
|
||||
properties = prop_set.raw()
|
||||
if '<threading>multi' in properties: tag = 'mt'
|
||||
@@ -772,6 +787,11 @@ def threading_tag(name, target_type, prop_set):
|
||||
|
||||
|
||||
def runtime_tag(name, target_type, prop_set ):
|
||||
if __debug__:
|
||||
from ..build.property_set import PropertySet
|
||||
assert isinstance(name, basestring)
|
||||
assert isinstance(target_type, basestring)
|
||||
assert isinstance(prop_set, PropertySet)
|
||||
tag = ''
|
||||
|
||||
properties = prop_set.raw()
|
||||
|
||||
@@ -45,7 +45,7 @@ import b2.build_system as build_system
|
||||
|
||||
|
||||
from b2.manager import get_manager
|
||||
from b2.util import stem, bjam_signature
|
||||
from b2.util import stem, bjam_signature, is_iterable_typed
|
||||
from b2.util.sequence import unique
|
||||
|
||||
import bjam
|
||||
@@ -88,7 +88,10 @@ __all_tests = []
|
||||
# Helper rule. Create a test target, using basename of first source if no target
|
||||
# name is explicitly passed. Remembers the created target in a global variable.
|
||||
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]))
|
||||
|
||||
@@ -189,7 +192,7 @@ __ln1 = re.compile("/(tools|libs)/(.*)/(test|example)")
|
||||
__ln2 = re.compile("/(tools|libs)/(.*)$")
|
||||
__ln3 = re.compile("(/status$)")
|
||||
def get_library_name(path):
|
||||
|
||||
assert isinstance(path, basestring)
|
||||
path = path.replace("\\", "/")
|
||||
match1 = __ln1.match(path)
|
||||
match2 = __ln2.match(path)
|
||||
@@ -216,6 +219,7 @@ __out_xml = option.get("out-xml", False, True)
|
||||
# - relative location of all source from the project root.
|
||||
#
|
||||
def dump_test(target):
|
||||
assert isinstance(target, targets.AbstractTarget)
|
||||
type = target.type()
|
||||
name = target.name()
|
||||
project = target.project()
|
||||
@@ -298,7 +302,11 @@ generators.register_composing("testing.time", [], ["TIME"])
|
||||
# contained in testing-aux.jam, which we load into Jam module named 'testing'
|
||||
|
||||
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.
|
||||
@@ -313,7 +321,12 @@ def run_path_setup(target, sources, ps):
|
||||
common.shared_library_path_variable(), dll_paths))
|
||||
|
||||
def capture_output_setup(target, sources, ps):
|
||||
run_path_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")
|
||||
|
||||
@@ -6,14 +6,153 @@ import types
|
||||
from itertools import groupby
|
||||
|
||||
|
||||
def safe_isinstance(value, types=None, class_names=None):
|
||||
"""To prevent circular imports, this extends isinstance()
|
||||
by checking also if `value` has a particular class name (or inherits from a
|
||||
particular class name). This check is safe in that an AttributeError is not
|
||||
raised in case `value` doesn't have a __class__ attribute.
|
||||
"""
|
||||
# inspect is being imported here because I seriously doubt
|
||||
# that this function will be used outside of the type
|
||||
# checking below.
|
||||
import inspect
|
||||
result = False
|
||||
if types is not None:
|
||||
result = result or isinstance(value, types)
|
||||
if class_names is not None and not result:
|
||||
# this doesn't work with inheritance, but normally
|
||||
# either the class will already be imported within the module,
|
||||
# or the class doesn't have any subclasses. For example: PropertySet
|
||||
if isinstance(class_names, basestring):
|
||||
class_names = [class_names]
|
||||
# this is the part that makes it "safe".
|
||||
try:
|
||||
base_names = [class_.__name__ for class_ in inspect.getmro(value.__class__)]
|
||||
for name in class_names:
|
||||
if name in base_names:
|
||||
return True
|
||||
except AttributeError:
|
||||
pass
|
||||
return result
|
||||
|
||||
|
||||
def is_iterable_typed(values, type_):
|
||||
return is_iterable(values) and all(isinstance(v, type_) for v in values)
|
||||
|
||||
|
||||
def is_iterable(value):
|
||||
"""Returns whether value is iterable and not a string."""
|
||||
return not isinstance(value, basestring) and hasattr(value, '__iter__')
|
||||
|
||||
|
||||
def is_iterable_or_none(value):
|
||||
return is_iterable(value) or value is None
|
||||
|
||||
|
||||
def is_single_value(value):
|
||||
# some functions may specify a bjam signature
|
||||
# that is a string type, but still allow a
|
||||
# PropertySet to be passed in
|
||||
return safe_isinstance(value, (basestring, type(None)), 'PropertySet')
|
||||
|
||||
|
||||
if __debug__:
|
||||
|
||||
from textwrap import dedent
|
||||
message = dedent(
|
||||
"""The parameter "{}" was passed in a wrong type for the "{}()" function.
|
||||
Actual:
|
||||
\ttype: {}
|
||||
\tvalue: {}
|
||||
Expected:
|
||||
\t{}
|
||||
"""
|
||||
)
|
||||
|
||||
bjam_types = {
|
||||
'*': is_iterable_or_none,
|
||||
'+': is_iterable_or_none,
|
||||
'?': is_single_value,
|
||||
'': is_single_value,
|
||||
}
|
||||
|
||||
bjam_to_python = {
|
||||
'*': 'iterable',
|
||||
'+': 'iterable',
|
||||
'?': 'single value',
|
||||
'': 'single value',
|
||||
}
|
||||
|
||||
|
||||
def get_next_var(field):
|
||||
it = iter(field)
|
||||
var = it.next()
|
||||
type_ = None
|
||||
yield_var = False
|
||||
while type_ not in bjam_types:
|
||||
try:
|
||||
# the first value has already
|
||||
# been consumed outside of the loop
|
||||
type_ = it.next()
|
||||
except StopIteration:
|
||||
# if there are no more values, then
|
||||
# var still needs to be returned
|
||||
yield_var = True
|
||||
break
|
||||
if type_ not in bjam_types:
|
||||
# type_ is not a type and is
|
||||
# another variable in the same field.
|
||||
yield var, ''
|
||||
# type_ is the next var
|
||||
var = type_
|
||||
else:
|
||||
# otherwise, type_ is a type for var
|
||||
yield var, type_
|
||||
try:
|
||||
# the next value should be a var
|
||||
var = it.next()
|
||||
except StopIteration:
|
||||
# if not, then we're done with
|
||||
# this field
|
||||
break
|
||||
if yield_var:
|
||||
yield var, ''
|
||||
|
||||
|
||||
# Decorator the specifies bjam-side prototype for a Python function
|
||||
def bjam_signature(s):
|
||||
if __debug__:
|
||||
from inspect import getcallargs
|
||||
def decorator(fn):
|
||||
function_name = fn.__module__ + '.' + fn.__name__
|
||||
def wrapper(*args, **kwargs):
|
||||
callargs = getcallargs(fn, *args, **kwargs)
|
||||
for field in s:
|
||||
for var, type_ in get_next_var(field):
|
||||
try:
|
||||
value = callargs[var]
|
||||
except KeyError:
|
||||
raise Exception(
|
||||
'Bjam Signature specifies a variable named "{}"\n'
|
||||
'but is not found within the python function signature\n'
|
||||
'for function {}()'.format(var, function_name)
|
||||
)
|
||||
if not bjam_types[type_](value):
|
||||
raise TypeError(
|
||||
message.format(var, function_name, type(type_), repr(value),
|
||||
bjam_to_python[type_])
|
||||
)
|
||||
return fn(*args, **kwargs)
|
||||
wrapper.__name__ = fn.__name__
|
||||
wrapper.bjam_signature = s
|
||||
return wrapper
|
||||
return decorator
|
||||
else:
|
||||
def decorator(f):
|
||||
f.bjam_signature = s
|
||||
return f
|
||||
|
||||
def wrap(f):
|
||||
f.bjam_signature = s
|
||||
return f
|
||||
|
||||
return wrap
|
||||
return decorator
|
||||
|
||||
def metatarget(f):
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ def make (native):
|
||||
# TODO: make os selection here.
|
||||
return make_UNIX (native)
|
||||
|
||||
@bjam_signature([['native']])
|
||||
def make_UNIX (native):
|
||||
|
||||
# VP: I have no idea now 'native' can be empty here! But it can!
|
||||
|
||||
@@ -5,7 +5,11 @@
|
||||
|
||||
import operator
|
||||
|
||||
from b2.util import is_iterable
|
||||
|
||||
|
||||
def unique (values, stable=False):
|
||||
assert is_iterable(values)
|
||||
if stable:
|
||||
s = set()
|
||||
r = []
|
||||
@@ -21,6 +25,8 @@ def max_element (elements, ordered = None):
|
||||
""" Returns the maximum number in 'elements'. Uses 'ordered' for comparisons,
|
||||
or '<' is none is provided.
|
||||
"""
|
||||
assert is_iterable(elements)
|
||||
assert callable(ordered) or ordered is None
|
||||
if not ordered: ordered = operator.lt
|
||||
|
||||
max = elements [0]
|
||||
@@ -34,6 +40,8 @@ def select_highest_ranked (elements, ranks):
|
||||
""" Returns all of 'elements' for which corresponding element in parallel
|
||||
list 'rank' is equal to the maximum value in 'rank'.
|
||||
"""
|
||||
assert is_iterable(elements)
|
||||
assert is_iterable(ranks)
|
||||
if not elements:
|
||||
return []
|
||||
|
||||
|
||||
@@ -3,11 +3,15 @@
|
||||
# all copies. This software is provided "as is" without express or implied
|
||||
# warranty, and with no claim as to its suitability for any purpose.
|
||||
|
||||
from utility import to_seq
|
||||
from b2.util import is_iterable
|
||||
from .utility import to_seq
|
||||
|
||||
|
||||
def difference (b, a):
|
||||
""" Returns the elements of B that are not in A.
|
||||
"""
|
||||
assert is_iterable(b)
|
||||
assert is_iterable(a)
|
||||
result = []
|
||||
for element in b:
|
||||
if not element in a:
|
||||
@@ -18,6 +22,8 @@ def difference (b, a):
|
||||
def intersection (set1, set2):
|
||||
""" Removes from set1 any items which don't appear in set2 and returns the result.
|
||||
"""
|
||||
assert is_iterable(set1)
|
||||
assert is_iterable(set2)
|
||||
result = []
|
||||
for v in set1:
|
||||
if v in set2:
|
||||
@@ -39,4 +45,6 @@ def equal (a, b):
|
||||
""" Returns True iff 'a' contains the same elements as 'b', irrespective of their order.
|
||||
# TODO: Python 2.4 has a proper set class.
|
||||
"""
|
||||
assert is_iterable(a)
|
||||
assert is_iterable(b)
|
||||
return contains (a, b) and contains (b, a)
|
||||
|
||||
@@ -11,6 +11,7 @@ import re
|
||||
import os
|
||||
import bjam
|
||||
from b2.exceptions import *
|
||||
from b2.util import is_iterable_typed
|
||||
|
||||
__re_grist_and_value = re.compile (r'(<[^>]*>)(.*)')
|
||||
__re_grist_content = re.compile ('^<(.*)>$')
|
||||
@@ -40,13 +41,13 @@ def add_grist (features):
|
||||
features: one string or a sequence of strings
|
||||
return: the gristed string, if features is a string, or a sequence of gristed strings, if features is a sequence
|
||||
"""
|
||||
|
||||
assert is_iterable_typed(features, basestring) or isinstance(features, basestring)
|
||||
def grist_one (feature):
|
||||
if feature [0] != '<' and feature [len (feature) - 1] != '>':
|
||||
return '<' + feature + '>'
|
||||
else:
|
||||
return feature
|
||||
|
||||
|
||||
if isinstance (features, str):
|
||||
return grist_one (features)
|
||||
else:
|
||||
@@ -56,6 +57,8 @@ def replace_grist (features, new_grist):
|
||||
""" Replaces the grist of a string by a new one.
|
||||
Returns the string with the new grist.
|
||||
"""
|
||||
assert is_iterable_typed(features, basestring) or isinstance(features, basestring)
|
||||
assert isinstance(new_grist, basestring)
|
||||
def replace_grist_one (name, new_grist):
|
||||
split = __re_grist_and_value.match (name)
|
||||
if not split:
|
||||
@@ -71,12 +74,14 @@ def replace_grist (features, new_grist):
|
||||
def get_value (property):
|
||||
""" Gets the value of a property, that is, the part following the grist, if any.
|
||||
"""
|
||||
assert is_iterable_typed(property, basestring) or isinstance(property, basestring)
|
||||
return replace_grist (property, '')
|
||||
|
||||
|
||||
def get_grist (value):
|
||||
""" Returns the grist of a string.
|
||||
If value is a sequence, does it for every value and returns the result as a sequence.
|
||||
"""
|
||||
assert is_iterable_typed(value, basestring) or isinstance(value, basestring)
|
||||
def get_grist_one (name):
|
||||
split = __re_grist_and_value.match (name)
|
||||
if not split:
|
||||
@@ -93,6 +98,7 @@ def ungrist (value):
|
||||
""" Returns the value without grist.
|
||||
If value is a sequence, does it for every value and returns the result as a sequence.
|
||||
"""
|
||||
assert is_iterable_typed(value, basestring) or isinstance(value, basestring)
|
||||
def ungrist_one (value):
|
||||
stripped = __re_grist_content.match (value)
|
||||
if not stripped:
|
||||
@@ -109,12 +115,15 @@ def replace_suffix (name, new_suffix):
|
||||
""" Replaces the suffix of name by new_suffix.
|
||||
If no suffix exists, the new one is added.
|
||||
"""
|
||||
assert isinstance(name, basestring)
|
||||
assert isinstance(new_suffix, basestring)
|
||||
split = os.path.splitext (name)
|
||||
return split [0] + new_suffix
|
||||
|
||||
def forward_slashes (s):
|
||||
""" Converts all backslashes to forward slashes.
|
||||
"""
|
||||
assert isinstance(s, basestring)
|
||||
return __re_backslash.sub ('/', s)
|
||||
|
||||
|
||||
@@ -122,6 +131,7 @@ def split_action_id (id):
|
||||
""" Splits an id in the toolset and specific rule parts. E.g.
|
||||
'gcc.compile.c++' returns ('gcc', 'compile.c++')
|
||||
"""
|
||||
assert isinstance(id, basestring)
|
||||
split = id.split ('.', 1)
|
||||
toolset = split [0]
|
||||
name = ''
|
||||
|
||||
Reference in New Issue
Block a user