2
0
mirror of https://github.com/boostorg/build.git synced 2026-02-17 01:32:12 +00:00

Partially upgrade build/generators.py

[SVN r64539]
This commit is contained in:
Vladimir Prus
2010-08-02 14:15:50 +00:00
parent 680a1297e8
commit eb262a3d35
4 changed files with 150 additions and 21 deletions

View File

@@ -1,5 +1,5 @@
# Status: being ported by Vladimir Prus
# Base revision: 41557
# Base revision: 48649
# TODO: replace the logging with dout
# Copyright Vladimir Prus 2002.
@@ -59,6 +59,7 @@ from b2.util import set
from b2.util.sequence import unique
import b2.util.sequence as sequence
from b2.manager import get_manager
import b2.build.type
def reset ():
""" Clear the module state. This is mainly for testing purposes.
@@ -66,6 +67,7 @@ def reset ():
global __generators, __type_to_generators, __generators_for_toolset, __construct_stack
global __overrides, __active_generators
global __viable_generators_cache, __viable_source_types_cache
global __vstg_cached_generators, __vst_cached_types
__generators = {}
__type_to_generators = {}
@@ -78,6 +80,9 @@ def reset ():
__viable_source_types_cache = {}
__active_generators = []
__vstg_cached_generators = []
__vst_cached_types = []
reset ()
_re_separate_types_prefix_and_postfix = re.compile ('([^\\(]*)(\\((.*)%(.*)\\))?')
@@ -101,6 +106,54 @@ def decrease_indent():
global __indent
__indent = __indent[0:-4]
# Updated cached viable source target type information as needed after a new
# derived target type gets added. This is needed because if a target type is a
# viable source target type for some generator then all of the target type's
# derived target types are automatically viable as source target types for the
# same generator. Does nothing if a non-derived target type is passed to it.
#
def update_cached_information_with_a_new_type(type):
base_type = b2.build.type.base(type)
if base_type:
for g in __vstg_cached_generators:
if base_type in __viable_source_types_cache.get(g, []):
__viable_source_types_cache[g].append(type)
for t in __vst_cached_types:
if base_type in __viable_source_types_cache.get(t, []):
__viable_source_types_cache[t].append(type)
# Clears cached viable source target type information except for target types
# and generators with all source types listed as viable. Should be called when
# something invalidates those cached values by possibly causing some new source
# types to become viable.
#
def invalidate_extendable_viable_source_target_type_cache():
global __vstg_cached_generators
generators_with_cached_source_types = __vstg_cached_generators
__vstg_cached_generators = []
for g in generators_with_cached_source_types:
if __viable_source_types_cache.has_key(g):
if __viable_source_types_cache[g] == ["*"]:
__vstg_cached_generators.append(g)
else:
del __viable_source_types_cache[g]
global __vst_cached_types
types_with_cached_sources_types = __vst_cached_types
__vst_cached_types = []
for t in types_with_cached_sources_types:
if __viable_source_types_cache.has_key(t):
if __viable_source_types_cache[t] == ["*"]:
__vst_cached_types.append(t)
else:
del __viable_source_types_cache[t]
def dout(message):
if debug():
print __indent + message
@@ -589,6 +642,24 @@ def register (g):
__generators_for_toolset.setdefault(base, []).append(g)
# After adding a new generator that can construct new target types, we need
# to clear the related cached viable source target type information for
# constructing a specific target type or using a specific generator. Cached
# viable source target type lists affected by this are those containing any
# of the target types constructed by the new generator or any of their base
# target types.
#
# A more advanced alternative to clearing that cached viable source target
# type information would be to expand it with additional source types or
# even better - mark it as needing to be expanded on next use.
#
# For now we just clear all the cached viable source target type information
# that does not simply state 'all types' and may implement a more detailed
# algorithm later on if it becomes needed.
invalidate_extendable_viable_source_target_type_cache()
def register_standard (id, source_types, target_types, requirements = []):
""" Creates new instance of the 'generator' class and registers it.
Returns the creates instance.
@@ -632,11 +703,19 @@ def __viable_source_types_real (target_type):
of calling itself recusrively on source types.
"""
generators = []
t = type.all_bases (target_type)
# 't0' is the initial list of target types we need to process to get a list
# of their viable source target types. New target types will not be added to
# this list.
t0 = type.all_bases (target_type)
# 't' is the list of target types which have not yet been processed to get a
# list of their viable source target types. This list will get expanded as
# we locate more target types to process.
t = t0
result = []
# 't' is the list of types which are not yet processed
while t:
# Find all generators for current type.
# Unlike 'find_viable_generators' we don't care about prop_set.
@@ -658,19 +737,29 @@ def __viable_source_types_real (target_type):
all = type.all_derived (source_type)
for n in all:
if not n in result:
t.append (n)
# Here there is no point in adding target types to
# the list of types to process in case they are or
# have already been on that list. We optimize this
# check by realizing that we only need to avoid the
# original target type's base types. Other target
# types that are or have been on the list of target
# types to process have been added to the 'result'
# list as well and have thus already been eliminated
# by the previous if.
if not n in t0:
t.append (n)
result.append (n)
result = unique (result)
return result
def viable_source_types (target_type):
""" Helper rule, caches the result of '__viable_source_types_real'.
"""
if not __viable_source_types_cache.has_key (target_type):
__viable_source_types_cache [target_type] = __viable_source_types_real (target_type)
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)
return __viable_source_types_cache [target_type]
def viable_source_types_for_generator_real (generator):
@@ -691,20 +780,22 @@ def viable_source_types_for_generator_real (generator):
else:
result = []
for s in source_types:
result += type.all_derived (s) + viable_source_types (s)
result = unique (result)
if "*" in result:
result = ["*"]
return result
viable_sources = viable_source_types(s)
if viable_sources == "*":
result = ["*"]
break
else:
result.extend(type.all_derived(s) + viable_sources)
return unique(result)
def viable_source_types_for_generator (generator):
""" Caches the result of 'viable_source_types_for_generator'.
"""
key = str (generator)
if not __viable_source_types_cache.has_key (key):
__viable_source_types_cache [key] = viable_source_types_for_generator_real (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)
return __viable_source_types_cache [key]
return __viable_source_types_cache[generator]
def try_one_generator_really (project, name, generator, target_type, properties, sources):
""" Returns usage requirements + list of created targets.
@@ -861,6 +952,8 @@ def find_viable_generators (target_type, prop_set):
key = target_type + '.' + str (prop_set)
l = __viable_generators_cache.get (key, None)
if not l:
l = []
if not l:
l = find_viable_generators_aux (target_type, prop_set)
@@ -899,6 +992,7 @@ def find_viable_generators (target_type, prop_set):
for g in viable_generators:
if not g.id () in overriden_ids:
result.append (g)
return result
@@ -909,7 +1003,7 @@ def __construct_really (project, name, target_type, prop_set, sources):
viable_generators = find_viable_generators (target_type, prop_set)
result = []
project.manager ().logger ().log (__name__, "*** %d viable generators" % len (viable_generators))
generators_that_succeeded = []

