Package SCons :: Module Builder
[hide private]
[frames] | no frames]

Source Code for Module SCons.Builder

  1  """SCons.Builder 
  2   
  3  Builder object subsystem. 
  4   
  5  A Builder object is a callable that encapsulates information about how 
  6  to execute actions to create a target Node (file) from source Nodes 
  7  (files), and how to create those dependencies for tracking. 
  8   
  9  The main entry point here is the Builder() factory method.  This provides 
 10  a procedural interface that creates the right underlying Builder object 
 11  based on the keyword arguments supplied and the types of the arguments. 
 12   
 13  The goal is for this external interface to be simple enough that the 
 14  vast majority of users can create new Builders as necessary to support 
 15  building new types of files in their configurations, without having to 
 16  dive any deeper into this subsystem. 
 17   
 18  The base class here is BuilderBase.  This is a concrete base class which 
 19  does, in fact, represent the Builder objects that we (or users) create. 
 20   
 21  There is also a proxy that looks like a Builder: 
 22   
 23      CompositeBuilder 
 24   
 25          This proxies for a Builder with an action that is actually a 
 26          dictionary that knows how to map file suffixes to a specific 
 27          action.  This is so that we can invoke different actions 
 28          (compilers, compile options) for different flavors of source 
 29          files. 
 30   
 31  Builders and their proxies have the following public interface methods 
 32  used by other modules: 
 33   
 34      __call__() 
 35          THE public interface.  Calling a Builder object (with the 
 36          use of internal helper methods) sets up the target and source 
 37          dependencies, appropriate mapping to a specific action, and the 
 38          environment manipulation necessary for overridden construction 
 39          variable.  This also takes care of warning about possible mistakes 
 40          in keyword arguments. 
 41   
 42      add_emitter() 
 43          Adds an emitter for a specific file suffix, used by some Tool 
 44          modules to specify that (for example) a yacc invocation on a .y 
 45          can create a .h *and* a .c file. 
 46   
 47      add_action() 
 48          Adds an action for a specific file suffix, heavily used by 
 49          Tool modules to add their specific action(s) for turning 
 50          a source file into an object file to the global static 
 51          and shared object file Builders. 
 52   
 53  There are the following methods for internal use within this module: 
 54   
 55      _execute() 
 56          The internal method that handles the heavily lifting when a 
 57          Builder is called.  This is used so that the __call__() methods 
 58          can set up warning about possible mistakes in keyword-argument 
 59          overrides, and *then* execute all of the steps necessary so that 
 60          the warnings only occur once. 
 61   
 62      get_name() 
 63          Returns the Builder's name within a specific Environment, 
 64          primarily used to try to return helpful information in error 
 65          messages. 
 66   
 67      adjust_suffix() 
 68      get_prefix() 
 69      get_suffix() 
 70      get_src_suffix() 
 71      set_src_suffix() 
 72          Miscellaneous stuff for handling the prefix and suffix 
 73          manipulation we use in turning source file names into target 
 74          file names. 
 75   
 76  """ 
 77   
 78  # 
 79  # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation 
 80  # 
 81  # Permission is hereby granted, free of charge, to any person obtaining 
 82  # a copy of this software and associated documentation files (the 
 83  # "Software"), to deal in the Software without restriction, including 
 84  # without limitation the rights to use, copy, modify, merge, publish, 
 85  # distribute, sublicense, and/or sell copies of the Software, and to 
 86  # permit persons to whom the Software is furnished to do so, subject to 
 87  # the following conditions: 
 88  # 
 89  # The above copyright notice and this permission notice shall be included 
 90  # in all copies or substantial portions of the Software. 
 91  # 
 92  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 
 93  # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
 94  # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 95  # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
 96  # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
 97  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
 98  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
 99  # 
