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
51 import SCons.Node.Alias
53 import SCons.Node.Python
57 import SCons.Sig.TimeStamp
70 # Pull UserError into the global name space for the benefit of
71 # Environment().SourceSignatures(), which has some import statements
72 # which seem to mess up its ability to reference SCons directly.
73 UserError = SCons.Errors.UserError
75 def installFunc(target, source, env):
76 """Install a source file into a target using the function specified
77 as the INSTALL construction variable."""
79 install = env['INSTALL']
81 raise SCons.Errors.UserError('Missing INSTALL construction variable.')
82 return install(target[0].path, source[0].path, env)
84 def installString(target, source, env):
85 return 'Install file: "%s" as "%s"' % (source[0], target[0])
87 installAction = SCons.Action.Action(installFunc, installString)
89 InstallBuilder = SCons.Builder.Builder(action=installAction)
91 def alias_builder(env, target, source):
94 AliasBuilder = SCons.Builder.Builder(action = alias_builder,
95 target_factory = SCons.Node.Alias.default_ans.Alias,
96 source_factory = SCons.Node.FS.default_fs.Entry,
100 """deepcopy lists and dictionaries, and just copy the reference
101 for everything else."""
102 if SCons.Util.is_Dict(x):
105 copy[key] = our_deepcopy(x[key])
106 elif SCons.Util.is_List(x):
107 copy = map(our_deepcopy, x)
112 def apply_tools(env, tools, toolpath):
115 if SCons.Util.is_String(tool):
116 env.Tool(tool, toolpath)
120 class BuilderWrapper:
121 """Wrapper class that associates an environment with a Builder at
123 def __init__(self, env, builder):
125 self.builder = builder
127 def __call__(self, *args, **kw):
128 return apply(self.builder, (self.env,) + args, kw)
130 # This allows a Builder to be executed directly
131 # through the Environment to which it's attached.
132 # In practice, we shouldn't need this, because
133 # builders actually get executed through a Node.
134 # But we do have a unit test for this, and can't
135 # yet rule out that it would be useful in the
136 # future, so leave it for now.
137 def execute(self, **kw):
139 apply(self.builder.execute, (), kw)
141 class BuilderDict(UserDict):
142 """This is a dictionary-like class used by an Environment to hold
143 the Builders. We need to do this because every time someone changes
144 the Builders in the Environment's BUILDERS dictionary, we must
145 update the Environment's attributes."""
146 def __init__(self, dict, env):
147 # Set self.env before calling the superclass initialization,
148 # because it will end up calling our other methods, which will
149 # need to point the values in this dictionary to self.env.
151 UserDict.__init__(self, dict)
153 def __setitem__(self, item, val):
154 UserDict.__setitem__(self, item, val)
156 self.setenvattr(item, val)
157 except AttributeError:
158 # Have to catch this because sometimes __setitem__ gets
159 # called out of __init__, when we don't have an env
160 # attribute yet, nor do we want one!
163 def setenvattr(self, item, val):
164 """Set the corresponding environment attribute for this Builder.
166 If the value is already a BuilderWrapper, we pull the builder
167 out of it and make another one, so that making a copy of an
168 existing BuilderDict is guaranteed separate wrappers for each
169 Builder + Environment pair."""
171 builder = val.builder
172 except AttributeError:
174 setattr(self.env, item, BuilderWrapper(self.env, builder))
176 def __delitem__(self, item):
177 UserDict.__delitem__(self, item)
178 delattr(self.env, item)
180 def update(self, dict):
181 for i, v in dict.items():
182 self.__setitem__(i, v)
185 """Base class for construction Environments. These are
186 the primary objects used to communicate dependency and
187 construction information to the build engine.
189 Keyword arguments supplied when the construction Environment
190 is created are construction variables used to initialize the
194 #######################################################################
195 # This is THE class for interacting with the SCons build engine,
196 # and it contains a lot of stuff, so we're going to try to keep this
197 # a little organized by grouping the methods.
198 #######################################################################
200 #######################################################################
201 # Methods that make an Environment act like a dictionary. These have
202 # the expected standard names for Python mapping objects. Note that
203 # we don't actually make an Environment a subclass of UserDict for
204 # performance reasons. Note also that we only supply methods for
205 # dictionary functionality that we actually need and use.
206 #######################################################################
214 self.fs = SCons.Node.FS.default_fs
215 self.ans = SCons.Node.Alias.default_ans
216 self.lookup_list = SCons.Node.arg2nodes_lookups
217 self._dict = our_deepcopy(SCons.Defaults.ConstructionEnvironment)
219 self._dict['BUILDERS'] = BuilderDict(self._dict['BUILDERS'], self)
222 platform = self._dict.get('PLATFORM', None)
224 platform = SCons.Platform.Platform()
225 if SCons.Util.is_String(platform):
226 platform = SCons.Platform.Platform(platform)
227 self._dict['PLATFORM'] = str(platform)
230 # Apply the passed-in variables before calling the tools,
231 # because they may use some of them:
232 apply(self.Replace, (), kw)
234 # Update the environment with the customizable options
235 # before calling the tools, since they may use some of the options:
240 tools = self._dict.get('TOOLS', None)
243 apply_tools(self, tools, toolpath)
245 # Reapply the passed in variables after calling the tools,
246 # since they should overide anything set by the tools:
247 apply(self.Replace, (), kw)
249 # Update the environment with the customizable options
250 # after calling the tools, since they should override anything
255 def __cmp__(self, other):
256 return cmp(self._dict, other._dict)
258 def __getitem__(self, key):
259 return self._dict[key]
261 def __setitem__(self, key, value):
262 if key in ['TARGET', 'TARGETS', 'SOURCE', 'SOURCES']:
263 SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning,
264 "Ignoring attempt to set reserved variable `%s'" % key)
265 elif key == 'BUILDERS':
271 self._dict[key] = BuilderDict(kwbd, self)
272 self._dict[key].update(value)
274 if not SCons.Util.is_valid_construction_var(key):
275 raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key
276 self._dict[key] = value
278 def __delitem__(self, key):
282 "Emulates the items() method of dictionaries."""
283 return self._dict.items()
285 def has_key(self, key):
286 return self._dict.has_key(key)
288 def get(self, key, default=None):
289 "Emulates the get() method of dictionaries."""
290 return self._dict.get(key, default)
292 #######################################################################
293 # Utility methods that are primarily for internal use by SCons.
294 # These begin with lower-case letters. Note that the subst() method
295 # is actually already out of the closet and used by people.
296 #######################################################################
298 def arg2nodes(self, args, node_factory=_null, lookup_list=_null):
299 if node_factory is _null:
300 node_factory = self.fs.File
301 if lookup_list is _null:
302 lookup_list = self.lookup_list
307 if not SCons.Util.is_List(args):
312 if SCons.Util.is_String(v):
314 for l in lookup_list:
319 if SCons.Util.is_String(n):
320 n = self.subst(n, raw=1)
325 v = self.subst(v, raw=1)
326 nodes.append(node_factory(v))
332 def get_calculator(self):
334 return self._calculator
335 except AttributeError:
337 module = self._calc_module
338 c = apply(SCons.Sig.Calculator, (module,), CalculatorArgs)
339 except AttributeError:
340 # Note that we're calling get_calculator() here, so the
341 # DefaultEnvironment() must have a _calc_module attribute
342 # to avoid infinite recursion.
343 c = SCons.Defaults.DefaultEnvironment().get_calculator()
347 def get_builder(self, name):
348 """Fetch the builder with the specified name from the environment.
351 return self._dict['BUILDERS'][name]
355 def get_scanner(self, skey):
356 """Find the appropriate scanner given a key (usually a file suffix).
357 Does a linear search. Could be sped up by creating a dictionary if
358 this proves too slow.
360 if self._dict['SCANNERS']:
361 for scanner in self._dict['SCANNERS']:
362 if skey in scanner.skeys:
366 def subst(self, string, raw=0, target=None, source=None):
367 """Recursively interpolates construction variables from the
368 Environment into the specified string, returning the expanded
369 result. Construction variables are specified by a $ prefix
370 in the string and begin with an initial underscore or
371 alphabetic character followed by any number of underscores
372 or alphanumeric characters. The construction variable names
373 may be surrounded by curly braces to separate the name from
377 mode = SCons.Util.SUBST_RAW
379 mode = SCons.Util.SUBST_CMD
380 return SCons.Util.scons_subst(string, self, mode, target, source)
382 def subst_kw(self, kw, raw=0, target=None, source=None):
384 mode = SCons.Util.SUBST_RAW
386 mode = SCons.Util.SUBST_CMD
388 for k, v in kw.items():
389 k = SCons.Util.scons_subst(k, self, mode, target, source)
390 if SCons.Util.is_String(v):
391 v = SCons.Util.scons_subst(v, self, mode, target, source)
395 def subst_list(self, string, raw=0, target=None, source=None):
396 """Calls through to SCons.Util.scons_subst_list(). See
397 the documentation for that function."""
399 mode = SCons.Util.SUBST_RAW
401 mode = SCons.Util.SUBST_CMD
402 return SCons.Util.scons_subst_list(string, self, mode, target, source)
404 def use_build_signature(self):
406 return self._build_signature
407 except AttributeError:
408 b = SCons.Defaults.DefaultEnvironment()._build_signature
409 self._build_signature = b
412 #######################################################################
413 # Public methods for manipulating an Environment. These begin with
414 # upper-case letters. The essential characteristic of methods in
415 # this section is that they do *not* have corresponding same-named
416 # global functions. For example, a stand-alone Append() function
417 # makes no sense, because Append() is all about appending values to
418 # an Environment's construction variables.
419 #######################################################################
421 def Append(self, **kw):
422 """Append values to existing construction variables
425 kw = our_deepcopy(kw)
426 for key in kw.keys():
427 if not self._dict.has_key(key):
428 self._dict[key] = kw[key]
429 elif SCons.Util.is_List(self._dict[key]) and not \
430 SCons.Util.is_List(kw[key]):
432 self._dict[key] = self._dict[key] + [ kw[key] ]
433 #self._dict[key] = map(None, self._dict[key] + [ kw[key] ])
434 elif SCons.Util.is_List(kw[key]) and not \
435 SCons.Util.is_List(self._dict[key]):
437 self._dict[key] = [ self._dict[key] ] + kw[key]
439 self._dict[key] = kw[key]
440 #self._dict[key] = map(None, self._dict[key] + [ kw[key] ])
441 elif SCons.Util.is_Dict(self._dict[key]) and \
442 SCons.Util.is_Dict(kw[key]):
443 self._dict[key].update(kw[key])
445 self._dict[key] = self._dict[key] + kw[key]
447 def AppendENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep):
448 """Append path elements to the path 'name' in the 'ENV'
449 dictionary for this environment. Will only add any particular
450 path once, and will normpath and normcase all paths to help
451 assure this. This can also handle the case where the env
452 variable is a list instead of a string.
456 if self._dict.has_key(envname) and self._dict[envname].has_key(name):
457 orig = self._dict[envname][name]
459 nv = SCons.Util.AppendPath(orig, newpath, sep)
461 if not self._dict.has_key(envname):
462 self._dict[envname] = {}
464 self._dict[envname][name] = nv
466 def Copy(self, tools=None, toolpath=[], **kw):
467 """Return a copy of a construction Environment. The
468 copy is like a Python "deep copy"--that is, independent
469 copies are made recursively of each objects--except that
470 a reference is copied when an object is not deep-copyable
471 (like a function). There are no references to any mutable
472 objects in the original Environment.
474 clone = copy.copy(self)
475 clone._dict = our_deepcopy(self._dict)
477 cbd = clone._dict['BUILDERS']
478 clone._dict['BUILDERS'] = BuilderDict(cbd, clone)
482 apply_tools(clone, tools, toolpath)
484 # Apply passed-in variables after the new tools.
485 apply(clone.Replace, (), kw)
488 def Detect(self, progs):
489 """Return the first available program in progs.
491 if not SCons.Util.is_List(progs):
494 path = self.WhereIs(prog)
498 def Dictionary(self, *args):
501 dlist = map(lambda x, s=self: s._dict[x], args)
506 def FindIxes(self, paths, prefix, suffix):
508 Search a list of paths for something that matches the prefix and suffix.
510 paths - the list of paths or nodes.
511 prefix - construction variable for the prefix.
512 suffix - construction variable for the suffix.
515 suffix = self.subst('$%s'%suffix)
516 prefix = self.subst('$%s'%prefix)
519 dir,name = os.path.split(str(path))
520 if name[:len(prefix)] == prefix and name[-len(suffix):] == suffix:
523 def Override(self, overrides):
525 Produce a modified environment whose variables
526 are overriden by the overrides dictionaries.
528 overrides - a dictionary that will override
529 the variables of this environment.
531 This function is much more efficient than Copy()
532 or creating a new Environment because it doesn't do
533 a deep copy of the dictionary, and doesn't do a copy
534 at all if there are no overrides.
538 env = copy.copy(self)
539 env._dict = copy.copy(self._dict)
540 env._dict.update(overrides)
545 def ParseConfig(self, command, function=None):
547 Use the specified function to parse the output of the command
548 in order to modify the current environment. The 'command'
549 can be a string or a list of strings representing a command and
550 it's arguments. 'Function' is an optional argument that takes
551 the environment and the output of the command. If no function is
552 specified, the output will be treated as the output of a typical
553 'X-config' command (i.e. gtk-config) and used to set the CPPPATH,
554 LIBPATH, LIBS, and CCFLAGS variables.
557 # the default parse function
558 def parse_conf(env, output):
567 params = string.split(output)
573 dict['LIBPATH'].append(arg[2:])
575 dict['LIBS'].append(arg[2:])
577 dict['CPPPATH'].append(arg[2:])
579 dict['CCFLAGS'].append(arg)
581 static_libs.append(arg)
582 apply(env.Append, (), dict)
586 function = parse_conf
587 if type(command) is type([]):
588 command = string.join(command)
589 command = self.subst(command)
590 return function(self, os.popen(command).read())
592 def Platform(self, platform):
593 platform = self.subst(platform)
594 return SCons.Platform.Platform(platform)(self)
596 def Prepend(self, **kw):
597 """Prepend values to existing construction variables
600 kw = our_deepcopy(kw)
601 for key in kw.keys():
602 if not self._dict.has_key(key):
603 self._dict[key] = kw[key]
604 elif SCons.Util.is_List(self._dict[key]) and not \
605 SCons.Util.is_List(kw[key]):
606 self._dict[key] = [ kw[key] ] + self._dict[key]
607 elif SCons.Util.is_List(kw[key]) and not \
608 SCons.Util.is_List(self._dict[key]):
609 self._dict[key] = kw[key] + [ self._dict[key] ]
610 elif SCons.Util.is_Dict(self._dict[key]) and \
611 SCons.Util.is_Dict(kw[key]):
612 self._dict[key].update(kw[key])
614 self._dict[key] = kw[key] + self._dict[key]
616 def PrependENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep):
617 """Prepend path elements to the path 'name' in the 'ENV'
618 dictionary for this environment. Will only add any particular
619 path once, and will normpath and normcase all paths to help
620 assure this. This can also handle the case where the env
621 variable is a list instead of a string.
625 if self._dict.has_key(envname) and self._dict[envname].has_key(name):
626 orig = self._dict[envname][name]
628 nv = SCons.Util.PrependPath(orig, newpath, sep)
630 if not self._dict.has_key(envname):
631 self._dict[envname] = {}
633 self._dict[envname][name] = nv
635 def Replace(self, **kw):
636 """Replace existing construction variables in an Environment
637 with new construction variables and/or values.
640 kwbd = our_deepcopy(kw['BUILDERS'])
642 self.__setitem__('BUILDERS', kwbd)
645 self._dict.update(our_deepcopy(kw))
647 def ReplaceIxes(self, path, old_prefix, old_suffix, new_prefix, new_suffix):
649 Replace old_prefix with new_prefix and old_suffix with new_suffix.
651 env - Environment used to interpolate variables.
652 path - the path that will be modified.
653 old_prefix - construction variable for the old prefix.
654 old_suffix - construction variable for the old suffix.
655 new_prefix - construction variable for the new prefix.
656 new_suffix - construction variable for the new suffix.
658 old_prefix = self.subst('$%s'%old_prefix)
659 old_suffix = self.subst('$%s'%old_suffix)
661 new_prefix = self.subst('$%s'%new_prefix)
662 new_suffix = self.subst('$%s'%new_suffix)
664 dir,name = os.path.split(str(path))
665 if name[:len(old_prefix)] == old_prefix:
666 name = name[len(old_prefix):]
667 if name[-len(old_suffix):] == old_suffix:
668 name = name[:-len(old_suffix)]
669 return os.path.join(dir, new_prefix+name+new_suffix)
671 def Tool(self, tool, toolpath=[]):
672 tool = self.subst(tool)
673 return SCons.Tool.Tool(tool, map(self.subst, toolpath))(self)
675 def WhereIs(self, prog, path=None, pathext=None):
676 """Find prog in the path.
680 path = self['ENV']['PATH']
683 elif SCons.Util.is_String(path):
684 path = self.subst(path)
687 pathext = self['ENV']['PATHEXT']
690 elif SCons.Util.is_String(pathext):
691 pathext = self.subst(pathext)
692 path = SCons.Util.WhereIs(prog, path, pathext)
696 #######################################################################
697 # Public methods for doing real "SCons stuff" (manipulating
698 # dependencies, setting attributes on targets, etc.). These begin
699 # with upper-case letters. The essential characteristic of methods
700 # in this section is that they all *should* have corresponding
701 # same-named global functions.
702 #######################################################################
704 def Action(self, *args, **kw):
705 nargs = self.subst_list(args)
706 nkw = self.subst_kw(kw)
707 return apply(SCons.Action.Action, nargs, nkw)
709 def AddPreAction(self, files, action):
710 nodes = self.arg2nodes(files, self.fs.Entry)
711 action = SCons.Action.Action(action)
713 n.add_pre_action(action)
716 def AddPostAction(self, files, action):
717 nodes = self.arg2nodes(files, self.fs.Entry)
718 action = SCons.Action.Action(action)
720 n.add_post_action(action)
723 def Alias(self, target, *source, **kw):
724 if not SCons.Util.is_List(target):
728 if not isinstance(t, SCons.Node.Alias.Alias):
729 t = self.arg2nodes(self.subst(t), self.ans.Alias)[0]
739 if not SCons.Util.is_List(s):
742 s = self.arg2nodes(s, self.fs.Entry)
744 AliasBuilder(self, t, s)
749 def AlwaysBuild(self, *targets):
752 tlist.extend(self.arg2nodes(t, self.fs.File))
761 def BuildDir(self, build_dir, src_dir, duplicate=1):
762 build_dir = self.arg2nodes(build_dir, self.fs.Dir)[0]
763 src_dir = self.arg2nodes(src_dir, self.fs.Dir)[0]
764 self.fs.BuildDir(build_dir, src_dir, duplicate)
766 def Builder(self, **kw):
767 nkw = self.subst_kw(kw)
768 return apply(SCons.Builder.Builder, [], nkw)
770 def CacheDir(self, path):
771 self.fs.CacheDir(self.subst(path))
773 def Clean(self, target, files):
776 if not isinstance(target, SCons.Node.Node):
777 target = self.subst(target)
778 target = self.fs.Entry(target, create=1)
780 if not SCons.Util.is_List(files):
785 if isinstance(f, SCons.Node.Node):
788 nodes.extend(self.arg2nodes(f, self.fs.Entry))
791 CleanTargets[target].extend(nodes)
793 CleanTargets[target] = nodes
795 def Configure(self, *args, **kw):
798 nargs = nargs + self.subst_list(args)[0]
799 nkw = self.subst_kw(kw)
801 nkw['custom_tests'] = self.subst_kw(nkw['custom_tests'])
804 return apply(SCons.SConf.SConf, nargs, nkw)
806 def Command(self, target, source, action):
807 """Builds the supplied target files from the supplied
808 source files using the supplied action. Action may
809 be any type that the Builder constructor will accept
811 bld = SCons.Builder.Builder(action=action,
812 source_factory=self.fs.Entry)
813 return bld(self, target, source)
815 def Depends(self, target, dependency):
816 """Explicity specify that 'target's depend on 'dependency'."""
817 tlist = self.arg2nodes(target, self.fs.Entry)
818 dlist = self.arg2nodes(dependency, self.fs.Entry)
820 t.add_dependency(dlist)
826 def Dir(self, name, *args, **kw):
829 return apply(self.fs.Dir, (self.subst(name),) + args, kw)
831 def Environment(self, **kw):
832 return apply(SCons.Environment.Environment, [], self.subst_kw(kw))
834 def File(self, name, *args, **kw):
837 return apply(self.fs.File, (self.subst(name),) + args, kw)
839 def FindFile(self, file, dirs):
840 file = self.subst(file)
841 nodes = self.arg2nodes(dirs, self.fs.Dir)
842 return SCons.Node.FS.find_file(file, nodes, self.fs.File)
844 def GetBuildPath(self, files):
845 ret = map(str, self.arg2nodes(files, self.fs.Entry))
850 def Ignore(self, target, dependency):
851 """Ignore a dependency."""
852 tlist = self.arg2nodes(target, self.fs.Entry)
853 dlist = self.arg2nodes(dependency, self.fs.Entry)
861 def Install(self, dir, source):
862 """Install specified files in the given directory."""
864 dnodes = self.arg2nodes(dir, self.fs.Dir)
866 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)
868 sources = self.arg2nodes(source, self.fs.File)
870 if SCons.Util.is_List(source):
871 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))
873 raise SCons.Errors.UserError, "Source `%s' of Install() is not a file. Install() source must be one or more files." % str(source)
877 target = self.fs.File(src.name, dnode)
878 tgt.append(InstallBuilder(self, target, src))
883 def InstallAs(self, target, source):
884 """Install sources as targets."""
885 sources = self.arg2nodes(source, self.fs.File)
886 targets = self.arg2nodes(target, self.fs.File)
888 for src, tgt in map(lambda x, y: (x, y), sources, targets):
889 ret.append(InstallBuilder(self, tgt, src))
894 def Literal(self, string):
895 return SCons.Util.Literal(string)
897 def Local(self, *targets):
900 if isinstance(targ, SCons.Node.Node):
904 for t in self.arg2nodes(targ, self.fs.Entry):
909 def Precious(self, *targets):
912 tlist.extend(self.arg2nodes(t, self.fs.Entry))
921 def Repository(self, *dirs, **kw):
922 dirs = self.arg2nodes(list(dirs), self.fs.Dir)
923 apply(self.fs.Repository, dirs, kw)
925 def Scanner(self, *args, **kw):
928 if SCons.Util.is_String(arg):
929 arg = self.subst(arg)
931 nkw = self.subst_kw(kw)
932 return apply(SCons.Scanner.Base, nargs, nkw)
934 def SConsignFile(self, name=".sconsign.dbm", dbm_module=None):
935 name = self.subst(name)
936 if not os.path.isabs(name):
937 name = os.path.join(str(self.fs.SConstruct_dir), name)
938 SCons.Sig.SConsignFile(name, dbm_module)
940 def SideEffect(self, side_effect, target):
941 """Tell scons that side_effects are built as side
942 effects of building targets."""
943 side_effects = self.arg2nodes(side_effect, self.fs.Entry)
944 targets = self.arg2nodes(target, self.fs.Entry)
946 for side_effect in side_effects:
947 # A builder of 1 means the node is supposed to appear
948 # buildable without actually having a builder, so we allow
949 # it to be a side effect as well.
950 if side_effect.has_builder() and side_effect.builder != 1:
951 raise SCons.Errors.UserError, "Multiple ways to build the same target were specified for: %s" % str(side_effect)
952 side_effect.add_source(targets)
953 side_effect.side_effect = 1
954 self.Precious(side_effect)
955 for target in targets:
956 target.side_effects.append(side_effect)
957 if len(side_effects) == 1:
958 return side_effects[0]
962 def SourceCode(self, entry, builder):
963 """Arrange for a source code builder for (part of) a tree."""
964 entries = self.arg2nodes(entry, self.fs.Entry)
965 for entry in entries:
966 entry.set_src_builder(builder)
967 if len(entries) == 1:
971 def SourceSignatures(self, type):
972 type = self.subst(type)
975 self._calc_module = SCons.Sig.MD5
976 elif type == 'timestamp':
977 import SCons.Sig.TimeStamp
978 self._calc_module = SCons.Sig.TimeStamp
980 raise UserError, "Unknown source signature type '%s'"%type
982 def Split(self, arg):
983 """This function converts a string or list into a list of strings
984 or Nodes. This makes things easier for users by allowing files to
985 be specified as a white-space separated list to be split.
987 - A single string containing names separated by spaces. These will be
988 split apart at the spaces.
989 - A single Node instance
990 - A list containing either strings or Node instances. Any strings
991 in the list are not split at spaces.
992 In all cases, the function returns a list of Nodes and strings."""
993 if SCons.Util.is_List(arg):
994 return map(self.subst, arg)
995 elif SCons.Util.is_String(arg):
996 return string.split(self.subst(arg))
998 return [self.subst(arg)]
1000 def TargetSignatures(self, type):
1001 type = self.subst(type)
1003 self._build_signature = 1
1004 elif type == 'content':
1005 self._build_signature = 0
1007 raise SCons.Errors.UserError, "Unknown target signature type '%s'"%type
1009 def Value(self, value):
1012 return SCons.Node.Python.Value(value)
1014 # The entry point that will be used by the external world
1015 # to refer to a construction environment. This allows the wrapper
1016 # interface to extend a construction environment for its own purposes
1017 # by subclassing SCons.Environment.Base and then assigning the
1018 # class to SCons.Environment.Environment.