3 Base class for construction Environments. These are
4 the primary objects used to communicate dependency and
5 construction information to the build engine.
7 Keyword arguments supplied when the construction Environment
8 is created are construction variables used to initialize the
15 # Permission is hereby granted, free of charge, to any person obtaining
16 # a copy of this software and associated documentation files (the
17 # "Software"), to deal in the Software without restriction, including
18 # without limitation the rights to use, copy, modify, merge, publish,
19 # distribute, sublicense, and/or sell copies of the Software, and to
20 # permit persons to whom the Software is furnished to do so, subject to
21 # the following conditions:
23 # The above copyright notice and this permission notice shall be included
24 # in all copies or substantial portions of the Software.
26 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
27 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
28 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
44 from UserDict import UserDict
48 from SCons.Debug import logInstanceCreation
52 import SCons.Node.Alias
54 import SCons.Node.Python
58 import SCons.Sig.TimeStamp
71 # Pull UserError into the global name space for the benefit of
72 # Environment().SourceSignatures(), which has some import statements
73 # which seem to mess up its ability to reference SCons directly.
74 UserError = SCons.Errors.UserError
76 def installFunc(target, source, env):
77 """Install a source file into a target using the function specified
78 as the INSTALL construction variable."""
80 install = env['INSTALL']
82 raise SCons.Errors.UserError('Missing INSTALL construction variable.')
83 return install(target[0].path, source[0].path, env)
85 def installString(target, source, env):
86 return 'Install file: "%s" as "%s"' % (source[0], target[0])
88 installAction = SCons.Action.Action(installFunc, installString)
90 InstallBuilder = SCons.Builder.Builder(action=installAction)
92 def alias_builder(env, target, source):
95 AliasBuilder = SCons.Builder.Builder(action = alias_builder,
96 target_factory = SCons.Node.Alias.default_ans.Alias,
97 source_factory = SCons.Node.FS.default_fs.Entry,
101 """deepcopy lists and dictionaries, and just copy the reference
102 for everything else."""
103 if SCons.Util.is_Dict(x):
106 copy[key] = our_deepcopy(x[key])
107 elif SCons.Util.is_List(x):
108 copy = map(our_deepcopy, x)
110 copy = x.__class__(copy)
111 except AttributeError:
117 def apply_tools(env, tools, toolpath):
120 if SCons.Util.is_String(tool):
121 env.Tool(tool, toolpath)
125 class BuilderWrapper:
126 """Wrapper class that associates an environment with a Builder at
128 def __init__(self, env, builder):
130 self.builder = builder
132 def __call__(self, *args, **kw):
133 return apply(self.builder, (self.env,) + args, kw)
135 # This allows a Builder to be executed directly
136 # through the Environment to which it's attached.
137 # In practice, we shouldn't need this, because
138 # builders actually get executed through a Node.
139 # But we do have a unit test for this, and can't
140 # yet rule out that it would be useful in the
141 # future, so leave it for now.
142 def execute(self, **kw):
144 apply(self.builder.execute, (), kw)
146 class BuilderDict(UserDict):
147 """This is a dictionary-like class used by an Environment to hold
148 the Builders. We need to do this because every time someone changes
149 the Builders in the Environment's BUILDERS dictionary, we must
150 update the Environment's attributes."""
151 def __init__(self, dict, env):
152 # Set self.env before calling the superclass initialization,
153 # because it will end up calling our other methods, which will
154 # need to point the values in this dictionary to self.env.
156 UserDict.__init__(self, dict)
158 def __setitem__(self, item, val):
159 UserDict.__setitem__(self, item, val)
161 self.setenvattr(item, val)
162 except AttributeError:
163 # Have to catch this because sometimes __setitem__ gets
164 # called out of __init__, when we don't have an env
165 # attribute yet, nor do we want one!
168 def setenvattr(self, item, val):
169 """Set the corresponding environment attribute for this Builder.
171 If the value is already a BuilderWrapper, we pull the builder
172 out of it and make another one, so that making a copy of an
173 existing BuilderDict is guaranteed separate wrappers for each
174 Builder + Environment pair."""
176 builder = val.builder
177 except AttributeError:
179 setattr(self.env, item, BuilderWrapper(self.env, builder))
181 def __delitem__(self, item):
182 UserDict.__delitem__(self, item)
183 delattr(self.env, item)
185 def update(self, dict):
186 for i, v in dict.items():
187 self.__setitem__(i, v)
190 """Base class for construction Environments. These are
191 the primary objects used to communicate dependency and
192 construction information to the build engine.
194 Keyword arguments supplied when the construction Environment
195 is created are construction variables used to initialize the
199 #######################################################################
200 # This is THE class for interacting with the SCons build engine,
201 # and it contains a lot of stuff, so we're going to try to keep this
202 # a little organized by grouping the methods.
203 #######################################################################
205 #######################################################################
206 # Methods that make an Environment act like a dictionary. These have
207 # the expected standard names for Python mapping objects. Note that
208 # we don't actually make an Environment a subclass of UserDict for
209 # performance reasons. Note also that we only supply methods for
210 # dictionary functionality that we actually need and use.
211 #######################################################################
219 if __debug__: logInstanceCreation(self)
220 self.fs = SCons.Node.FS.default_fs
221 self.ans = SCons.Node.Alias.default_ans
222 self.lookup_list = SCons.Node.arg2nodes_lookups
223 self._dict = our_deepcopy(SCons.Defaults.ConstructionEnvironment)
225 self._dict['__env__'] = self
226 self._dict['BUILDERS'] = BuilderDict(self._dict['BUILDERS'], self)
229 platform = self._dict.get('PLATFORM', None)
231 platform = SCons.Platform.Platform()
232 if SCons.Util.is_String(platform):
233 platform = SCons.Platform.Platform(platform)
234 self._dict['PLATFORM'] = str(platform)
237 # Apply the passed-in variables before calling the tools,
238 # because they may use some of them:
239 apply(self.Replace, (), kw)
241 # Update the environment with the customizable options
242 # before calling the tools, since they may use some of the options:
247 tools = self._dict.get('TOOLS', None)
250 apply_tools(self, tools, toolpath)
252 # Reapply the passed in variables after calling the tools,
253 # since they should overide anything set by the tools:
254 apply(self.Replace, (), kw)
256 # Update the environment with the customizable options
257 # after calling the tools, since they should override anything
262 def __cmp__(self, other):
263 # Since an Environment now has an '__env__' construction variable
264 # that refers to itself, delete that variable to avoid infinite
265 # loops when comparing the underlying dictionaries in some Python
266 # versions (*cough* 1.5.2 *cough*)...
267 sdict = self._dict.copy()
269 odict = other._dict.copy()
271 return cmp(sdict, odict)
273 def __getitem__(self, key):
274 return self._dict[key]
276 def __setitem__(self, key, value):
277 if key in ['TARGET', 'TARGETS', 'SOURCE', 'SOURCES']:
278 SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning,
279 "Ignoring attempt to set reserved variable `%s'" % key)
280 elif key == 'BUILDERS':
286 self._dict[key] = BuilderDict(kwbd, self)
287 self._dict[key].update(value)
289 if not SCons.Util.is_valid_construction_var(key):
290 raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key
291 self._dict[key] = value
293 def __delitem__(self, key):
297 "Emulates the items() method of dictionaries."""
298 return self._dict.items()
300 def has_key(self, key):
301 return self._dict.has_key(key)
303 def get(self, key, default=None):
304 "Emulates the get() method of dictionaries."""
305 return self._dict.get(key, default)
307 #######################################################################
308 # Utility methods that are primarily for internal use by SCons.
309 # These begin with lower-case letters. Note that the subst() method
310 # is actually already out of the closet and used by people.
311 #######################################################################
313 def arg2nodes(self, args, node_factory=_null, lookup_list=_null):
314 if node_factory is _null:
315 node_factory = self.fs.File
316 if lookup_list is _null:
317 lookup_list = self.lookup_list
322 if not SCons.Util.is_List(args):
327 if SCons.Util.is_String(v):
329 for l in lookup_list:
334 if SCons.Util.is_String(n):
335 n = self.subst(n, raw=1)
340 v = self.subst(v, raw=1)
341 nodes.append(node_factory(v))
347 def get_calculator(self):
349 return self._calculator
350 except AttributeError:
352 module = self._calc_module
353 c = apply(SCons.Sig.Calculator, (module,), CalculatorArgs)
354 except AttributeError:
355 # Note that we're calling get_calculator() here, so the
356 # DefaultEnvironment() must have a _calc_module attribute
357 # to avoid infinite recursion.
358 c = SCons.Defaults.DefaultEnvironment().get_calculator()
362 def get_builder(self, name):
363 """Fetch the builder with the specified name from the environment.
366 return self._dict['BUILDERS'][name]
370 def get_scanner(self, skey):
371 """Find the appropriate scanner given a key (usually a file suffix).
372 Does a linear search. Could be sped up by creating a dictionary if
373 this proves too slow.
375 if self._dict['SCANNERS']:
376 for scanner in self._dict['SCANNERS']:
377 if skey in scanner.skeys:
381 def subst(self, string, raw=0, target=None, source=None, dict=None, conv=None):
382 """Recursively interpolates construction variables from the
383 Environment into the specified string, returning the expanded
384 result. Construction variables are specified by a $ prefix
385 in the string and begin with an initial underscore or
386 alphabetic character followed by any number of underscores
387 or alphanumeric characters. The construction variable names
388 may be surrounded by curly braces to separate the name from
391 return SCons.Util.scons_subst(string, self, raw, target, source, dict, conv)
393 def subst_kw(self, kw, raw=0, target=None, source=None, dict=None):
395 for k, v in kw.items():
396 k = self.subst(k, raw, target, source, dict)
397 if SCons.Util.is_String(v):
398 v = self.subst(v, raw, target, source, dict)
402 def subst_list(self, string, raw=0, target=None, source=None, dict=None, conv=None):
403 """Calls through to SCons.Util.scons_subst_list(). See
404 the documentation for that function."""
405 return SCons.Util.scons_subst_list(string, self, raw, target, source, dict, conv)
408 def subst_path(self, path):
409 """Substitute a path list, turning EntryProxies into Nodes
410 and leaving Nodes (and other objects) as-is."""
412 if not SCons.Util.is_List(path):
416 """This is the "string conversion" routine that we have our
417 substitutions use to return Nodes, not strings. This relies
418 on the fact that an EntryProxy object has a get() method that
419 returns the underlying Node that it wraps, which is a bit of
420 architectural dependence that we might need to break or modify
421 in the future in response to additional requirements."""
424 except AttributeError:
432 if SCons.Util.is_String(p):
433 p = self.subst(p, conv=s)
434 if SCons.Util.is_List(p):
441 def _update(self, dict):
442 """Update an environment's values directly, bypassing the normal
443 checks that occur when users try to set items.
445 self._dict.update(dict)
447 def use_build_signature(self):
449 return self._build_signature
450 except AttributeError:
451 b = SCons.Defaults.DefaultEnvironment()._build_signature
452 self._build_signature = b
455 #######################################################################
456 # Public methods for manipulating an Environment. These begin with
457 # upper-case letters. The essential characteristic of methods in
458 # this section is that they do *not* have corresponding same-named
459 # global functions. For example, a stand-alone Append() function
460 # makes no sense, because Append() is all about appending values to
461 # an Environment's construction variables.
462 #######################################################################
464 def Append(self, **kw):
465 """Append values to existing construction variables
468 kw = our_deepcopy(kw)
469 for key, val in kw.items():
470 # It would be easier on the eyes to write this using
471 # "continue" statements whenever we finish processing an item,
472 # but Python 1.5.2 apparently doesn't let you use "continue"
473 # within try:-except: blocks, so we have to nest our code.
475 orig = self._dict[key]
477 # No existing variable in the environment, so just set
478 # it to the new value.
479 self._dict[key] = val
482 # Most straightforward: just try to add them
483 # together. This will work in most cases, when the
484 # original and new values are of compatible types.
485 self._dict[key] = orig + val
488 # Try to update a dictionary value with another.
489 # If orig isn't a dictionary, it won't have an
490 # update() method; if val isn't a dictionary,
491 # it won't have a keys() method. Either way,
492 # it's an AttributeError.
494 except AttributeError:
496 # Check if the original is a list.
497 add_to_orig = orig.append
498 except AttributeError:
499 # The original isn't a list, but the new
500 # value is (by process of elimination),
501 # so insert the original in the new value
502 # (if there's one to insert) and replace
503 # the variable with it.
506 self._dict[key] = val
508 # The original is a list, so append the new
509 # value to it (if there's a value to append).
513 def AppendENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep):
514 """Append path elements to the path 'name' in the 'ENV'
515 dictionary for this environment. Will only add any particular
516 path once, and will normpath and normcase all paths to help
517 assure this. This can also handle the case where the env
518 variable is a list instead of a string.
522 if self._dict.has_key(envname) and self._dict[envname].has_key(name):
523 orig = self._dict[envname][name]
525 nv = SCons.Util.AppendPath(orig, newpath, sep)
527 if not self._dict.has_key(envname):
528 self._dict[envname] = {}
530 self._dict[envname][name] = nv
532 def AppendUnique(self, **kw):
533 """Append values to existing construction variables
534 in an Environment, if they're not already there.
536 kw = our_deepcopy(kw)
537 for key, val in kw.items():
538 if not self._dict.has_key(key):
539 self._dict[key] = val
540 elif SCons.Util.is_Dict(self._dict[key]) and \
541 SCons.Util.is_Dict(val):
542 self._dict[key].update(val)
543 elif SCons.Util.is_List(val):
545 if not SCons.Util.is_List(dk):
547 val = filter(lambda x, dk=dk: x not in dk, val)
548 self._dict[key] = dk + val
551 if SCons.Util.is_List(dk):
553 self._dict[key] = dk + val
555 self._dict[key] = self._dict[key] + val
557 def Copy(self, tools=None, toolpath=[], **kw):
558 """Return a copy of a construction Environment. The
559 copy is like a Python "deep copy"--that is, independent
560 copies are made recursively of each objects--except that
561 a reference is copied when an object is not deep-copyable
562 (like a function). There are no references to any mutable
563 objects in the original Environment.
565 clone = copy.copy(self)
566 clone._dict = our_deepcopy(self._dict)
567 clone['__env__'] = clone
569 cbd = clone._dict['BUILDERS']
570 clone._dict['BUILDERS'] = BuilderDict(cbd, clone)
574 apply_tools(clone, tools, toolpath)
576 # Apply passed-in variables after the new tools.
578 for key, value in kw.items():
579 new[key] = SCons.Util.scons_subst_once(value, self, key)
580 apply(clone.Replace, (), new)
583 def Detect(self, progs):
584 """Return the first available program in progs.
586 if not SCons.Util.is_List(progs):
589 path = self.WhereIs(prog)
593 def Dictionary(self, *args):
596 dlist = map(lambda x, s=self: s._dict[x], args)
601 def FindIxes(self, paths, prefix, suffix):
603 Search a list of paths for something that matches the prefix and suffix.
605 paths - the list of paths or nodes.
606 prefix - construction variable for the prefix.
607 suffix - construction variable for the suffix.
610 suffix = self.subst('$'+suffix)
611 prefix = self.subst('$'+prefix)
614 dir,name = os.path.split(str(path))
615 if name[:len(prefix)] == prefix and name[-len(suffix):] == suffix:
618 def Override(self, overrides):
620 Produce a modified environment whose variables
621 are overriden by the overrides dictionaries.
623 overrides - a dictionary that will override
624 the variables of this environment.
626 This function is much more efficient than Copy()
627 or creating a new Environment because it doesn't do
628 a deep copy of the dictionary, and doesn't do a copy
629 at all if there are no overrides.
633 env = copy.copy(self)
634 env._dict = copy.copy(self._dict)
637 for key, value in overrides.items():
638 new[key] = SCons.Util.scons_subst_once(value, self, key)
639 env._dict.update(new)
644 def ParseConfig(self, command, function=None):
646 Use the specified function to parse the output of the command
647 in order to modify the current environment. The 'command'
648 can be a string or a list of strings representing a command and
649 it's arguments. 'Function' is an optional argument that takes
650 the environment and the output of the command. If no function is
651 specified, the output will be treated as the output of a typical
652 'X-config' command (i.e. gtk-config) and used to set the CPPPATH,
653 LIBPATH, LIBS, and CCFLAGS variables.
656 # the default parse function
657 def parse_conf(env, output):
666 params = string.split(output)
672 dict['LIBPATH'].append(arg[2:])
674 dict['LIBS'].append(arg[2:])
676 dict['CPPPATH'].append(arg[2:])
678 dict['CCFLAGS'].append(arg)
680 static_libs.append(arg)
681 apply(env.Append, (), dict)
685 function = parse_conf
686 if type(command) is type([]):
687 command = string.join(command)
688 command = self.subst(command)
689 return function(self, os.popen(command).read())
691 def Platform(self, platform):
692 platform = self.subst(platform)
693 return SCons.Platform.Platform(platform)(self)
695 def Prepend(self, **kw):
696 """Prepend values to existing construction variables
699 kw = our_deepcopy(kw)
700 for key, val in kw.items():
701 # It would be easier on the eyes to write this using
702 # "continue" statements whenever we finish processing an item,
703 # but Python 1.5.2 apparently doesn't let you use "continue"
704 # within try:-except: blocks, so we have to nest our code.
706 orig = self._dict[key]
708 # No existing variable in the environment, so just set
709 # it to the new value.
710 self._dict[key] = val
713 # Most straightforward: just try to add them
714 # together. This will work in most cases, when the
715 # original and new values are of compatible types.
716 self._dict[key] = val + orig
719 # Try to update a dictionary value with another.
720 # If orig isn't a dictionary, it won't have an
721 # update() method; if val isn't a dictionary,
722 # it won't have a keys() method. Either way,
723 # it's an AttributeError.
725 except AttributeError:
727 # Check if the added value is a list.
728 add_to_val = val.append
729 except AttributeError:
730 # The added value isn't a list, but the
731 # original is (by process of elimination),
732 # so insert the the new value in the original
733 # (if there's one to insert).
737 # The added value is a list, so append
738 # the original to it (if there's a value
742 self._dict[key] = val
744 def PrependENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep):
745 """Prepend path elements to the path 'name' in the 'ENV'
746 dictionary for this environment. Will only add any particular
747 path once, and will normpath and normcase all paths to help
748 assure this. This can also handle the case where the env
749 variable is a list instead of a string.
753 if self._dict.has_key(envname) and self._dict[envname].has_key(name):
754 orig = self._dict[envname][name]
756 nv = SCons.Util.PrependPath(orig, newpath, sep)
758 if not self._dict.has_key(envname):
759 self._dict[envname] = {}
761 self._dict[envname][name] = nv
763 def PrependUnique(self, **kw):
764 """Append values to existing construction variables
765 in an Environment, if they're not already there.
767 kw = our_deepcopy(kw)
768 for key, val in kw.items():
769 if not self._dict.has_key(key):
770 self._dict[key] = val
771 elif SCons.Util.is_Dict(self._dict[key]) and \
772 SCons.Util.is_Dict(val):
773 self._dict[key].update(val)
774 elif SCons.Util.is_List(val):
776 if not SCons.Util.is_List(dk):
778 val = filter(lambda x, dk=dk: x not in dk, val)
779 self._dict[key] = val + dk
782 if SCons.Util.is_List(dk):
784 self._dict[key] = val + dk
786 self._dict[key] = val + dk
788 def Replace(self, **kw):
789 """Replace existing construction variables in an Environment
790 with new construction variables and/or values.
793 kwbd = our_deepcopy(kw['BUILDERS'])
795 self.__setitem__('BUILDERS', kwbd)
798 self._dict.update(our_deepcopy(kw))
800 def ReplaceIxes(self, path, old_prefix, old_suffix, new_prefix, new_suffix):
802 Replace old_prefix with new_prefix and old_suffix with new_suffix.
804 env - Environment used to interpolate variables.
805 path - the path that will be modified.
806 old_prefix - construction variable for the old prefix.
807 old_suffix - construction variable for the old suffix.
808 new_prefix - construction variable for the new prefix.
809 new_suffix - construction variable for the new suffix.
811 old_prefix = self.subst('$'+old_prefix)
812 old_suffix = self.subst('$'+old_suffix)
814 new_prefix = self.subst('$'+new_prefix)
815 new_suffix = self.subst('$'+new_suffix)
817 dir,name = os.path.split(str(path))
818 if name[:len(old_prefix)] == old_prefix:
819 name = name[len(old_prefix):]
820 if name[-len(old_suffix):] == old_suffix:
821 name = name[:-len(old_suffix)]
822 return os.path.join(dir, new_prefix+name+new_suffix)
824 def Tool(self, tool, toolpath=[]):
825 tool = self.subst(tool)
826 return SCons.Tool.Tool(tool, map(self.subst, toolpath))(self)
828 def WhereIs(self, prog, path=None, pathext=None):
829 """Find prog in the path.
833 path = self['ENV']['PATH']
836 elif SCons.Util.is_String(path):
837 path = self.subst(path)
840 pathext = self['ENV']['PATHEXT']
843 elif SCons.Util.is_String(pathext):
844 pathext = self.subst(pathext)
845 path = SCons.Util.WhereIs(prog, path, pathext)
849 #######################################################################
850 # Public methods for doing real "SCons stuff" (manipulating
851 # dependencies, setting attributes on targets, etc.). These begin
852 # with upper-case letters. The essential characteristic of methods
853 # in this section is that they all *should* have corresponding
854 # same-named global functions.
855 #######################################################################
857 def Action(self, *args, **kw):
858 nargs = self.subst(args)
859 nkw = self.subst_kw(kw)
860 return apply(SCons.Action.Action, nargs, nkw)
862 def AddPreAction(self, files, action):
863 nodes = self.arg2nodes(files, self.fs.Entry)
864 action = SCons.Action.Action(action)
866 n.add_pre_action(action)
869 def AddPostAction(self, files, action):
870 nodes = self.arg2nodes(files, self.fs.Entry)
871 action = SCons.Action.Action(action)
873 n.add_post_action(action)
876 def Alias(self, target, *source, **kw):
877 if not SCons.Util.is_List(target):
881 if not isinstance(t, SCons.Node.Alias.Alias):
882 t = self.arg2nodes(self.subst(t), self.ans.Alias)[0]
892 if not SCons.Util.is_List(s):
895 s = self.arg2nodes(s, self.fs.Entry)
897 AliasBuilder(self, t, s)
902 def AlwaysBuild(self, *targets):
905 tlist.extend(self.arg2nodes(t, self.fs.File))
914 def BuildDir(self, build_dir, src_dir, duplicate=1):
915 build_dir = self.arg2nodes(build_dir, self.fs.Dir)[0]
916 src_dir = self.arg2nodes(src_dir, self.fs.Dir)[0]
917 self.fs.BuildDir(build_dir, src_dir, duplicate)
919 def Builder(self, **kw):
920 nkw = self.subst_kw(kw)
921 return apply(SCons.Builder.Builder, [], nkw)
923 def CacheDir(self, path):
924 self.fs.CacheDir(self.subst(path))
926 def Clean(self, target, files):
929 if not isinstance(target, SCons.Node.Node):
930 target = self.subst(target)
931 target = self.fs.Entry(target, create=1)
933 if not SCons.Util.is_List(files):
938 if isinstance(f, SCons.Node.Node):
941 nodes.extend(self.arg2nodes(f, self.fs.Entry))
944 CleanTargets[target].extend(nodes)
946 CleanTargets[target] = nodes
948 def Configure(self, *args, **kw):
951 nargs = nargs + self.subst_list(args)[0]
952 nkw = self.subst_kw(kw)
954 nkw['custom_tests'] = self.subst_kw(nkw['custom_tests'])
957 return apply(SCons.SConf.SConf, nargs, nkw)
959 def Command(self, target, source, action, **kw):
960 """Builds the supplied target files from the supplied
961 source files using the supplied action. Action may
962 be any type that the Builder constructor will accept
964 nkw = self.subst_kw(kw)
965 nkw['action'] = action
966 nkw['source_factory'] = self.fs.Entry
967 bld = apply(SCons.Builder.Builder, (), nkw)
968 return bld(self, target, source)
970 def Depends(self, target, dependency):
971 """Explicity specify that 'target's depend on 'dependency'."""
972 tlist = self.arg2nodes(target, self.fs.Entry)
973 dlist = self.arg2nodes(dependency, self.fs.Entry)
975 t.add_dependency(dlist)
981 def Dir(self, name, *args, **kw):
984 return apply(self.fs.Dir, (self.subst(name),) + args, kw)
986 def Environment(self, **kw):
987 return apply(SCons.Environment.Environment, [], self.subst_kw(kw))
989 def Execute(self, action, *args, **kw):
990 """Directly execute an action through an Environment
992 action = apply(self.Action, (action,) + args, kw)
993 return action([], [], self)
995 def File(self, name, *args, **kw):
998 return apply(self.fs.File, (self.subst(name),) + args, kw)
1000 def FindFile(self, file, dirs):
1001 file = self.subst(file)
1002 nodes = self.arg2nodes(dirs, self.fs.Dir)
1003 return SCons.Node.FS.find_file(file, nodes, self.fs.File)
1005 def GetBuildPath(self, files):
1006 ret = map(str, self.arg2nodes(files, self.fs.Entry))
1011 def Ignore(self, target, dependency):
1012 """Ignore a dependency."""
1013 tlist = self.arg2nodes(target, self.fs.Entry)
1014 dlist = self.arg2nodes(dependency, self.fs.Entry)
1022 def Install(self, dir, source):
1023 """Install specified files in the given directory."""
1025 dnodes = self.arg2nodes(dir, self.fs.Dir)
1027 raise SCons.Errors.UserError, "Target `%s' of Install() is a file, but should be a directory. Perhaps you have the Install() arguments backwards?" % str(dir)
1029 sources = self.arg2nodes(source, self.fs.File)
1031 if SCons.Util.is_List(source):
1032 raise SCons.Errors.UserError, "Source `%s' of Install() contains one or more non-files. Install() source must be one or more files." % repr(map(str, source))
1034 raise SCons.Errors.UserError, "Source `%s' of Install() is not a file. Install() source must be one or more files." % str(source)
1036 for dnode in dnodes:
1038 target = self.fs.File(src.name, dnode)
1039 tgt.append(InstallBuilder(self, target, src))
1044 def InstallAs(self, target, source):
1045 """Install sources as targets."""
1046 sources = self.arg2nodes(source, self.fs.File)
1047 targets = self.arg2nodes(target, self.fs.File)
1049 for src, tgt in map(lambda x, y: (x, y), sources, targets):
1050 ret.append(InstallBuilder(self, tgt, src))
1055 def Literal(self, string):
1056 return SCons.Util.Literal(string)
1058 def Local(self, *targets):
1060 for targ in targets:
1061 if isinstance(targ, SCons.Node.Node):
1065 for t in self.arg2nodes(targ, self.fs.Entry):
1070 def Precious(self, *targets):
1073 tlist.extend(self.arg2nodes(t, self.fs.Entry))
1082 def Repository(self, *dirs, **kw):
1083 dirs = self.arg2nodes(list(dirs), self.fs.Dir)
1084 apply(self.fs.Repository, dirs, kw)
1086 def Scanner(self, *args, **kw):
1089 if SCons.Util.is_String(arg):
1090 arg = self.subst(arg)
1092 nkw = self.subst_kw(kw)
1093 return apply(SCons.Scanner.Base, nargs, nkw)
1095 def SConsignFile(self, name=".sconsign.dbm", dbm_module=None):
1096 name = self.subst(name)
1097 if not os.path.isabs(name):
1098 name = os.path.join(str(self.fs.SConstruct_dir), name)
1099 SCons.Sig.SConsignFile(name, dbm_module)
1101 def SideEffect(self, side_effect, target):
1102 """Tell scons that side_effects are built as side
1103 effects of building targets."""
1104 side_effects = self.arg2nodes(side_effect, self.fs.Entry)
1105 targets = self.arg2nodes(target, self.fs.Entry)
1107 for side_effect in side_effects:
1108 # A builder of 1 means the node is supposed to appear
1109 # buildable without actually having a builder, so we allow
1110 # it to be a side effect as well.
1111 if side_effect.has_builder() and side_effect.builder != 1:
1112 raise SCons.Errors.UserError, "Multiple ways to build the same target were specified for: %s" % str(side_effect)
1113 side_effect.add_source(targets)
1114 side_effect.side_effect = 1
1115 self.Precious(side_effect)
1116 for target in targets:
1117 target.side_effects.append(side_effect)
1118 if len(side_effects) == 1:
1119 return side_effects[0]
1123 def SourceCode(self, entry, builder):
1124 """Arrange for a source code builder for (part of) a tree."""
1125 entries = self.arg2nodes(entry, self.fs.Entry)
1126 for entry in entries:
1127 entry.set_src_builder(builder)
1128 if len(entries) == 1:
1132 def SourceSignatures(self, type):
1133 type = self.subst(type)
1135 import SCons.Sig.MD5
1136 self._calc_module = SCons.Sig.MD5
1137 elif type == 'timestamp':
1138 import SCons.Sig.TimeStamp
1139 self._calc_module = SCons.Sig.TimeStamp
1141 raise UserError, "Unknown source signature type '%s'"%type
1143 def Split(self, arg):
1144 """This function converts a string or list into a list of strings
1145 or Nodes. This makes things easier for users by allowing files to
1146 be specified as a white-space separated list to be split.
1147 The input rules are:
1148 - A single string containing names separated by spaces. These will be
1149 split apart at the spaces.
1150 - A single Node instance
1151 - A list containing either strings or Node instances. Any strings
1152 in the list are not split at spaces.
1153 In all cases, the function returns a list of Nodes and strings."""
1154 if SCons.Util.is_List(arg):
1155 return map(self.subst, arg)
1156 elif SCons.Util.is_String(arg):
1157 return string.split(self.subst(arg))
1159 return [self.subst(arg)]
1161 def TargetSignatures(self, type):
1162 type = self.subst(type)
1164 self._build_signature = 1
1165 elif type == 'content':
1166 self._build_signature = 0
1168 raise SCons.Errors.UserError, "Unknown target signature type '%s'"%type
1170 def Value(self, value):
1173 return SCons.Node.Python.Value(value)
1175 # The entry point that will be used by the external world
1176 # to refer to a construction environment. This allows the wrapper
1177 # interface to extend a construction environment for its own purposes
1178 # by subclassing SCons.Environment.Base and then assigning the
1179 # class to SCons.Environment.Environment.