2 # Copyright 2008, Google Inc.
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
9 # * Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
11 # * Redistributions in binary form must reproduce the above
12 # copyright notice, this list of conditions and the following disclaimer
13 # in the documentation and/or other materials provided with the
15 # * Neither the name of Google Inc. nor the names of its
16 # contributors may be used to endorse or promote products derived from
17 # this software without specific prior written permission.
19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 """Software construction toolkit target management for SCons."""
38 # Dict of target groups (TargetGroup indexed by group name)
41 # Dict of targets (Target indexed by target name)
44 # Dict of target modes (TargetMode indexed by mode name)
47 #------------------------------------------------------------------------------
50 class TargetGroup(object):
51 """Target group, as used by AddTargetGroup() and GetTargetGroups()."""
53 def __init__(self
, name
, description
):
54 """Initializes the target group.
57 name: Name of the target group.
58 description: Description of group.
61 self
.description
= description
63 def GetTargetNames(self
):
64 """Returns a list of target name strings for the group."""
65 items
= map(str, SCons
.Script
.Alias(self
.name
)[0].sources
)
66 # Remove duplicates from multiple environments
67 return list(set(items
))
69 #------------------------------------------------------------------------------
72 class TargetMode(object):
73 """Target mode, as used by GetTargetModes()."""
75 def __init__(self
, name
, description
):
76 """Initializes the target mode.
79 name: Name of the target mode.
80 description: Description of mode.
83 self
.description
= description
85 def GetTargetNames(self
):
86 """Returns a list of target name strings for the group."""
87 items
= map(str, SCons
.Script
.Alias(self
.name
)[0].sources
)
88 # Remove duplicates from multiple environments
89 return list(set(items
))
91 #------------------------------------------------------------------------------
97 def __init__(self
, name
):
98 """Initializes the target.
101 name: Name of the target.
104 self
.properties
= {} # Global properties
105 self
.mode_properties
= {} # Dict of modes to mode-specific properties
107 #------------------------------------------------------------------------------
110 def AddTargetGroup(name
, description
):
111 """Adds a target group, used for printing help.
114 name: Name of target group. This should be the name of an alias which
115 points to other aliases for the specific targets.
116 description: Description of the target group. Should read properly when
117 appended to 'The following ' - for example, 'programs can be built'.
120 # Warn if the target group already exists with a different description
121 if (name
in __target_groups
122 and __target_groups
[name
].description
!= description
):
123 print ('Warning: Changing description of target group "%s" from "%s" to '
124 '"%s"' % (name
, __target_groups
[name
].description
, description
))
125 __target_groups
[name
].description
= description
127 __target_groups
[name
] = TargetGroup(name
, description
)
130 def GetTargetGroups():
131 """Gets the dict of target groups.
134 The dict of target groups, indexed by group name.
136 This dict is not fully populated until after BuildEnvironments() has been
139 return __target_groups
142 def GetTargetModes():
143 """Gets the dict of target modes.
146 The dict of target modes, indexed by mode name.
148 This dict is not fully populated until after BuildEnvironments() has been
151 # TODO: Better to rename this to # GetTargetBuildEnvironments()?
152 # That's a more description name.
153 return __target_modes
157 """Gets the dict of targets.
160 The dict of targets, indexed by target name.
162 This dict is not fully populated until after BuildEnvironments() has been
168 def SetTargetProperty(self
, target_name
, all_modes
=False, **kwargs
):
169 """Sets one or more properties for a target.
172 self: Environment context.
173 target_name: Name of the target.
174 all_modes: If True, property applies to all modes. If false, it applies
175 only to the current mode (determined by self['BUILD_TYPE']).
176 kwargs: Keyword args are used to set properties. Properties will be
177 converted to strings via env.subst().
180 foo_test = env.Program(...)[0]
181 env.SetTargetProperty('foo_test', global=True, DESCRIPTION='Foo test')
182 env.SetTargetProperty('foo_test', EXE=foo_test)
185 if target_name
not in __targets
:
186 __targets
[target_name
] = Target(target_name
)
187 target
= __targets
[target_name
]
190 add_to_dict
= target
.properties
192 mode
= self
.get('BUILD_TYPE')
193 if mode
not in target
.mode_properties
:
194 target
.mode_properties
[mode
] = {}
195 add_to_dict
= target
.mode_properties
[mode
]
198 for k
, v
in kwargs
.items():
199 add_to_dict
[k
] = self
.subst(str(v
))
203 """Adds SCons help for the targets, groups, and modes.
205 This is called automatically by BuildEnvironments()."""
208 for group
in GetTargetGroups().values():
209 items
= group
.GetTargetNames()
212 help_text
+= '\nThe following %s:' % group
.description
213 colwidth
= max(map(len, items
)) + 2
216 cols
= 1 # If target names are really long, one per line
217 rows
= (len(items
) + cols
- 1) / cols
218 for row
in range(0, rows
):
220 for i
in range(row
, len(items
), rows
):
221 help_text
+= '%-*s' % (colwidth
, items
[i
])
222 help_text
+= '\n %s (do all of the above)\n' % group
.name
224 SCons
.Script
.Help(help_text
)
227 def SetTargetDescription(self
, target_name
, description
):
228 """Convenience function to set a target's global DESCRIPTION property.
231 self: Environment context.
232 target_name: Name of the target.
233 description: Description of the target.
235 self
.SetTargetProperty(target_name
, all_modes
=True, DESCRIPTION
=description
)
238 def AddTargetMode(env
):
239 """Adds the environment as a target mode.
242 env: Environment context.
244 Called via env.Defer() for each build mode.
246 # Save the build mode and description
247 mode
= env
.get('BUILD_TYPE')
248 __target_modes
[mode
] = TargetMode(mode
, env
.get('BUILD_TYPE_DESCRIPTION'))
251 #------------------------------------------------------------------------------
255 # NOTE: SCons requires the use of this name, which fails gpylint.
256 """SCons entry point for this tool."""
257 env
= env
# Silence gpylint
259 __builtin__
.AddTargetGroup
= AddTargetGroup
260 __builtin__
.AddTargetHelp
= AddTargetHelp
261 __builtin__
.GetTargetGroups
= GetTargetGroups
262 __builtin__
.GetTargetModes
= GetTargetModes
263 __builtin__
.GetTargets
= GetTargets
265 env
.AddMethod(SetTargetDescription
)
266 env
.AddMethod(SetTargetProperty
)
268 # Defer per-mode setup
269 env
.Defer(AddTargetMode
)