| #!/usr/bin/python2.4 |
| # Copyright 2009, Google Inc. |
| # All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions are |
| # met: |
| # |
| # * Redistributions of source code must retain the above copyright |
| # notice, this list of conditions and the following disclaimer. |
| # * Redistributions in binary form must reproduce the above |
| # copyright notice, this list of conditions and the following disclaimer |
| # in the documentation and/or other materials provided with the |
| # distribution. |
| # * Neither the name of Google Inc. nor the names of its |
| # contributors may be used to endorse or promote products derived from |
| # this software without specific prior written permission. |
| # |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| """Software construction toolkit target management for SCons.""" |
| |
| |
| import __builtin__ |
| import SCons.Script |
| |
| |
| # Dict of target groups (TargetGroup indexed by group name) |
| __target_groups = {} |
| |
| # Dict of targets (Target indexed by target name) |
| __targets = {} |
| |
| # Dict of target modes (TargetMode indexed by mode name) |
| __target_modes = {} |
| |
| #------------------------------------------------------------------------------ |
| |
| |
| class TargetGroup(object): |
| """Target group, as used by AddTargetGroup() and GetTargetGroups().""" |
| |
| def __init__(self, name, description): |
| """Initializes the target group. |
| |
| Args: |
| name: Name of the target group. |
| description: Description of group. |
| """ |
| self.name = name |
| self.description = description |
| |
| def GetTargetNames(self): |
| """Returns a list of target name strings for the group.""" |
| items = map(str, SCons.Script.Alias(self.name)[0].sources) |
| # Remove duplicates from multiple environments |
| return list(set(items)) |
| |
| #------------------------------------------------------------------------------ |
| |
| |
| class TargetMode(object): |
| """Target mode, as used by GetTargetModes().""" |
| |
| def __init__(self, name, description): |
| """Initializes the target mode. |
| |
| Args: |
| name: Name of the target mode. |
| description: Description of mode. |
| """ |
| self.name = name |
| self.description = description |
| |
| def GetTargetNames(self): |
| """Returns a list of target name strings for the group.""" |
| items = map(str, SCons.Script.Alias(self.name)[0].sources) |
| # Remove duplicates from multiple environments |
| return list(set(items)) |
| |
| #------------------------------------------------------------------------------ |
| |
| |
| class Target(object): |
| """Target object.""" |
| |
| def __init__(self, name): |
| """Initializes the target. |
| |
| Args: |
| name: Name of the target. |
| """ |
| self.name = name |
| self.properties = {} # Global properties |
| self.mode_properties = {} # Dict of modes to mode-specific properties |
| |
| #------------------------------------------------------------------------------ |
| |
| |
| def AddTargetGroup(name, description): |
| """Adds a target group, used for printing help. |
| |
| Args: |
| name: Name of target group. This should be the name of an alias which |
| points to other aliases for the specific targets. |
| description: Description of the target group. Should read properly when |
| appended to 'The following ' - for example, 'programs can be built'. |
| """ |
| |
| # Warn if the target group already exists with a different description |
| if (name in __target_groups |
| and __target_groups[name].description != description): |
| print ('Warning: Changing description of target group "%s" from "%s" to ' |
| '"%s"' % (name, __target_groups[name].description, description)) |
| __target_groups[name].description = description |
| else: |
| __target_groups[name] = TargetGroup(name, description) |
| |
| |
| def GetTargetGroups(): |
| """Gets the dict of target groups. |
| |
| Returns: |
| The dict of target groups, indexed by group name. |
| |
| This dict is not fully populated until after BuildEnvironments() has been |
| called. |
| """ |
| return __target_groups |
| |
| |
| def GetTargetModes(): |
| """Gets the dict of target modes. |
| |
| Returns: |
| The dict of target modes, indexed by mode name. |
| |
| This dict is not fully populated until after BuildEnvironments() has been |
| called. |
| """ |
| # TODO: Better to rename this to # GetTargetBuildEnvironments()? That's a |
| # more description name. |
| return __target_modes |
| |
| |
| def GetTargets(): |
| """Gets the dict of targets. |
| |
| Returns: |
| The dict of targets, indexed by target name. |
| |
| This dict is not fully populated until after BuildEnvironments() has been |
| called. |
| """ |
| return __targets |
| |
| |
| def SetTargetProperty(self, target_name, all_modes=False, **kwargs): |
| """Sets one or more properties for a target. |
| |
| Args: |
| self: Environment context. |
| target_name: Name of the target. |
| all_modes: If True, property applies to all modes. If false, it applies |
| only to the current mode (determined by self['BUILD_TYPE']). |
| kwargs: Keyword args are used to set properties. Properties will be |
| converted to strings via env.subst(). |
| |
| For example: |
| foo_test = env.Program(...)[0] |
| env.SetTargetProperty('foo_test', global=True, DESCRIPTION='Foo test') |
| env.SetTargetProperty('foo_test', EXE=foo_test) |
| """ |
| # Get the target |
| if target_name not in __targets: |
| __targets[target_name] = Target(target_name) |
| target = __targets[target_name] |
| |
| if all_modes: |
| add_to_dict = target.properties |
| else: |
| mode = self.get('BUILD_TYPE') |
| if mode not in target.mode_properties: |
| target.mode_properties[mode] = {} |
| add_to_dict = target.mode_properties[mode] |
| |
| # Add values |
| for k, v in kwargs.items(): |
| add_to_dict[k] = self.subst(str(v)) |
| |
| |
| def AddTargetHelp(): |
| """Adds SCons help for the targets, groups, and modes. |
| |
| This is called automatically by BuildEnvironments().""" |
| help_text = '' |
| |
| for group in GetTargetGroups().values(): |
| items = group.GetTargetNames() |
| items.sort() |
| if items: |
| help_text += '\nThe following %s:' % group.description |
| colwidth = max(map(len, items)) + 2 |
| cols = 77 / colwidth |
| if cols < 1: |
| cols = 1 # If target names are really long, one per line |
| rows = (len(items) + cols - 1) / cols |
| for row in range(0, rows): |
| help_text += '\n ' |
| for i in range(row, len(items), rows): |
| help_text += '%-*s' % (colwidth, items[i]) |
| help_text += '\n %s (do all of the above)\n' % group.name |
| |
| SCons.Script.Help(help_text) |
| |
| |
| def SetTargetDescription(self, target_name, description): |
| """Convenience function to set a target's global DESCRIPTION property. |
| |
| Args: |
| self: Environment context. |
| target_name: Name of the target. |
| description: Description of the target. |
| """ |
| self.SetTargetProperty(target_name, all_modes=True, DESCRIPTION=description) |
| |
| |
| def AddTargetMode(env): |
| """Adds the environment as a target mode. |
| |
| Args: |
| env: Environment context. |
| |
| Called via env.Defer() for each build mode. |
| """ |
| # Save the build mode and description |
| mode = env.get('BUILD_TYPE') |
| __target_modes[mode] = TargetMode(mode, env.get('BUILD_TYPE_DESCRIPTION')) |
| |
| |
| #------------------------------------------------------------------------------ |
| |
| |
| def generate(env): |
| # NOTE: SCons requires the use of this name, which fails gpylint. |
| """SCons entry point for this tool.""" |
| env = env # Silence gpylint |
| |
| __builtin__.AddTargetGroup = AddTargetGroup |
| __builtin__.AddTargetHelp = AddTargetHelp |
| __builtin__.GetTargetGroups = GetTargetGroups |
| __builtin__.GetTargetModes = GetTargetModes |
| __builtin__.GetTargets = GetTargets |
| |
| env.AddMethod(SetTargetDescription) |
| env.AddMethod(SetTargetProperty) |
| |
| # Defer per-mode setup |
| env.Defer(AddTargetMode) |