View File

@@ -16,6 +16,7 @@ from b2.exceptions import *
from b2.build import feature, property, scanner
from b2.util import bjam_signature
__re_hyphen = re.compile ('-')
def __register_features ():
@@ -98,6 +99,12 @@ def register (type, suffixes = [], base_type = None):
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
# make the generator selection module update any of its cached
# information related to a new derived type being defined.
generators.update_cached_information_with_a_new_type(type)
# FIXME: resolving recursive dependency.
from b2.manager import get_manager
get_manager().projects().project_rules().add_rule_for_type(type)
@@ -142,6 +149,12 @@ def get_scanner (type, prop_set):
return None
def base(type):
"""Returns a base type for the given type or nothing in case the given type is
not derived."""
return __types[type]['base']
def all_bases (type):
""" Returns type and all of its bases, in the order of their distance from type.
"""

View File

@@ -51,6 +51,28 @@ else
}
""")
t.write("Other/mygen.py", """
import b2.build.generators as generators
import b2.build.type as type
from b2.manager import get_manager
import os
type.register('MY_TYPE', ['extension'])
generators.register_standard('mygen.generate-a-cpp-file', ['MY_TYPE'], ['CPP'])
if os.name == 'nt':
action = 'echo void g() {} > "$(<)"'
else:
action = 'echo "void g() {}" > "$(<)"'
def f(*args):
print "Generating a CPP file..."
get_manager().engine().register_action("mygen.generate-a-cpp-file",
action, function=f)
""")
t.write("Other/jamfile.jam", """
import mygen ;
obj other-obj : source.extension ;

View File

@@ -30,7 +30,7 @@ class NullLogger:
return False
def on (self):
return False
return True
class TextLogger (NullLogger):
def __init__ (self):