100   
101  __revision__ = "src/engine/SCons/Builder.py 2928 2008/04/29 22:44:09 knight" 
102   
103  import SCons.compat 
104   
105  import UserDict 
106  import UserList 
107   
108  import SCons.Action 
109  from SCons.Debug import logInstanceCreation 
110  from SCons.Errors import InternalError, UserError 
111  import SCons.Executor 
112  import SCons.Memoize 
113  import SCons.Node 
114  import SCons.Node.FS 
115  import SCons.Util 
116  import SCons.Warnings 
117   
118 -class _Null:
119 pass
120 121 _null = _Null 122
123 -class DictCmdGenerator(SCons.Util.Selector):
124 """This is a callable class that can be used as a 125 command generator function. It holds on to a dictionary 126 mapping file suffixes to Actions. It uses that dictionary 127 to return the proper action based on the file suffix of 128 the source file.""" 129
130 - def __init__(self, dict=None, source_ext_match=1):
131 SCons.Util.Selector.__init__(self, dict) 132 self.source_ext_match = source_ext_match
133
134 - def src_suffixes(self):
135 return self.keys()
136
137 - def add_action(self, suffix, action):
138 """Add a suffix-action pair to the mapping. 139 """ 140 self[suffix] = action
141
142 - def __call__(self, target, source, env, for_signature):
143 if not source: 144 return [] 145 146 if self.source_ext_match: 147 ext = None 148 for src in map(str, source): 149 my_ext = SCons.Util.splitext(src)[1] 150 if ext and my_ext != ext: 151 raise UserError("While building `%s' from `%s': Cannot build multiple sources with different extensions: %s, %s" % (repr(map(str, target)), src, ext, my_ext)) 152 ext = my_ext 153 else: 154 ext = SCons.Util.splitext(str(source[0]))[1] 155 156 if not ext: 157 raise UserError("While building `%s': Cannot deduce file extension from source files: %s" % (repr(map(str, target)), repr(map(str, source)))) 158 159 try: 160 ret = SCons.Util.Selector.__call__(self, env, source) 161 except KeyError, e: 162 raise UserError("Ambiguous suffixes after environment substitution: %s == %s == %s" % (e[0], e[1], e[2])) 163 if ret is None: 164 raise UserError("While building `%s' from `%s': Don't know how to build from a source file with suffix `%s'. Expected a suffix in this list: %s." % \ 165 (repr(map(str, target)), repr(map(str, source)), ext, repr(self.keys()))) 166 return ret
167
168 -class CallableSelector(SCons.Util.Selector):
169 """A callable dictionary that will, in turn, call the value it 170 finds if it can."""
171 - def __call__(self, env, source):
172 value = SCons.Util.Selector.__call__(self, env, source) 173 if callable(value): 174 value = value(env, source) 175 return value
176
177 -class DictEmitter(SCons.Util.Selector):
178 """A callable dictionary that maps file suffixes to emitters. 179 When called, it finds the right emitter in its dictionary for the 180 suffix of the first source file, and calls that emitter to get the 181 right lists of targets and sources to return. If there's no emitter 182 for the suffix in its dictionary, the original target and source are 183 returned. 184 """
185 - def __call__(self, target, source, env):
186 emitter = SCons.Util.Selector.__call__(self, env, source) 187 if emitter: 188 target, source = emitter(target, source, env) 189 return (target, source)
190
191 -class ListEmitter(UserList.UserList):
192 """A callable list of emitters that calls each in sequence, 193 returning the result. 194 """
195 - def __call__(self, target, source, env):
196 for e in self.data: 197 target, source = e(target, source, env) 198 return (target, source)
199 200 # These are a common errors when calling a Builder; 201 # they are similar to the 'target' and 'source' keyword args to builders, 202 # so we issue warnings when we see them. The warnings can, of course, 203 # be disabled. 204 misleading_keywords = { 205 'targets' : 'target', 206 'sources' : 'source', 207 } 208
209 -class OverrideWarner(UserDict.UserDict):
210 """A class for warning about keyword arguments that we use as 211 overrides in a Builder call. 212 213 This class exists to handle the fact that a single Builder call 214 can actually invoke multiple builders. This class only emits the 215 warnings once, no matter how many Builders are invoked. 216 """
217 - def __init__(self, dict):
218 UserDict.UserDict.__init__(self, dict) 219 if __debug__: logInstanceCreation(self, 'Builder.OverrideWarner') 220 self.already_warned = None
221 - def warn(self):
222 if self.already_warned: 223 return 224 for k in self.keys(): 225 if misleading_keywords.has_key(k): 226 alt = misleading_keywords[k] 227 msg = "Did you mean to use `%s' instead of `%s'?" % (alt, k) 228 SCons.Warnings.warn(SCons.Warnings.MisleadingKeywordsWarning, msg) 229 self.already_warned = 1
230
231 -def Builder(**kw):
232 """A factory for builder objects.""" 233 composite = None 234 if kw.has_key('generator'): 235 if kw.has_key('action'): 236 raise UserError, "You must not specify both an action and a generator." 237 kw['action'] = SCons.Action.CommandGeneratorAction(kw['generator']) 238 del kw['generator'] 239 elif kw.has_key('action'): 240 source_ext_match = kw.get('source_ext_match', 1) 241 if kw.has_key('source_ext_match'): 242 del kw['source_ext_match'] 243 if SCons.Util.is_Dict(kw['action']): 244 composite = DictCmdGenerator(kw['action'], source_ext_match) 245 kw['action'] = SCons.Action.CommandGeneratorAction(composite) 246 kw['src_suffix'] = composite.src_suffixes() 247 else: 248 kw['action'] = SCons.Action.Action(kw['action']) 249 250 if kw.has_key('emitter'): 251 emitter = kw['emitter'] 252 if SCons.Util.is_String(emitter): 253 # This allows users to pass in an Environment 254 # variable reference (like "$FOO") as an emitter. 255 # We will look in that Environment variable for 256 # a callable to use as the actual emitter. 257 var = SCons.Util.get_environment_var(emitter) 258 if not var: 259 raise UserError, "Supplied emitter '%s' does not appear to refer to an Environment variable" % emitter 260 kw['emitter'] = EmitterProxy(var) 261 elif SCons.Util.is_Dict(emitter): 262 kw['emitter'] = DictEmitter(emitter) 263 elif SCons.Util.is_List(emitter): 264 kw['emitter'] = ListEmitter(emitter) 265 266 result = apply(BuilderBase, (), kw) 267 268 if not composite is None: 269 result = CompositeBuilder(result, composite) 270 271 return result
272
273 -def _node_errors(builder, env, tlist, slist):
274 """Validate that the lists of target and source nodes are 275 legal for this builder and environment. Raise errors or 276 issue warnings as appropriate. 277 """ 278 279 # First, figure out if there are any errors in the way the targets 280 # were specified. 281 for t in tlist: 282 if t.side_effect: 283 raise UserError, "Multiple ways to build the same target were specified for: %s" % t 284 if t.has_explicit_builder(): 285 if not t.env is None and not t.env is env: 286 action = t.builder.action 287 t_contents = action.get_contents(tlist, slist, t.env) 288 contents = action.get_contents(tlist, slist, env) 289 290 if t_contents == contents: 291 msg = "Two different environments were specified for target %s,\n\tbut they appear to have the same action: %s" % (t, action.genstring(tlist, slist, t.env)) 292 SCons.Warnings.warn(SCons.Warnin