Boost logo

Boost-Commit :

From: ghost_at_[hidden]
Date: 2008-05-18 00:46:23


Author: vladimir_prus
Date: 2008-05-18 00:46:23 EDT (Sun, 18 May 2008)
New Revision: 45475
URL: http://svn.boost.org/trac/boost/changeset/45475

Log:
WIP on toolset.py.

Text files modified:
   branches/build/python_port/python/boost/build/build/toolset.py | 301 ++++++++++++++++++++++-----------------
   1 files changed, 170 insertions(+), 131 deletions(-)

Modified: branches/build/python_port/python/boost/build/build/toolset.py
==============================================================================
--- branches/build/python_port/python/boost/build/build/toolset.py (original)
+++ branches/build/python_port/python/boost/build/build/toolset.py 2008-05-18 00:46:23 EDT (Sun, 18 May 2008)
@@ -1,4 +1,5 @@
 # Status: being ported by Vladimir Prus
+# Base revision: 40958
 #
 # Copyright 2003 Dave Abrahams
 # Copyright 2005 Rene Rivera
@@ -18,37 +19,49 @@
 __re_first_segment = re.compile ('([^.]*).*')
 __re_first_group = re.compile (r'[^.]*\.(.*)')
 
+# Flag is a mechanism to set a value
+# A single toolset flag. Specifies that when certain
+# properties are in build property set, certain values
+# should be appended to some variable.
+#
+# A flag applies to a specific action in specific module.
+# The list of all flags for a module is stored, and each
+# flag further contains the name of the rule it applies
+# for,
+class Flag:
+
+ def __init__(self, variable_name, values, condition, rule = None):
+ self.variable_name = variable_name
+ self.values = values
+ self.condition = condition
+ self.rule = rule
+
 def reset ():
     """ Clear the module state. This is mainly for testing purposes.
     """
- global __rules, __module_flags, __flags_to_modules, __stv, __flag_no
-
- # A global counter used to set variables in the maps.
- # TODO: I think the code can be made simpler and this made unnecessary.
- __flag_no = 1
-
- # A map indexed by the rule or module name. The content of each entry is:
- # entry = {
- # 'flags': [],
- # 'variable': {},
- # 'values': {},
- # 'condition': {}
- # }
- #
- # Porting note. In the bjam version, each of this corresponds to .$(rule-or-module).xxx
- __rules = {}
+ global __module_flags, __flags, __stv
     
- # Corresponds to .module-flags.xxx
+ # Mapping from module name to a list of all flags that apply
+ # to either that module directly, or to any rule in that module.
+ # Each element of the list is Flag instance.
+ # So, for module named xxx this might contain flags for 'xxx',
+ # for 'xxx.compile', for 'xxx.compile.c++', etc.
     __module_flags = {}
-
- # Corresponds to .rule-or-module.$(.flag-no)
- __flags_to_modules = {}
+
+ # Mapping from specific rule or module name to a list of Flag instances
+ # that apply to that name.
+ # Say, it might contain flags for 'xxx.compile.c++'. If there are
+ # entries for module name 'xxx', they are flags for 'xxx' itself,
+ # not including any rules in that module.
+ __flags = {}
     
     # A cache for varaible settings. The key is generated from the rule name and the properties.
     __stv = {}
     
 reset ()
 
+# FIXME: --ignore-toolset-requirements
+# FIXME: using
     
 def normalize_condition (property_sets):
     """ Expands subfeatures in each property set.
@@ -67,6 +80,10 @@
 
     return result
 
+# FIXME push-checking-for-flags-module ....
+# FIXME: investigate existing uses of 'hack-hack' parameter
+# in jam code.
+
 def flags (rule_or_module, variable_name, condition, values = []):
     """ Specifies the flags (variables) that must be set on targets under certain
         conditions, described by arguments.
@@ -81,7 +98,8 @@
                           module, an error is issued.
 
          variable_name: Variable that should be set on target
- condition: An optional condition when this flag should be applied.
+
+ condition A condition when this flag should be applied.
                           Should be set of property sets. If one of
                           those property sets is contained in build
                           properties, the flag will be used.
@@ -90,7 +108,16 @@
                           "gcc". Subfeatures, like in "<toolset>gcc-3.2"
                           are allowed. If left empty, the flag will
                           always used.
-
+
+ Propery sets may use value-less properties
+ ('<a>' vs. '<a>value') to match absent
+ properties. This allows to separately match
+
+ <architecture>/<address-model>64
+ <architecture>ia64/<address-model>
+
+ Where both features are optional. Without this
+ syntax we'd be forced to define "default" value.
 
          values: The value to add to variable. If <feature>
                           is specified, then the value of 'feature'
@@ -125,34 +152,62 @@
     if settings:
         for s in settings:
             for target in targets:
- manager.engine ().set_target_variable (target, s [0], s[1])
+ manager.engine ().set_target_variable (target, s [0], s[1], True)
 
 def find_property_subset (property_sets, properties):
