Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r64539 - in trunk/tools/build/v2: build test util
From: ghost_at_[hidden]
Date: 2010-08-02 10:15:52


Author: vladimir_prus
Date: 2010-08-02 10:15:50 EDT (Mon, 02 Aug 2010)
New Revision: 64539
URL: http://svn.boost.org/trac/boost/changeset/64539

Log:
Partially upgrade build/generators.py
Text files modified:
   trunk/tools/build/v2/build/generators.py | 134 ++++++++++++++++++++++++++++++++++-----
   trunk/tools/build/v2/build/type.py | 13 +++
   trunk/tools/build/v2/test/generator_selection.py | 22 ++++++
   trunk/tools/build/v2/util/logger.py | 2
   4 files changed, 150 insertions(+), 21 deletions(-)

Modified: trunk/tools/build/v2/build/generators.py
==============================================================================
--- trunk/tools/build/v2/build/generators.py (original)
+++ trunk/tools/build/v2/build/generators.py 2010-08-02 10:15:50 EDT (Mon, 02 Aug 2010)
@@ -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.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 @@
     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 @@
     __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 @@
     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 @@
 
     __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 @@
         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 @@
                     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 @@
     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 @@
     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 @@
     for g in viable_generators:
         if not g.id () in overriden_ids:
             result.append (g)
+
         
     return result
     
@@ -909,7 +1003,7 @@
     viable_generators = find_viable_generators (target_type, prop_set)
                     
     result = []
-
+
     project.manager ().logger ().log (__name__, "*** %d viable generators" % len (viable_generators))
 
     generators_that_succeeded = []

Modified: trunk/tools/build/v2/build/type.py
==============================================================================
--- trunk/tools/build/v2/build/type.py (original)
+++ trunk/tools/build/v2/build/type.py 2010-08-02 10:15:50 EDT (Mon, 02 Aug 2010)
@@ -16,6 +16,7 @@
 from b2.build import feature, property, scanner
 from b2.util import bjam_signature
 
+
 __re_hyphen = re.compile ('-')
 
 def __register_features ():
@@ -98,6 +99,12 @@
         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 @@
             
     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.
     """

Modified: trunk/tools/build/v2/test/generator_selection.py
==============================================================================
--- trunk/tools/build/v2/test/generator_selection.py (original)
+++ trunk/tools/build/v2/test/generator_selection.py 2010-08-02 10:15:50 EDT (Mon, 02 Aug 2010)
@@ -51,6 +51,28 @@
 }
 """)
 
+ 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 ;

Modified: trunk/tools/build/v2/util/logger.py
==============================================================================
--- trunk/tools/build/v2/util/logger.py (original)
+++ trunk/tools/build/v2/util/logger.py 2010-08-02 10:15:50 EDT (Mon, 02 Aug 2010)
@@ -30,7 +30,7 @@
         return False
 
     def on (self):
- return False
+ return True
 
 class TextLogger (NullLogger):
     def __init__ (self):


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk