mirror of
https://github.com/boostorg/build.git
synced 2026-02-15 00:52:16 +00:00
Port build/configure.jam.
Also allow to expose Python class to Jam, which fixes tag.py and inline.py testcases. [SVN r64610]
This commit is contained in:
@@ -55,7 +55,7 @@ def alias(name, sources, requirements=None, default_build=None, usage_requiremen
|
||||
|
||||
targets.main_target_alternative(AliasTarget(
|
||||
name, project,
|
||||
targets.main_target_sources(sources, name),
|
||||
targets.main_target_sources(sources, name, no_renaming=True),
|
||||
targets.main_target_requirements(requirements or [], project),
|
||||
targets.main_target_default_build(default_build, project),
|
||||
targets.main_target_usage_requirements(usage_requirements or [], project)))
|
||||
|
||||
157
v2/build/configure.py
Normal file
157
v2/build/configure.py
Normal file
@@ -0,0 +1,157 @@
|
||||
# Status: ported.
|
||||
# Base revison: 64488
|
||||
#
|
||||
# Copyright (c) 2010 Vladimir Prus.
|
||||
#
|
||||
# Use, modification and distribution is subject to the Boost Software
|
||||
# License Version 1.0. (See accompanying file LICENSE_1_0.txt or
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# This module defines function to help with two main tasks:
|
||||
#
|
||||
# - Discovering build-time configuration for the purposes of adjusting
|
||||
# build process.
|
||||
# - Reporting what is built, and how it is configured.
|
||||
|
||||
import b2.build.property as property
|
||||
import b2.build.property_set as property_set
|
||||
|
||||
import b2.build.targets
|
||||
|
||||
from b2.manager import get_manager
|
||||
from b2.util.sequence import unique
|
||||
from b2.util import bjam_signature, value_to_jam
|
||||
|
||||
import bjam
|
||||
import os
|
||||
|
||||
__width = 30
|
||||
|
||||
def set_width(width):
|
||||
global __width
|
||||
__width = 30
|
||||
|
||||
__components = []
|
||||
__built_components = []
|
||||
__component_logs = {}
|
||||
__announced_checks = False
|
||||
|
||||
__log_file = None
|
||||
__log_fd = -1
|
||||
|
||||
def register_components(components):
|
||||
"""Declare that the components specified by the parameter exist."""
|
||||
__components.extend(components)
|
||||
|
||||
def components_building(components):
|
||||
"""Declare that the components specified by the parameters will be build."""
|
||||
__built_components.extend(components)
|
||||
|
||||
def log_component_configuration(component, message):
|
||||
"""Report something about component configuration that the user should better know."""
|
||||
__component_logs.setdefault(component, []).append(message)
|
||||
|
||||
def log_check_result(result):
|
||||
global __announced_checks
|
||||
if not __announced_checks:
|
||||
print "Performing configuration checks"
|
||||
__announced_checks = True
|
||||
|
||||
print result
|
||||
|
||||
def log_library_search_result(library, result):
|
||||
log_check_result((" - %(library)s : %(result)s" % locals()).rjust(width))
|
||||
|
||||
|
||||
def print_component_configuration():
|
||||
|
||||
print "\nComponent configuration:"
|
||||
for c in __components:
|
||||
if c in __built_components:
|
||||
s = "building"
|
||||
else:
|
||||
s = "not building"
|
||||
message = " - %s)" % c
|
||||
message = message.rjust(__width)
|
||||
message += " : " + s
|
||||
for m in __component_logs.get(c, []):
|
||||
print " -" + m
|
||||
print ""
|
||||
|
||||
__builds_cache = {}
|
||||
|
||||
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.
|
||||
|
||||
result = []
|
||||
|
||||
existing = __builds_cache.get((what, ps), None)
|
||||
if existing is None:
|
||||
|
||||
result = False
|
||||
__builds_cache[(what, ps)] = False
|
||||
|
||||
targets = b2.build.targets.generate_from_reference(
|
||||
metatarget_reference, project, ps).targets()
|
||||
jam_targets = []
|
||||
for t in targets:
|
||||
jam_targets.append(t.actualize())
|
||||
|
||||
x = (" - %s" % what).rjust(__width)
|
||||
if bjam.call("UPDATE_NOW", jam_targets, str(__log_fd), "ignore-minus-n"):
|
||||
__builds_cache[(what, ps)] = True
|
||||
result = True
|
||||
log_check_result("%s: yes" % x)
|
||||
else:
|
||||
log_check_result("%s: no" % x)
|
||||
|
||||
return result
|
||||
else:
|
||||
return existing
|
||||
|
||||
def set_log_file(log_file_name):
|
||||
# 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.
|
||||
global __log_file, __log_fd
|
||||
dirname = os.path.dirname(log_file_name)
|
||||
if not os.path.exists(dirname):
|
||||
os.makedirs(dirname)
|
||||
# Make sure to keep the file around, so that it's not
|
||||
# garbage-collected and closed
|
||||
__log_file = open(log_file_name, "w")
|
||||
__log_fd = __log_file.fileno()
|
||||
|
||||
# Frontend rules
|
||||
|
||||
class CheckTargetBuildsWorker:
|
||||
|
||||
def __init__(self, target, true_properties, false_properties):
|
||||
self.target = target
|
||||
self.true_properties = property.create_from_strings(true_properties)
|
||||
self.false_properties = property.create_from_strings(false_properties)
|
||||
|
||||
def check(self, ps):
|
||||
|
||||
# FIXME: this should not be hardcoded. Other checks might
|
||||
# want to consider different set of features as relevant.
|
||||
toolset = ps.get_properties('toolset')[0]
|
||||
ps = property_set.create([toolset])
|
||||
t = get_manager().targets().current()
|
||||
p = t.project()
|
||||
if builds(self.target, p, ps, "%s builds" % self.target):
|
||||
return self.true_properties
|
||||
else:
|
||||
return self.false_properties
|
||||
|
||||
@bjam_signature((["target"], ["true_properties", "*"], ["false_properties", "*"]))
|
||||
def check_target_builds(target, true_properties, false_properties):
|
||||
worker = CheckTargetBuildsWorker(target, true_properties, false_properties)
|
||||
value = value_to_jam(worker.check)
|
||||
return "<conditional>" + value
|
||||
|
||||
get_manager().projects().add_rule("check-target-builds", check_target_builds)
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ class BjamNativeAction:
|
||||
if property_set:
|
||||
p = property_set.raw()
|
||||
|
||||
b2.util.call_jam_function(self.action_name, targets, sources, p)
|
||||
b2.util.set_jam_action(self.action_name, targets, sources, p)
|
||||
|
||||
action_modifiers = {"updated": 0x01,
|
||||
"together": 0x02,
|
||||
@@ -144,6 +144,10 @@ class Engine:
|
||||
# Rule is already in indirect format
|
||||
return action_name
|
||||
else:
|
||||
ix = action_name.find('.')
|
||||
if ix != -1 and action_name[:ix] == context_module:
|
||||
return context_module + '%' + action_name[ix+1:]
|
||||
|
||||
return context_module + '%' + action_name
|
||||
|
||||
def register_bjam_action (self, action_name, function=None):
|
||||
|
||||
@@ -650,7 +650,8 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project))
|
||||
modules = sys.modules
|
||||
for class_name in modules:
|
||||
parts = class_name.split('.')
|
||||
if name is class_name or parts[0] == "b2" and parts[-1] == name:
|
||||
if name is class_name or parts[0] == "b2" \
|
||||
and parts[-1] == name.replace("-", "_"):
|
||||
module = modules[class_name]
|
||||
self.loaded_tool_modules_[name] = module
|
||||
return module
|
||||
|
||||
@@ -273,14 +273,6 @@ def split_conditional (property):
|
||||
|
||||
return None
|
||||
|
||||
# FIXME: this should go
|
||||
def is_conditional (property):
|
||||
""" Returns True if a property is conditional.
|
||||
"""
|
||||
if __re_colon.search (replace_grist (property, '')):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def select (features, properties):
|
||||
""" Selects properties which correspond to any of the given features.
|
||||
@@ -310,7 +302,7 @@ def evaluate_conditionals_in_context (properties, context):
|
||||
else:
|
||||
base.append (p)
|
||||
|
||||
result = base
|
||||
result = base[:]
|
||||
for p in conditional:
|
||||
|
||||
# Evaluate condition
|
||||
|
||||
@@ -303,9 +303,9 @@ class PropertySet:
|
||||
context = self
|
||||
|
||||
if not self.evaluated_.has_key(context):
|
||||
# FIXME: figure why the call messes up first parameter
|
||||
self.evaluated_[context] = create(
|
||||
property.evaluate_conditionals_in_context(self.all_raw_,
|
||||
context.raw()))
|
||||
property.evaluate_conditionals_in_context(self.all(), context))
|
||||
|
||||
return self.evaluated_[context]
|
||||
|
||||
@@ -412,6 +412,8 @@ class PropertySet:
|
||||
def get (self, feature):
|
||||
""" Returns all values of 'feature'.
|
||||
"""
|
||||
if type(feature) == type([]):
|
||||
feature = feature[0]
|
||||
if not isinstance(feature, b2.build.feature.Feature):
|
||||
feature = b2.build.feature.get(feature)
|
||||
|
||||
@@ -439,9 +441,5 @@ class PropertySet:
|
||||
return result
|
||||
|
||||
def __contains__(self, item):
|
||||
for p in self.all_set_:
|
||||
if p.feature().name() == "toolset":
|
||||
print "EXISTING", hash(p), hash(p._feature), hash(p._value), "--", hash(item._feature), has(item._value)
|
||||
print self.all_set_
|
||||
return item in self.all_set_
|
||||
|
||||
|
||||
@@ -87,7 +87,6 @@ from b2.build.errors import user_error_checkpoint
|
||||
import b2.build.build_request as build_request
|
||||
|
||||
import b2.util.set
|
||||
|
||||
_re_separate_target_from_properties = re.compile (r'^([^<]*)(/(<.*))?$')
|
||||
|
||||
class TargetRegistry:
|
||||
@@ -111,7 +110,7 @@ class TargetRegistry:
|
||||
target.project ().add_alternative (target)
|
||||
return target
|
||||
|
||||
def main_target_sources (self, sources, main_target_name, no_remaning=0):
|
||||
def main_target_sources (self, sources, main_target_name, no_renaming=0):
|
||||
"""Return the list of sources to use, if main target rule is invoked
|
||||
with 'sources'. If there are any objects in 'sources', they are treated
|
||||
as main target instances, and the name of such targets are adjusted to
|
||||
@@ -120,17 +119,20 @@ class TargetRegistry:
|
||||
result = []
|
||||
|
||||
for t in sources:
|
||||
|
||||
t = b2.util.jam_to_value_maybe(t)
|
||||
|
||||
if isinstance (t, AbstractTarget):
|
||||
name = t.name ()
|
||||
|
||||
if not no_renaming:
|
||||
new_name = main_target_name + '__' + name
|
||||
t.rename (new_name)
|
||||
name = main_target_name + '__' + name
|
||||
t.rename (name)
|
||||
|
||||
# Inline targets are not built by default.
|
||||
p = t.project()
|
||||
p.mark_target_as_explicit(name)
|
||||
result.append (new_name)
|
||||
result.append(name)
|
||||
|
||||
else:
|
||||
result.append (t)
|
||||
@@ -776,6 +778,50 @@ class FileReference (AbstractTarget):
|
||||
|
||||
return self.file_location_
|
||||
|
||||
def resolve_reference(target_reference, project):
|
||||
""" Given a target_reference, made in context of 'project',
|
||||
returns the AbstractTarget instance that is referred to, as well
|
||||
as properties explicitly specified for this reference.
|
||||
"""
|
||||
# Separate target name from properties override
|
||||
split = _re_separate_target_from_properties.match (target_reference)
|
||||
if not split:
|
||||
raise BaseException ("Invalid reference: '%s'" % target_reference)
|
||||
|
||||
id = split.group (1)
|
||||
|
||||
sproperties = []
|
||||
|
||||
if split.group (3):
|
||||
sproperties = property.create_from_strings(feature.split(split.group(3)))
|
||||
sproperties = feature.expand_composites(sproperties)
|
||||
|
||||
# Find the target
|
||||
target = project.find (id)
|
||||
|
||||
return (target, property_set.create(sproperties))
|
||||
|
||||
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
|
||||
- usage requirements
|
||||
- generated virtual targets, if any
|
||||
target_reference: Target reference
|
||||
project: Project where the reference is made
|
||||
property_set: Properties of the main target that makes the reference
|
||||
"""
|
||||
target, sproperties = resolve_reference(target_reference, project)
|
||||
|
||||
# Take properties which should be propagated and refine them
|
||||
# with source-specific requirements.
|
||||
propagated = property_set.propagated()
|
||||
rproperties = propagated.refine(sproperties)
|
||||
|
||||
return target.generate(rproperties)
|
||||
|
||||
|
||||
|
||||
class BasicTarget (AbstractTarget):
|
||||
""" Implements the most standard way of constructing main target
|
||||
alternative from sources. Allows sources to be either file or
|
||||
@@ -835,29 +881,6 @@ class BasicTarget (AbstractTarget):
|
||||
def default_build (self):
|
||||
return self.default_build_
|
||||
|
||||
def resolve_reference (self, target_reference, project):
|
||||
""" Given a target_reference, made in context of 'project',
|
||||
returns the AbstractTarget instance that is referred to, as well
|
||||
as properties explicitly specified for this reference.
|
||||
"""
|
||||
# Separate target name from properties override
|
||||
split = _re_separate_target_from_properties.match (target_reference)
|
||||
if not split:
|
||||
raise BaseException ("Invalid reference: '%s'" % target_reference)
|
||||
|
||||
id = split.group (1)
|
||||
|
||||
sproperties = []
|
||||
|
||||
if split.group (3):
|
||||
sproperties = property.create_from_strings(feature.split(split.group(3)))
|
||||
sproperties = feature.expand_composites(sproperties)
|
||||
|
||||
# Find the target
|
||||
target = project.find (id)
|
||||
|
||||
return (target, property_set.create(sproperties))
|
||||
|
||||
def common_properties (self, build_request, requirements):
|
||||
""" Given build request and requirements, return properties
|
||||
common to dependency build request and target build
|
||||
@@ -908,24 +931,23 @@ class BasicTarget (AbstractTarget):
|
||||
#
|
||||
# might come from project's requirements.
|
||||
unconditional = feature.expand(requirements.non_conditional())
|
||||
|
||||
raw = context.all()
|
||||
raw = property.refine(raw, unconditional)
|
||||
|
||||
context = context.refine(property_set.create(unconditional))
|
||||
|
||||
# We've collected properties that surely must be present in common
|
||||
# properties. We now try to figure out what other properties
|
||||
# should be added in order to satisfy rules (4)-(6) from the docs.
|
||||
|
||||
conditionals = requirements.conditional()
|
||||
conditionals = property_set.create(requirements.conditional())
|
||||
|
||||
# It's supposed that #conditionals iterations
|
||||
# should be enough for properties to propagate along conditions in any
|
||||
# direction.
|
||||
max_iterations = len(conditionals) +\
|
||||
max_iterations = len(conditionals.all()) +\
|
||||
len(requirements.get("<conditional>")) + 1
|
||||
|
||||
added_requirements = []
|
||||
current = raw
|
||||
current = context
|
||||
|
||||
# It's assumed that ordinary conditional requirements can't add
|
||||
# <indirect-conditional> properties, and that rules referred
|
||||
@@ -933,25 +955,24 @@ class BasicTarget (AbstractTarget):
|
||||
# <indirect-conditional> properties. So the list of indirect conditionals
|
||||
# does not change.
|
||||
indirect = requirements.get("<conditional>")
|
||||
indirect = [s[1:] for s in indirect]
|
||||
|
||||
ok = 0
|
||||
for i in range(0, max_iterations):
|
||||
|
||||
e = property.evaluate_conditionals_in_context(conditionals, current)
|
||||
e = conditionals.evaluate_conditionals(current).all()[:]
|
||||
|
||||
# Evaluate indirect conditionals.
|
||||
for i in indirect:
|
||||
i = b2.util.jam_to_value_maybe(i)
|
||||
if callable(i):
|
||||
# This is Python callable, yeah.
|
||||
e.extend(bjam.call(i, current))
|
||||
e.extend(i(current))
|
||||
else:
|
||||
# Name of bjam function. Because bjam is unable to handle
|
||||
# list of Property, pass list of strings.
|
||||
br = b2.util.call_jam_function(i, [str(p) for p in current])
|
||||
br = b2.util.call_jam_function(i[1:], [str(p) for p in current.all()])
|
||||
if br:
|
||||
e.extend(property.create_from_strings(br))
|
||||
|
||||
|
||||
if e == added_requirements:
|
||||
# If we got the same result, we've found final properties.
|
||||
@@ -963,7 +984,7 @@ class BasicTarget (AbstractTarget):
|
||||
# Recompute 'current' using initial properties and conditional
|
||||
# requirements.
|
||||
added_requirements = e
|
||||
current = property.refine(raw, feature.expand(e))
|
||||
current = context.refine(property_set.create(feature.expand(e)))
|
||||
|
||||
if not ok:
|
||||
self.manager().errors()("Can't evaluate conditional properties "
|
||||
@@ -973,7 +994,7 @@ class BasicTarget (AbstractTarget):
|
||||
if what == "added":
|
||||
return property_set.create(unconditional + added_requirements)
|
||||
elif what == "refined":
|
||||
return property_set.create(current)
|
||||
return current
|
||||
else:
|
||||
self.manager().errors("Invalid value of the 'what' parameter")
|
||||
|
||||
@@ -1029,7 +1050,7 @@ class BasicTarget (AbstractTarget):
|
||||
usage_requirements = []
|
||||
for id in target_ids:
|
||||
|
||||
result = self.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()
|
||||
|
||||
@@ -1046,7 +1067,7 @@ class BasicTarget (AbstractTarget):
|
||||
usage_requirements = []
|
||||
for p in properties:
|
||||
|
||||
result = self.generate_from_reference(p.value(), self.project_, ps)
|
||||
result = generate_from_reference(p.value(), self.project_, ps)
|
||||
|
||||
for t in result.targets():
|
||||
result_properties.append(property.Property(p.feature(), t))
|
||||
@@ -1180,25 +1201,6 @@ class BasicTarget (AbstractTarget):
|
||||
self.manager().targets().decrease_indent()
|
||||
|
||||
return self.generated_[ps]
|
||||
|
||||
def generate_from_reference (self, 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
|
||||
- usage requirements
|
||||
- generated virtual targets, if any
|
||||
target_reference: Target reference
|
||||
project: Project where the reference is made
|
||||
property_set: Properties of the main target that makes the reference
|
||||
"""
|
||||
target, sproperties = self.resolve_reference(target_reference, project)
|
||||
|
||||
# Take properties which should be propagated and refine them
|
||||
# with source-specific requirements.
|
||||
propagated = property_set.propagated()
|
||||
rproperties = propagated.refine(sproperties)
|
||||
|
||||
return target.generate(rproperties)
|
||||
|
||||
def compute_usage_requirements (self, subvariant):
|
||||
""" Given the set of generated targets, and refined build
|
||||
@@ -1276,6 +1278,9 @@ class TypedTarget (BasicTarget):
|
||||
def __init__ (self, name, project, type, sources, requirements, default_build, usage_requirements):
|
||||
BasicTarget.__init__ (self, name, project, sources, requirements, default_build, usage_requirements)
|
||||
self.type_ = type
|
||||
|
||||
def __jam_repr__(self):
|
||||
return b2.util.value_to_jam(self)
|
||||
|
||||
def type (self):
|
||||
return self.type_
|
||||
|
||||
@@ -78,6 +78,7 @@ import b2.build.property_set as property_set
|
||||
import b2.build.property as property
|
||||
|
||||
from b2.manager import get_manager
|
||||
from b2.util import bjam_signature
|
||||
|
||||
__re_starts_with_at = re.compile ('^@(.*)')
|
||||
|
||||
@@ -533,16 +534,22 @@ class AbstractFileTarget (VirtualTarget):
|
||||
|
||||
if tag:
|
||||
|
||||
rule_names = [t[:1] for t in tag if t[0] == '@']
|
||||
if rule_names:
|
||||
if len(tag) > 1:
|
||||
self.manager_.errors()(
|
||||
"""<tag>@rulename is present but is not the only <tag> feature""")
|
||||
|
||||
self.name_ = bjam.call(rule_names[0], specified_name, self.type_, ps)
|
||||
else:
|
||||
if len(tag) > 1:
|
||||
self.manager_.errors()(
|
||||
"""The value of the <tag> feature must be '@rule-nane'""")
|
||||
"""<tag>@rulename is present but is not the only <tag> feature""")
|
||||
|
||||
tag = tag[0]
|
||||
if callable(tag):
|
||||
self.name_ = tag(specified_name, self.type_, ps)
|
||||
else:
|
||||
if not tag[0] == '@':
|
||||
self.manager_.errors()("""The value of the <tag> feature must be '@rule-nane'""")
|
||||
|
||||
exported_ps = b2.util.value_to_jam(ps, methods=True)
|
||||
self.name_ = b2.util.call_jam_function(
|
||||
tag[1:], specified_name, self.type_, exported_ps)
|
||||
if self.name_:
|
||||
self.name_ = self.name_[0]
|
||||
|
||||
# If there's no tag or the tag rule returned nothing.
|
||||
if not tag or not self.name_:
|
||||
@@ -571,10 +578,13 @@ class AbstractFileTarget (VirtualTarget):
|
||||
|
||||
return name
|
||||
|
||||
@bjam_signature((["specified_name"], ["type"], ["property_set"]))
|
||||
def add_prefix_and_suffix(specified_name, type, property_set):
|
||||
"""Appends the suffix appropriate to 'type/property-set' combination
|
||||
to the specified name and returns the result."""
|
||||
|
||||
property_set = b2.util.jam_to_value_maybe(property_set)
|
||||
|
||||
suffix = ""
|
||||
if type:
|
||||
suffix = b2.build.type.generated_target_suffix(type, property_set)
|
||||
|
||||
@@ -460,6 +460,8 @@ def main_real():
|
||||
global_build_dir = option.get("build-dir")
|
||||
manager = Manager(engine, global_build_dir)
|
||||
|
||||
import b2.build.configure as configure
|
||||
|
||||
if "--version" in sys.argv:
|
||||
|
||||
version.report()
|
||||
@@ -587,17 +589,18 @@ def main_real():
|
||||
## {
|
||||
## generators.dump ;
|
||||
## }
|
||||
|
||||
|
||||
## # We wish to put config.log in the build directory corresponding
|
||||
## # to Jamroot, so that the location does not differ depending on
|
||||
## # directory where we do build. The amount of indirection necessary
|
||||
## # here is scary.
|
||||
## local first-project = [ $(targets[0]).project ] ;
|
||||
## local first-project-root-location = [ $(first-project).get project-root ] ;
|
||||
## local first-project-root-module = [ project.load $(first-project-root-location) ] ;
|
||||
## local first-project-root = [ project.target $(first-project-root-module) ] ;
|
||||
## local first-build-build-dir = [ $(first-project-root).build-dir ] ;
|
||||
## configure.set-log-file $(first-build-build-dir)/config.log ;
|
||||
# We wish to put config.log in the build directory corresponding
|
||||
# to Jamroot, so that the location does not differ depending on
|
||||
# directory where we do build. The amount of indirection necessary
|
||||
# here is scary.
|
||||
first_project = targets[0].project()
|
||||
first_project_root_location = first_project.get('project-root')
|
||||
first_project_root_module = manager.projects().load(first_project_root_location)
|
||||
first_project_root = manager.projects().target(first_project_root_module)
|
||||
first_build_build_dir = first_project_root.build_dir()
|
||||
configure.set_log_file(os.path.join(first_build_build_dir, "config.log"))
|
||||
|
||||
virtual_targets = []
|
||||
|
||||
|
||||
@@ -856,9 +856,31 @@ call_python_function(RULE* r, FRAME* frame)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Do nothing. There are cases, e.g. feature.feature function that
|
||||
should return value for the benefit of Python code and which
|
||||
also can be called by Jam code. */
|
||||
/* See if this is an instance that defines special __jam_repr__
|
||||
method. */
|
||||
if (PyInstance_Check(py_result)
|
||||
&& PyObject_HasAttrString(py_result, "__jam_repr__"))
|
||||
{
|
||||
PyObject* repr = PyObject_GetAttrString(py_result, "__jam_repr__");
|
||||
if (repr)
|
||||
{
|
||||
PyObject* arguments2 = PyTuple_New(0);
|
||||
PyObject* py_result2 = PyObject_Call(repr, arguments2, 0);
|
||||
Py_DECREF(repr);
|
||||
Py_DECREF(arguments2);
|
||||
if (PyString_Check(py_result2))
|
||||
{
|
||||
result = list_new(0, newstr(PyString_AsString(py_result2)));
|
||||
}
|
||||
Py_DECREF(py_result2);
|
||||
}
|
||||
}
|
||||
|
||||
/* If 'result' is still empty, do nothing. There are cases, e.g.
|
||||
feature.feature function that should return value for the benefit
|
||||
of Python code and which also can be called by Jam code, where
|
||||
no sensible value can be returned. We cannot even emit a warning,
|
||||
since there will be a pile of them. */
|
||||
}
|
||||
|
||||
Py_DECREF( py_result );
|
||||
|
||||
@@ -187,6 +187,15 @@ if ! $(dont-build)
|
||||
DEPENDS all : $(targets) ;
|
||||
}
|
||||
|
||||
rule call-in-module ( m : rulename : * )
|
||||
{
|
||||
module $(m)
|
||||
{
|
||||
return [ $(2) $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ] ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
rule set-update-action ( action : targets * : sources * : properties * )
|
||||
{
|
||||
$(action) $(targets) : $(sources) : $(properties) ;
|
||||
|
||||
@@ -38,12 +38,6 @@ class Manager:
|
||||
self.errors_ = Errors()
|
||||
self.command_line_free_features_ = property_set.empty()
|
||||
|
||||
# Object Map.
|
||||
# TODO: This is a kludge: maps object names to the actual instances.
|
||||
# Sometimes, objects are stored in properties, along with some grist.
|
||||
# This map is used to store the value and return an id, which can be later on used to retriev it back.
|
||||
self.object_map_ = {}
|
||||
|
||||
global the_manager
|
||||
the_manager = self
|
||||
|
||||
@@ -86,22 +80,6 @@ class Manager:
|
||||
def set_command_line_free_features(self, v):
|
||||
self.command_line_free_features_ = v
|
||||
|
||||
def register_object (self, value):
|
||||
""" Stores an object in a map and returns a key that can be used to retrieve it.
|
||||
"""
|
||||
key = 'object_registry_' + str (value)
|
||||
self.object_map_ [key] = value
|
||||
return key
|
||||
|
||||
def get_object (self, key):
|
||||
""" Returns a previously registered object.
|
||||
"""
|
||||
if not isinstance (key, str):
|
||||
# Probably it's the object itself.
|
||||
return key
|
||||
|
||||
return self.object_map_ [key]
|
||||
|
||||
def construct (self, properties = [], targets = []):
|
||||
""" Constructs the dependency graph.
|
||||
properties: the build properties.
|
||||
|
||||
@@ -46,6 +46,9 @@ def flush_annotations(xml=0):
|
||||
print_annotation(ann[0], ann[1], xml)
|
||||
annotations = []
|
||||
|
||||
def clear_annotations():
|
||||
global annotations
|
||||
annotations = []
|
||||
|
||||
defer_annotations = 0
|
||||
|
||||
|
||||
@@ -64,6 +64,10 @@ def run_tests(critical_tests, other_tests):
|
||||
print "PASSED"
|
||||
else:
|
||||
print "FAILED"
|
||||
|
||||
if i == "regression":
|
||||
BoostBuild.flush_annotations()
|
||||
BoostBuild.clear_annotations()
|
||||
else:
|
||||
rs = "succeed"
|
||||
if not passed:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
import bjam
|
||||
import re
|
||||
import types
|
||||
|
||||
# Decorator the specifies bjam-side prototype for a Python function
|
||||
def bjam_signature(s):
|
||||
@@ -39,7 +40,7 @@ def unquote(s):
|
||||
|
||||
_extract_jamfile_and_rule = re.compile("(Jamfile<.*>)%(.*)")
|
||||
|
||||
def call_jam_function(name, *args):
|
||||
def set_jam_action(name, *args):
|
||||
|
||||
m = _extract_jamfile_and_rule.match(name)
|
||||
if m:
|
||||
@@ -49,6 +50,62 @@ def call_jam_function(name, *args):
|
||||
|
||||
return bjam.call(*args)
|
||||
|
||||
|
||||
def call_jam_function(name, *args):
|
||||
|
||||
m = _extract_jamfile_and_rule.match(name)
|
||||
if m:
|
||||
args = ("call-in-module", m.group(1), m.group(2)) + args
|
||||
return bjam.call(*args)
|
||||
else:
|
||||
return bjam.call(*((name,) + args))
|
||||
|
||||
__value_id = 0
|
||||
__python_to_jam = {}
|
||||
__jam_to_python = {}
|
||||
|
||||
def value_to_jam(value, methods=False):
|
||||
"""Makes a token to refer to a Python value inside Jam language code.
|
||||
|
||||
The token is merely a string that can be passed around in Jam code and
|
||||
eventually passed back. For example, we might want to pass PropertySet
|
||||
instance to a tag function and it might eventually call back
|
||||
to virtual_target.add_suffix_and_prefix, passing the same instance.
|
||||
|
||||
For values that are classes, we'll also make class methods callable
|
||||
from Jam.
|
||||
|
||||
Note that this is necessary to make a bit more of existing Jamfiles work.
|
||||
This trick should not be used to much, or else the performance benefits of
|
||||
Python port will be eaten.
|
||||
"""
|
||||
|
||||
global __value_id
|
||||
|
||||
r = __python_to_jam.get(value, None)
|
||||
if r:
|
||||
return r
|
||||
|
||||
exported_name = '###_' + str(__value_id)
|
||||
__value_id = __value_id + 1
|
||||
__python_to_jam[value] = exported_name
|
||||
__jam_to_python[exported_name] = value
|
||||
|
||||
if methods and type(value) == types.InstanceType:
|
||||
for field_name in dir(value):
|
||||
field = getattr(value, field_name)
|
||||
if callable(field) and not field_name.startswith("__"):
|
||||
bjam.import_rule("", exported_name + "." + field_name, field)
|
||||
|
||||
return exported_name
|
||||
|
||||
def jam_to_value_maybe(jam_value):
|
||||
|
||||
if type(jam_value) == type("") and jam_value.startswith("###"):
|
||||
return __jam_to_python[jam_value]
|
||||
else:
|
||||
return jam_value
|
||||
|
||||
def stem(filename):
|
||||
i = filename.find('.')
|
||||
if i != -1:
|
||||
|
||||
Reference in New Issue
Block a user