- """ Returns the first element of 'property_sets' which is a subset of
- 'properties', or an empty list if no such element exists.
-
- TODO: does this one belong here or in feature?
- """
+ """Returns the first element of 'property-sets' which is a subset of
+ 'properties', or an empty list if no such element exists."""
+
+ prop_keys = get_grist(properties)
+
     for s in property_sets:
- features = feature.split (s)
- if set.contains (features, properties):
+ # Handle value-less properties like '<architecture>' (compare with
+ # '<architecture>x86').
+
+ set = feature.split(s)
+
+ # Find the set of features that
+ # - have no property specified in required property set
+ # - are omitted in build property set
+ default_props = []
+ for i in set:
+ # If $(i) is a value-less property it should match default
+ # value of an optional property. See the first line in the
+ # example below:
+ #
+ # property set properties result
+ # <a> <b>foo <b>foo match
+ # <a> <b>foo <a>foo <b>foo no match
+ # <a>foo <b>foo <b>foo no match
+ # <a>foo <b>foo <a>foo <b>foo match
+ if not (get_value(i) or get_grist(i) in prop_keys):
+ default_props.append(i)
+
+ # FIXME: can this be expressed in a more pythonic way?
+ has_all = 1
+ for i in set:
+ if i not in (properties + default_props):
+ has_all = 0
+ break
+ if has_all:
             return s
 
     return None
+
 
 def register (toolset):
     """ Registers a new toolset.
     """
- feature.extend_feature ('toolset', [toolset])
+ feature.extend('toolset', [toolset])
 
 def inherit_generators (toolset, properties, base, generators_to_ignore = []):
     if not properties:
         properties = [replace_grist (toolset, '<toolset>')]
         
- base_generators = generators.generators_for_toolset (base)
+ base_generators = generators.generators_for_toolset(base)
     
     for g in base_generators:
- id = g.id ()
+ id = g.id()
         
         if not id in generators_to_ignore:
             # Some generator names have multiple periods in their name, so
@@ -161,38 +216,39 @@
             # which is not what we want. Manually parse the base and suffix
             # (if there's a better way to do this, I'd love to see it.)
             # See also register in module generators.
- (base, suffix) = split_action_id (id)
+ (base, suffix) = split_action_id(id)
 
             new_id = toolset + '.' + suffix
 
- generators.register (g.clone (new_id, properties))
+ generators.register(g.clone(new_id, properties))
 
-def inherit_flags (toolset, base, prohibited_properties = []):
- """ Inherits the properties set for another toolset.
- Properties listed in prohibited_properties won't
- be inherited. Note that <debug-symbols>on and
- <debug-symbols>off are two different properties
- """
- for f in __module_flags.get (base, []):
- rule_or_module = __flags_to_modules [f]
-
- entry = __rules [rule_or_module][f]
+def inherit_flags(toolset, base, prohibited_properties = []):
+ """Brings all flag definitions from the 'base' toolset into the 'toolset'
+ toolset. Flag definitions whose conditions make use of properties in
+ 'prohibited-properties' are ignored. Don't confuse property and feature, for
+ example <debug-symbols>on and <debug-symbols>off, so blocking one of them does
+ not block the other one.
+
+ The flag conditions are not altered at all, so if a condition includes a name,
+ 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."""
+ for f in __module_flags.get(base, []):
         
- if not entry ['condition'] or set.difference (entry ['condition'], prohibited_properties):
- match = __re_first_group.match (rule_or_module)
+ if not f.condition or set.difference(f.condition, prohibited_properties):
+ match = __re_first_group.match(f.rule)
             rule_ = None
             if match:
- rule_ = match.group (1)
+ rule_ = match.group(1)
 
             new_rule_or_module = ''
 
             if rule_:
                 new_rule_or_module = toolset + '.' + rule_
-
             else:
                 new_rule_or_module = toolset
 
- __add_flag (new_rule_or_module, entry ['variable'], entry ['condition'], entry ['values'])
+ __add_flag (new_rule_or_module, f.variable_name, f.condition, f.values)
 
 def inherit_rules (toolset, base):
     base_generators = generators.generators_for_toolset (base)
@@ -205,14 +261,18 @@
         ids.append (id) ;
 
     new_actions = []
- for name, value in action.enumerate ():
- (old_toolset, id) = split_action_id (name)
-
- if old_toolset == base:
- new_actions.append ((id, value [0], value [1]))
 
- for a in new_actions:
- action.register (toolset + '.' + a [0], a [1], a [2])
+ engine = get_manager().engine()
+ # FIXME: do this!
+ for action in engine.action.values():
+ pass
+# (old_toolset, id) = split_action_id(action.action_name)
+#
+# if old_toolset == base:
+# new_actions.append ((id, value [0], value [1]))
+#
+# for a in new_actions:
+# action.register (toolset + '.' + a [0], a [1], a [2])
         
     # TODO: how to deal with this?
 # IMPORT $(base) : $(rules) : $(toolset) : $(rules) : localized ;
