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):
115 if SCons.Util.is_String(tool):
116 tool = SCons.Tool.Tool(tool)
119 class BuilderWrapper:
120 """Wrapper class that associates an environment with a Builder at
122 def __init__(self, env, builder):
124 self.builder = builder
126 def __call__(self, *args, **kw):
127 return apply(self.builder, (self.env,) + args, kw)
129 # This allows a Builder to be executed directly
130 # through the Environment to which it's attached.
131 # In practice, we shouldn't need this, because
132 # builders actually get executed through a Node.
133 # But we do have a unit test for this, and can't
134 # yet rule out that it would be useful in the
135 # future, so leave it for now.
136 def execute(self, **kw):
138 apply(self.builder.execute, (), kw)
140 class BuilderDict(UserDict):
141 """This is a dictionary-like class used by an Environment to hold
142 the Builders. We need to do this because every time someone changes
143 the Builders in the Environment's BUILDERS dictionary, we must
144 update the Environment's attributes."""
145 def __init__(self, dict, env):
146 # Set self.env before calling the superclass initialization,
147 # because it will end up calling our other methods, which will
148 # need to point the values in this dictionary to self.env.
150 UserDict.__init__(self, dict)
152 def __setitem__(self, item, val):
153 UserDict.__setitem__(self, item, val)
155 self.setenvattr(item, val)
156 except AttributeError:
157 # Have to catch this because sometimes __setitem__ gets
158 # called out of __init__, when we don't have an env
159 # attribute yet, nor do we want one!
162 def setenvattr(self, item, val):
163 """Set the corresponding environment attribute for this Builder.
165 If the value is already a BuilderWrapper, we pull the builder
166 out of it and make another one, so that making a copy of an
167 existing BuilderDict is guaranteed separate wrappers for each
168 Builder + Environment pair."""
170 builder = val.builder
171 except AttributeError:
173 setattr(self.env, item, BuilderWrapper(self.env, builder))
175 def __delitem__(self, item):
176 UserDict.__delitem__(self, item)
177 delattr(self.env, item)
179 def update(self, dict):
180 for i, v in dict.items():
181 self.__setitem__(i, v)
184 """Base class for construction Environments. These are
185 the primary objects used to communicate dependency and
186 construction information to the build engine.
188 Keyword arguments supplied when the construction Environment
189 is created are construction variables used to initialize the
193 #######################################################################
194 # This is THE class for interacting with the SCons build engine,
195 # and it contains a lot of stuff, so we're going to try to keep this
196 # a little organized by grouping the methods.
197 #######################################################################
199 #######################################################################
200 # Methods that make an Environment act like a dictionary. These have
201 # the expected standard names for Python mapping objects. Note that
202 # we don't actually make an Environment a subclass of UserDict for
203 # performance reasons. Note also that we only supply methods for
204 # dictionary functionality that we actually need and use.
205 #######################################################################
212 self.fs = SCons.Node.FS.default_fs
213 self.ans = SCons.Node.Alias.default_ans
214 self.lookup_list = SCons.Node.arg2nodes_lookups
215 self._dict = our_deepcopy(SCons.Defaults.ConstructionEnvironment)
217 self._dict['BUILDERS'] = BuilderDict(self._dict['BUILDERS'], self)
220 platform = self._dict.get('PLATFORM', None)
222 platform = SCons.Platform.Platform()
223 if SCons.Util.is_String(platform):
224 platform = SCons.Platform.Platform(platform)
225 self._dict['PLATFORM'] = str(platform)
228 # Apply the passed-in variables before calling the tools,
229 # because they may use some of them:
230 apply(self.Replace, (), kw)
232 # Update the environment with the customizable options
233 # before calling the tools, since they may use some of the options:
238 tools = self._dict.get('TOOLS', None)
241 apply_tools(self, tools)
243 # Reapply the passed in variables after calling the tools,
244 # since they should overide anything set by the tools:
245 apply(self.Replace, (), kw)
247 # Update the environment with the customizable options
248 # after calling the tools, since they should override anything
253 def __cmp__(self, other):
254 return cmp(self._dict, other._dict)
256 def __getitem__(self, key):
257 return self._dict[key]
259 def __setitem__(self, key, value):
260 if key in ['TARGET', 'TARGETS', 'SOURCE', 'SOURCES']:
261 SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning,
262 "Ignoring attempt to set reserved variable `%s'" % key)
263 elif key == 'BUILDERS':
269 self._dict[key] = BuilderDict(kwbd, self)
270 self._dict[key].update(value)
272 if not SCons.Util.is_valid_construction_var(key):
273 raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key
274 self._dict[key] = value
276 def __delitem__(self, key):
280 "Emulates the items() method of dictionaries."""
281 return self._dict.items()
283 def has_key(self, key):
284 return self._dict.has_key(key)
286 def get(self, key, default=None):
287 "Emulates the get() method of dictionaries."""
288 return self._dict.get(key, default)
290 #######################################################################
291 # Utility methods that are primarily for internal use by SCons.
292 # These begin with lower-case letters. Note that the subst() method
293 # is actually already out of the closet and used by people.
294 #######################################################################
296 def arg2nodes(self, args, node_factory=_null, lookup_list=_null):
297 if node_factory is _null:
298 node_factory = self.fs.File
299 if lookup_list is _null:
300 lookup_list = self.lookup_list
305 if not SCons.Util.is_List(args):
310 if SCons.Util.is_String(v):
312 for l in lookup_list:
317 if SCons.Util.is_String(n):
318 n = self.subst(n, raw=1)
323 v = self.subst(v, raw=1)
324 nodes.append(node_factory(v))
330 def get_calculator(self):
332 return self._calculator
333 except AttributeError:
335 module = self._calc_module
336 c = apply(SCons.Sig.Calculator, (module,), CalculatorArgs)
337 except AttributeError:
338 # Note that we're calling get_calculator() here, so the
339 # DefaultEnvironment() must have a _calc_module attribute
340 # to avoid infinite recursion.
341 c = SCons.Defaults.DefaultEnvironment().get_calculator()
345 def get_builder(self, name):
346 """Fetch the builder with the specified name from the environment.
349 return self._dict['BUILDERS'][name]
353 def get_scanner(self, skey):
354 """Find the appropriate scanner given a key (usually a file suffix).
355 Does a linear search. Could be sped up by creating a dictionary if
356 this proves too slow.
358 if self._dict['SCANNERS']:
359 for scanner in self._dict['SCANNERS']:
360 if skey in scanner.skeys:
364 def subst(self, string, raw=0, target=None, source=None):
365 """Recursively interpolates construction variables from the
366 Environment into the specified string, returning the expanded
367 result. Construction variables are specified by a $ prefix
368 in the string and begin with an initial underscore or
369 alphabetic character followed by any number of underscores
370 or alphanumeric characters. The construction variable names
371 may be surrounded by curly braces to separate the name from
375 mode = SCons.Util.SUBST_RAW
377 mode = SCons.Util.SUBST_CMD
378 return SCons.Util.scons_subst(string, self, mode, target, source)
380 def subst_kw(self, kw, raw=0, target=None, source=None):
382 mode = SCons.Util.SUBST_RAW
384 mode = SCons.Util.SUBST_CMD
386 for k, v in kw.items():
387 k = SCons.Util.scons_subst(k, self, mode, target, source)
388 if SCons.Util.is_String(v):
389 v = SCons.Util.scons_subst(v, self, mode, target, source)
393 def subst_list(self, string, raw=0, target=None, source=None):
394 """Calls through to SCons.Util.scons_subst_list(). See
395 the documentation for that function."""
397 mode = SCons.Util.SUBST_RAW
399 mode = SCons.Util.SUBST_CMD
400 return SCons.Util.scons_subst_list(string, self, mode, target, source)
402 def use_build_signature(self):
404 return self._build_signature
405 except AttributeError:
406 b = SCons.Defaults.DefaultEnvironment()._build_signature
407 self._build_signature = b
410 #######################################################################
411 # Public methods for manipulating an Environment. These begin with
412 # upper-case letters. The essential characteristic of methods in
413 # this section is that they do *not* have corresponding same-named
414 # global functions. For example, a stand-alone Append() function
415 # makes no sense, because Append() is all about appending values to
416 # an Environment's construction variables.
417 #######################################################################
419 def Append(self, **kw):
420 """Append values to existing construction variables
423 kw = our_deepcopy(kw)
424 for key in kw.keys():
425 if not self._dict.has_key(key):
426 self._dict[key] = kw[key]
427 elif SCons.Util.is_List(self._dict[key]) and not \
428 SCons.Util.is_List(kw[key]):
430 self._dict[key] = self._dict[key] + [ kw[key] ]
431 #self._dict[key] = map(None, self._dict[key] + [ kw[key] ])
432 elif SCons.Util.is_List(kw[key]) and not \
433 SCons.Util.is_List(self._dict[key]):
435 self._dict[key] = [ self._dict[key] ] + kw[key]
437 self._dict[key] = kw[key]
438 #self._dict[key] = map(None, self._dict[key] + [ kw[key] ])
439 elif SCons.Util.is_Dict(self._dict[key]) and \
440 SCons.Util.is_Dict(kw[key]):
441 self._dict[key].update(kw[key])
443 self._dict[key] = self._dict[key] + kw[key]
445 def AppendENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep):
446 """Append path elements to the path 'name' in the 'ENV'
447 dictionary for this environment. Will only add any particular
448 path once, and will normpath and normcase all paths to help
449 assure this. This can also handle the case where the env
450 variable is a list instead of a string.
454 if self._dict.has_key(envname) and self._dict[envname].has_key(name):
455 orig = self._dict[envname][name]
457 nv = SCons.Util.AppendPath(orig, newpath, sep)
459 if not self._dict.has_key(envname):
460 self._dict[envname] = {}
462 self._dict[envname][name] = nv
464 def Copy(self, tools=None, **kw):
465 """Return a copy of a construction Environment. The
466 copy is like a Python "deep copy"--that is, independent
467 copies are made recursively of each objects--except that
468 a reference is copied when an object is not deep-copyable
469 (like a function). There are no references to any mutable
470 objects in the original Environment.
472 clone = copy.copy(self)
473 clone._dict = our_deepcopy(self._dict)
475 cbd = clone._dict['BUILDERS']
476 clone._dict['BUILDERS'] = BuilderDict(cbd, clone)
480 apply_tools(clone, tools)
482 # Apply passed-in variables after the new tools.
483 apply(clone.Replace, (), kw)
486 def Detect(self, progs):
487 """Return the first available program in progs.
489 if not SCons.Util.is_List(progs):
492 path = self.WhereIs(prog)
496 def Dictionary(self, *args):
499 dlist = map(lambda x, s=self: s._dict[x], args)
504 def FindIxes(self, paths, prefix, suffix):
506 Search a list of paths for something that matches the prefix and suffix.
508 paths - the list of paths or nodes.
509 prefix - construction variable for the prefix.
510 suffix - construction variable for the suffix.
513 suffix = self.subst('$%s'%suffix)
514 prefix = self.subst('$%s'%prefix)
517 dir,name = os.path.split(str(path))
518 if name[:len(prefix)] == prefix and name[-len(suffix):] == suffix:
521 def Override(self, overrides):
523 Produce a modified environment whose variables
524 are overriden by the overrides dictionaries.
526 overrides - a dictionary that will override
527 the variables of this environment.
529 This function is much more efficient than Copy()
530 or creating a new Environment because it doesn't do
531 a deep copy of the dictionary, and doesn't do a copy
532 at all if there are no overrides.
536 env = copy.copy(self)
537 env._dict = copy.copy(self._dict)
538 env._dict.update(overrides)
543 def ParseConfig(self, command, function=None):
545 Use the specified function to parse the output of the command
546 in order to modify the current environment. The 'command'
547 can be a string or a list of strings representing a command and
548 it's arguments. 'Function' is an optional argument that takes
549 the environment and the output of the command. If no function is
550 specified, the output will be treated as the output of a typical
551 'X-config' command (i.e. gtk-config) and used to set the CPPPATH,
552 LIBPATH, LIBS, and CCFLAGS variables.
555 # the default parse function
556 def parse_conf(env, output):
565 params = string.split(output)
571 dict['LIBPATH'].append(arg[2:])
573 dict['LIBS'].append(arg[2:])
575 dict['CPPPATH'].append(arg[2:])
577 dict['CCFLAGS'].append(arg)
579 static_libs.append(arg)
580 apply(env.Append, (), dict)
584 function = parse_conf
585 if type(command) is type([]):
586 command = string.join(command)
587 command = self.subst(command)
588 return function(self, os.popen(command).read())
590 def Platform(self, platform):
591 platform = self.subst(platform)
592 return SCons.Platform.Platform(platform)(self)
594 def Prepend(self, **kw):
595 """Prepend values to existing construction variables
598 kw = our_deepcopy(kw)
599 for key in kw.keys():
600 if not self._dict.has_key(key):
601 self._dict[key] = kw[key]
602 elif SCons.Util.is_List(self._dict[key]) and not \
603 SCons.Util.is_List(kw[key]):
604 self._dict[key] = [ kw[key] ] + self._dict[key]
605 elif SCons.Util.is_List(kw[key]) and not \
606 SCons.Util.is_List(self._dict[key]):
607 self._dict[key] = kw[key] + [ self._dict[key] ]
608 elif SCons.Util.is_Dict(self._dict[key]) and \
609 SCons.Util.is_Dict(kw[key]):
610 self._dict[key].update(kw[key])
612 self._dict[key] = kw[key] + self._dict[key]
614 def PrependENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep):
615 """Prepend path elements to the path 'name' in the 'ENV'
616 dictionary for this environment. Will only add any particular
617 path once, and will normpath and normcase all paths to help
618 assure this. This can also handle the case where the env
619 variable is a list instead of a string.
623 if self._dict.has_key(envname) and self._dict[envname].has_key(name):
624 orig = self._dict[envname][name]
626 nv = SCons.Util.PrependPath(orig, newpath, sep)
628 if not self._dict.has_key(envname):
629 self._dict[envname] = {}
631 self._dict[envname][name] = nv
633 def Replace(self, **kw):
634 """Replace existing construction variables in an Environment
635 with new construction variables and/or values.
638 kwbd = our_deepcopy(kw['BUILDERS'])
640 self.__setitem__('BUILDERS', kwbd)
643 self._dict.update(our_deepcopy(kw))
645 def ReplaceIxes(self, path, old_prefix, old_suffix, new_prefix, new_suffix):
647 Replace old_prefix with new_prefix and old_suffix with new_suffix.
649 env - Environment used to interpolate variables.
650 path - the path that will be modified.
651 old_prefix - construction variable for the old prefix.
652 old_suffix - construction variable for the old suffix.
653 new_prefix - construction variable for the new prefix.
654 new_suffix - construction variable for the new suffix.
656 old_prefix = self.subst('$%s'%old_prefix)
657 old_suffix = self.subst('$%s'%old_suffix)
659 new_prefix = self.subst('$%s'%new_prefix)
660 new_suffix = self.subst('$%s'%new_suffix)
662 dir,name = os.path.split(str(path))
663 if name[:len(old_prefix)] == old_prefix:
664 name = name[len(old_prefix):]
665 if name[-len(old_suffix):] == old_suffix:
666 name = name[:-len(old_suffix)]
667 return os.path.join(dir, new_prefix+name+new_suffix)
669 def Tool(self, tool):
670 tool = self.subst(tool)
671 return SCons.Tool.Tool(tool)(self)
673 def WhereIs(self, prog, path=None, pathext=None):
674 """Find prog in the path.
678 path = self['ENV']['PATH']
681 elif SCons.Util.is_String(path):
682 path = self.subst(path)
685 pathext = self['ENV']['PATHEXT']
688 elif SCons.Util.is_String(pathext):
689 pathext = self.subst(pathext)
690 path = SCons.Util.WhereIs(prog, path, pathext)
694 #######################################################################
695 # Public methods for doing real "SCons stuff" (manipulating
696 # dependencies, setting attributes on targets, etc.). These begin
697 # with upper-case letters. The essential characteristic of methods
698 # in this section is that they all *should* have corresponding
699 # same-named global functions.
700 #######################################################################
702 def Action(self, *args, **kw):
703 nargs = self.subst_list(args)
704 nkw = self.subst_kw(kw)
705 return apply(SCons.Action.Action, nargs, nkw)
707 def AddPreAction(self, files, action):
708 nodes = self.arg2nodes(files, self.fs.Entry)
709 action = SCons.Action.Action(action)
711 n.add_pre_action(action)
714 def AddPostAction(self, files, action):
715 nodes = self.arg2nodes(files, self.fs.Entry)
716 action = SCons.Action.Action(action)
718 n.add_post_action(action)
721 def Alias(self, target, *source, **kw):
722 if not SCons.Util.is_List(target):
726 if not isinstance(t, SCons.Node.Alias.Alias):
727 t = self.arg2nodes(self.subst(t), self.ans.Alias)[0]
737 if not SCons.Util.is_List(s):
740 s = self.arg2nodes(s, self.fs.Entry)
742 AliasBuilder(self, t, s)
747 def AlwaysBuild(self, *targets):
750 tlist.extend(self.arg2nodes(t, self.fs.File))
759 def BuildDir(self, build_dir, src_dir, duplicate=1):
760 build_dir = self.arg2nodes(build_dir, self.fs.Dir)[0]
761 src_dir = self.arg2nodes(src_dir, self.fs.Dir)[0]
762 self.fs.BuildDir(build_dir, src_dir, duplicate)
764 def Builder(self, **kw):
765 nkw = self.subst_kw(kw)
766 return apply(SCons.Builder.Builder, [], nkw)
768 def CacheDir(self, path):
769 self.fs.CacheDir(self.subst(path))
771 def Clean(self, target, files):
774 if not isinstance(target, SCons.Node.Node):
775 target = self.subst(target)
776 target = self.fs.Entry(target, create=1)
778 if not SCons.Util.is_List(files):
783 if isinstance(f, SCons.Node.Node):
786 nodes.extend(self.arg2nodes(f, self.fs.Entry))
789 CleanTargets[target].extend(nodes)
791 CleanTargets[target] = nodes
793 def Configure(self, *args, **kw):
796 nargs = nargs + self.subst_list(args)[0]
797 nkw = self.subst_kw(kw)
799 nkw['custom_tests'] = self.subst_kw(nkw['custom_tests'])
802 return apply(SCons.SConf.SConf, nargs, nkw)
804 def Command(self, target, source, action):
805 """Builds the supplied target files from the supplied
806 source files using the supplied action. Action may
807 be any type that the Builder constructor will accept
809 bld = SCons.Builder.Builder(action=action,
810 source_factory=self.fs.Entry)
811 return bld(self, target, source)
813 def Depends(self, target, dependency):
814 """Explicity specify that 'target's depend on 'dependency'."""
815 tlist = self.arg2nodes(target, self.fs.Entry)
816 dlist = self.arg2nodes(dependency, self.fs.Entry)
818 t.add_dependency(dlist)
824 def Dir(self, name, *args, **kw):
827 return apply(self.fs.Dir, (self.subst(name),) + args, kw)
829 def Environment(self, **kw):
830 return apply(SCons.Environment.Environment, [], self.subst_kw(kw))
832 def File(self, name, *args, **kw):
835 return apply(self.fs.File, (self.subst(name),) + args, kw)
837 def FindFile(self, file, dirs):
838 file = self.subst(file)
839 nodes = self.arg2nodes(dirs, self.fs.Dir)
840 return SCons.Node.FS.find_file(file, nodes, self.fs.File)
842 def GetBuildPath(self, files):
843 ret = map(str, self.arg2nodes(files, self.fs.Entry))
848 def Ignore(self, target, dependency):
849 """Ignore a dependency."""
850 tlist = self.arg2nodes(target, self.fs.Entry)
851 dlist = self.arg2nodes(dependency, self.fs.Entry)
859 def Install(self, dir, source):
860 """Install specified files in the given directory."""
862 dnodes = self.arg2nodes(dir, self.fs.Dir)
864 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)
866 sources = self.arg2nodes(source, self.fs.File)
868 if SCons.Util.is_List(source):
869 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))
871 raise SCons.Errors.UserError, "Source `%s' of Install() is not a file. Install() source must be one or more files." % str(source)
875 target = self.fs.File(src.name, dnode)
876 tgt.append(InstallBuilder(self, target, src))
881 def InstallAs(self, target, source):
882 """Install sources as targets."""
883 sources = self.arg2nodes(source, self.fs.File)
884 targets = self.arg2nodes(target, self.fs.File)
886 for src, tgt in map(lambda x, y: (x, y), sources, targets):
887 ret.append(InstallBuilder(self, tgt, src))
892 def Literal(self, string):
893 return SCons.Util.Literal(string)
895 def Local(self, *targets):
898 if isinstance(targ, SCons.Node.Node):
902 for t in self.arg2nodes(targ, self.fs.Entry):
907 def Precious(self, *targets):
910 tlist.extend(self.arg2nodes(t, self.fs.Entry))
919 def Repository(self, *dirs, **kw):
920 dirs = self.arg2nodes(list(dirs), self.fs.Dir)
921 apply(self.fs.Repository, dirs, kw)
923 def Scanner(self, *args, **kw):
926 if SCons.Util.is_String(arg):
927 arg = self.subst(arg)
929 nkw = self.subst_kw(kw)
930 return apply(SCons.Scanner.Base, nargs, nkw)
932 def SConsignFile(self, name=".sconsign.dbm", dbm_module=None):
933 name = self.subst(name)
934 if not os.path.isabs(name):
935 name = os.path.join(str(self.fs.SConstruct_dir), name)
936 SCons.Sig.SConsignFile(name, dbm_module)
938 def SideEffect(self, side_effect, target):
939 """Tell scons that side_effects are built as side
940 effects of building targets."""
941 side_effects = self.arg2nodes(side_effect, self.fs.Entry)
942 targets = self.arg2nodes(target, self.fs.Entry)
944 for side_effect in side_effects:
945 # A builder of 1 means the node is supposed to appear
946 # buildable without actually having a builder, so we allow
947 # it to be a side effect as well.
948 if side_effect.has_builder() and side_effect.builder != 1:
949 raise SCons.Errors.UserError, "Multiple ways to build the same target were specified for: %s" % str(side_effect)
950 side_effect.add_source(targets)
951 side_effect.side_effect = 1
952 self.Precious(side_effect)
953 for target in targets:
954 target.side_effects.append(side_effect)
955 if len(side_effects) == 1:
956 return side_effects[0]
960 def SourceCode(self, entry, builder):
961 """Arrange for a source code builder for (part of) a tree."""
962 entries = self.arg2nodes(entry, self.fs.Entry)
963 for entry in entries:
964 entry.set_src_builder(builder)
965 if len(entries) == 1:
969 def SourceSignatures(self, type):
970 type = self.subst(type)
973 self._calc_module = SCons.Sig.MD5
974 elif type == 'timestamp':
975 import SCons.Sig.TimeStamp
976 self._calc_module = SCons.Sig.TimeStamp
978 raise UserError, "Unknown source signature type '%s'"%type
980 def Split(self, arg):
981 """This function converts a string or list into a list of strings
982 or Nodes. This makes things easier for users by allowing files to
983 be specified as a white-space separated list to be split.
985 - A single string containing names separated by spaces. These will be
986 split apart at the spaces.
987 - A single Node instance
988 - A list containing either strings or Node instances. Any strings
989 in the list are not split at spaces.
990 In all cases, the function returns a list of Nodes and strings."""
991 if SCons.Util.is_List(arg):
992 return map(self.subst, arg)
993 elif SCons.Util.is_String(arg):
994 return string.split(self.subst(arg))
996 return [self.subst(arg)]
998 def TargetSignatures(self, type):
999 type = self.subst(type)
1001 self._build_signature = 1
1002 elif type == 'content':
1003 self._build_signature = 0
1005 raise SCons.Errors.UserError, "Unknown target signature type '%s'"%type
1007 def Value(self, value):
1010 return SCons.Node.Python.Value(value)
1012 # The entry point that will be used by the external world
1013 # to refer to a construction environment. This allows the wrapper
1014 # interface to extend a construction environment for its own purposes
1015 # by subclassing SCons.Environment.Base and then assigning the
1016 # class to SCons.Environment.Environment.