@@ -231,29 +291,24 @@
     """
     result = []
 
- key = rule_or_module
- if __rules.has_key (key):
- for f in __rules [key]['flags']:
- entry = __rules [key][f]
- variable = entry ['variable']
- condition = entry ['condition']
- values = entry ['values']
-
- if not condition or find_property_subset (condition, properties):
- processed = []
- for v in values:
- # The value might be <feature-name> so needs special
- # treatment.
- processed += __handle_flag_value (manager, v, properties)
+ for f in __flags.get(rule_or_module, []):
+
+ if not f.condition or find_property_subset (f.condition, properties):
+ processed = []
+ for v in f.values:
+ # The value might be <feature-name> so needs special
+ # treatment.
+ processed += __handle_flag_value (manager, v, properties)
 
- for r in processed:
- result.append ((variable, r))
+ for r in processed:
+ result.append ((f.variable_name, r))
     
     # strip away last dot separated part and recurse.
- next = __re_split_last_segment.match (key)
+ next = __re_split_last_segment.match(rule_or_module)
     
     if next:
- result.extend (__set_target_variables_aux (manager, next.group (1), properties))
+ result.extend(__set_target_variables_aux(
+ manager, next.group(1), properties))
 
     return result
 
@@ -270,7 +325,7 @@
             if 'dependency' in att:
                 # the value of a dependency feature is a target
                 # and must be actualized
-
+ # FIXME: verify that 'find' actually works, ick!
                 result.append (manager.targets ().find (ungristed).actualize ())
 
             elif 'path' in att or 'free' in att:
@@ -284,13 +339,9 @@
                     values.append (ungristed)
 
                 else:
- values += value.split ('&&')
+ values.extend(value.split ('&&'))
 
- if 'path' in att:
- result += [ Path.native (v) for v in values ]
-
- else:
- result += values
+ result.extend(values)
             else:
                 result.append (ungristed)
     else:
@@ -302,56 +353,44 @@
     """ Adds a new flag setting with the specified values.
         Does no checking.
     """
- if __rules.has_key (rule_or_module):
- current = __rules [rule_or_module]
- else:
- current = {
- 'flags': []
- }
-
- entry = {
- 'variable': variable_name,
- 'values': values,
- 'condition': condition
- }
-
- global __flag_no
- current ['flags'].append (__flag_no)
- current [__flag_no] = entry
-
- __rules [rule_or_module] = current
+ f = Flag(variable_name, values, condition, rule_or_module)
     
- # Store all flags for a module
+ # Grab the name of the module
     m = __re_first_segment.match (rule_or_module)
- if m:
- module_ = m.group (1)
- if not __module_flags.has_key (module_): __module_flags [module_] = []
- __module_flags [module_].append (__flag_no)
-
- # Store flag-no -> rule_or_module mapping
- __flags_to_modules [__flag_no] = rule_or_module
+ assert m
+ module = m.group(1)
 
- __flag_no += 1
+ __module_flags.setdefault(m, []).append(f)
+ __flags.setdefault(rule_or_module, []).append(f)
 
-
-###################################################################
-# Still to port.
-# Original lines are prefixed with "# "
-#
-# # Make toolset 'toolset', defined in a module of the same name,
-# # inherit from 'base'
-# # 1. The 'init' rule from 'base' is imported into 'toolset' with full
-# # name. Another 'init' is called, which forwards to the base one.
-# # 2. All generators from 'base' are cloned. The ids are adjusted and
-# # <toolset> property in requires is adjusted too
-# # 3. All flags are inherited
-# # 4. All rules are imported.
-# rule inherit ( toolset : base )
-# {
-# import $(base) ;
-#
-# inherit_generators $(toolset) : $(base) ;
-# inherit-flags $(toolset) : $(base) ;
-# inherit-rules $(toolset) : $(base) ;
-# }
-#
+def requirements():
+ """Return the list of global 'toolset requirements'.
+ Those requirements will be automatically added to the requirements of any main target."""
+ return __requirements
+
+def add_requirements(requirements):
+ """Adds elements to the list of global 'toolset requirements'. The requirements
+ will be automatically added to the requirements for all main targets, as if
+ they were specified literally. For best results, all requirements added should
+ be conditional or indirect conditional."""
+
+ # FIXME:
+ #if ! $(.ignore-requirements)
+ #{
+ __requirements.extend(requirements)
+ #}
+
+# Make toolset 'toolset', defined in a module of the same name,
+# inherit from 'base'
+# 1. The 'init' rule from 'base' is imported into 'toolset' with full
+# name. Another 'init' is called, which forwards to the base one.
+# 2. All generators from 'base' are cloned. The ids are adjusted and
+# <toolset> property in requires is adjusted too
+# 3. All flags are inherited
+# 4. All rules are imported.
+def inherit(toolset, base):
+ get_manager().projects().load_module(base, []);
+
+ inherit_generators(toolset, base)
+ inherit_flags(toolset, base)
+ inherit_rules(toolset, base)


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