1 """SCons.Environment
2
3 Base class for construction Environments. These are
4 the primary objects used to communicate dependency and
5 construction information to the build engine.
6
7 Keyword arguments supplied when the construction Environment
8 is created are construction variables used to initialize the
9 Environment
10 """
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 __revision__ = "src/engine/SCons/Environment.py 2725 2008/03/31 12:52:02 knight"
36
37
38 import copy
39 import os
40 import os.path
41 import re
42 import shlex
43 import string
44 from UserDict import UserDict
45
46 import SCons.Action
47 import SCons.Builder
48 from SCons.Debug import logInstanceCreation
49 import SCons.Defaults
50 import SCons.Errors
51 import SCons.Memoize
52 import SCons.Node
53 import SCons.Node.Alias
54 import SCons.Node.FS
55 import SCons.Node.Python
56 import SCons.Platform
57 import SCons.SConsign
58 import SCons.Subst
59 import SCons.Tool
60 import SCons.Util
61 import SCons.Warnings
62
65
66 _null = _Null
67
68 _warn_copy_deprecated = True
69 _warn_source_signatures_deprecated = True
70 _warn_target_signatures_deprecated = True
71
72 CleanTargets = {}
73 CalculatorArgs = {}
74
75 semi_deepcopy = SCons.Util.semi_deepcopy
76
77
78
79
80 UserError = SCons.Errors.UserError
81
84
85 AliasBuilder = SCons.Builder.Builder(action = alias_builder,
86 target_factory = SCons.Node.Alias.default_ans.Alias,
87 source_factory = SCons.Node.FS.Entry,
88 multi = 1,
89 is_explicit = None,
90 name='AliasBuilder')
91
107
108
109
110
111 reserved_construction_var_names = \
112 ['TARGET', 'TARGETS', 'SOURCE', 'SOURCES']
113
122
126
128 try:
129 bd = env._dict[key]
130 for k in bd.keys():
131 del bd[k]
132 except KeyError:
133 bd = BuilderDict(kwbd, env)
134 env._dict[key] = bd
135 bd.update(value)
136
140
144
145
146
147
148
149
150
151
152
153
154
155
156
157
159 """
160 A generic Wrapper class that associates a method (which can
161 actually be any callable) with an object. As part of creating this
162 MethodWrapper object an attribute with the specified (by default,
163 the name of the supplied method) is added to the underlying object.
164 When that new "method" is called, our __call__() method adds the
165 object as the first argument, simulating the Python behavior of
166 supplying "self" on method calls.
167
168 We hang on to the name by which the method was added to the underlying
169 base class so that we can provide a method to "clone" ourselves onto
170 a new underlying object being copied (without which we wouldn't need
171 to save that info).
172 """
173 - def __init__(self, object, method, name=None):
174 if name is None:
175 name = method.__name__
176 self.object = object
177 self.method = method
178 self.name = name
179 setattr(self.object, name, self)
180
182 nargs = (self.object,) + args
183 return apply(self.method, nargs, kwargs)
184
185 - def clone(self, new_object):
186 """
187 Returns an object that re-binds the underlying "method" to
188 the specified new object.
189 """
190 return self.__class__(new_object, self.method, self.name)
191
193 """
194 A MethodWrapper subclass that that associates an environment with
195 a Builder.
196
197 This mainly exists to wrap the __call__() function so that all calls
198 to Builders can have their argument lists massaged in the same way
199 (treat a lone argument as the source, treat two arguments as target
200 then source, make sure both target and source are lists) without
201 having to have cut-and-paste code to do it.
202
203 As a bit of obsessive backwards compatibility, we also intercept
204 attempts to get or set the "env" or "builder" attributes, which were
205 the names we used before we put the common functionality into the
206 MethodWrapper base class. We'll keep this around for a while in case
207 people shipped Tool modules that reached into the wrapper (like the
208 Tool/qt.py module does, or did). There shouldn't be a lot attribute
209 fetching or setting on these, so a little extra work shouldn't hurt.
210 """
212 if source is _null:
213 source = target
214 target = None
215 if not target is None and not SCons.Util.is_List(target):
216 target = [target]
217 if not source is None and not SCons.Util.is_List(source):
218 source = [source]
219 return apply(MethodWrapper.__call__, (self, target, source) + args, kw)
220
222 return '<BuilderWrapper %s>' % repr(self.name)
223
226
228 if name == 'env':
229 return self.object
230 elif name == 'builder':
231 return self.method
232 else:
233 return self.__dict__[name]
234
236 if name == 'env':
237 self.object = value
238 elif name == 'builder':
239 self.method = value
240 else:
241 self.__dict__[name] = value
242
243
244
245
246
247
248
249
250
251
252
253
255 """This is a dictionary-like class used by an Environment to hold
256 the Builders. We need to do this because every time someone changes
257 the Builders in the Environment's BUILDERS dictionary, we must
258 update the Environment's attributes."""
260
261
262
263 self.env = env
264 UserDict.__init__(self, dict)
265
267 return self.__class__(self.data, self.env)
268
270 try:
271 method = getattr(self.env, item).method
272 except AttributeError:
273 pass
274 else:
275 self.env.RemoveMethod(method)
276 UserDict.__setitem__(self, item, val)
277 BuilderWrapper(self.env, val, item)
278
280 UserDict.__delitem__(self, item)
281 delattr(self.env, item)
282
286
287
288
289 _is_valid_var = re.compile(r'[_a-zA-Z]\w*$')
290
292 """Return if the specified string is a legitimate construction
293 variable.
294 """
295 return _is_valid_var.match(varstr)
296
297
298
300 """Base class for different flavors of construction environments.
301
302 This class contains a minimal set of methods that handle contruction
303 variable expansion and conversion of strings to Nodes, which may or
304 may not be actually useful as a stand-alone class. Which methods
305 ended up in this class is pretty arbitrary right now. They're
306 basically the ones which we've empirically determined are common to
307 the different construction environment subclasses, and most of the
308 others that use or touch the underlying dictionary of construction
309 variables.
310
311 Eventually, this class should contain all the methods that we
312 determine are necessary for a "minimal" interface to the build engine.
313 A full "native Python" SCons environment has gotten pretty heavyweight
314 with all of the methods and Tools and construction variables we've
315 jammed in there, so it would be nice to have a lighter weight
316 alternative for interfaces that don't need all of the bells and
317 whistles. (At some point, we'll also probably rename this class
318 "Base," since that more reflects what we want this class to become,
319 but because we've released comments that tell people to subclass
320 Environment.Base to create their own flavors of construction
321 environment, we'll save that for a future refactoring when this
322 class actually becomes useful.)
323 """
324
325 if SCons.Memoize.use_memoizer:
326 __metaclass__ = SCons.Memoize.Memoized_Metaclass
327
338
339
341 """Initial the dispatch tables for special handling of
342 special construction variables."""
343 self._special_del = {}
344 self._special_del['SCANNERS'] = _del_SCANNERS
345
346 self._special_set = {}
347 for key in reserved_construction_var_names:
348 self._special_set[key] = _set_reserved
349 self._special_set['BUILDERS'] = _set_BUILDERS
350 self._special_set['SCANNERS'] = _set_SCANNERS
351
352
353
354
355 self._special_set_keys = self._special_set.keys()
356
358 return cmp(self._dict, other._dict)
359
361 special = self._special_del.get(key)
362 if special:
363 special(self, key)
364 else:
365 del self._dict[key]
366
368 return self._dict[key]
369
371
372
373
374
375
376
377
378
379
380
381
382
383 if key in self._special_set_keys:
384 self._special_set[key](self, key, value)
385 else:
386
387
388
389
390 if not self._dict.has_key(key) \
391 and not _is_valid_var.match(key):
392 raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key
393 self._dict[key] = value
394
395 - def get(self, key, default=None):
396 "Emulates the get() method of dictionaries."""
397 return self._dict.get(key, default)
398
401
403 return self._dict.items()
404
406 if node_factory is _null:
407 node_factory = self.fs.File
408 if lookup_list is _null:
409 lookup_list = self.lookup_list
410
411 if not args:
412 return []
413
414 args = SCons.Util.flatten(args)
415
416 nodes = []
417 for v in args:
418 if SCons.Util.is_String(v):
419 n = None
420 for l in lookup_list:
421 n = l(v)
422 if not n is None:
423 break
424 if not n is None:
425 if SCons.Util.is_String(n):
426
427 kw['raw'] = 1
428 n = apply(self.subst, (n,), kw)
429 if node_factory:
430 n = node_factory(n)
431 if SCons.Util.is_List(n):
432 nodes.extend(n)
433 else:
434 nodes.append(n)
435 elif node_factory:
436
437 kw['raw'] = 1
438 v = node_factory(apply(self.subst, (v,), kw))
439 if SCons.Util.is_List(v):
440 nodes.extend(v)
441 else:
442 nodes.append(v)
443 else:
444 nodes.append(v)
445
446 return nodes
447
450
453
454 - def subst(self, string, raw=0, target=None, source=None, conv=None):
455 """Recursively interpolates construction variables from the
456 Environment into the specified string, returning the expanded
457 result. Construction variables are specified by a $ prefix
458 in the string and begin with an initial underscore or
459 alphabetic character followed by any number of underscores
460 or alphanumeric characters. The construction variable names
461 may be surrounded by curly braces to separate the name from
462 trailing characters.
463 """
464 gvars = self.gvars()
465 lvars = self.lvars()
466 lvars['__env__'] = self
467 return SCons.Subst.scons_subst(string, self, raw, target, source, gvars, lvars, conv)
468
469 - def subst_kw(self, kw, raw=0, target=None, source=None):
470 nkw = {}
471 for k, v in kw.items():
472 k = self.subst(k, raw, target, source)
473 if SCons.Util.is_String(v):
474 v = self.subst(v, raw, target, source)
475 nkw[k] = v
476 return nkw
477
478 - def subst_list(self, string, raw=0, target=None, source=None, conv=None):
485
486 - def subst_path(self, path, target=None, source=None):
487 """Substitute a path list, turning EntryProxies into Nodes
488 and leaving Nodes (and other objects) as-is."""
489
490 if not SCons.Util.is_List(path):
491 path = [path]
492
493 def s(obj):
494 """This is the "string conversion" routine that we have our
495 substitutions use to return Nodes, not strings. This relies
496 on the fact that an EntryProxy object has a get() method that
497 returns the underlying Node that it wraps, which is a bit of
498 architectural dependence that we might need to break or modify
499 in the future in response to additional requirements."""
500 try:
501 get = obj.get
502 except AttributeError:
503 obj = SCons.Util.to_String_for_subst(obj)
504 else:
505 obj = get()
506 return obj
507
508 r = []
509 for p in path:
510 if SCons.Util.is_String(p):
511 p = self.subst(p, target=target, source=source, conv=s)
512 if SCons.Util.is_List(p):
513 if len(p) == 1:
514 p = p[0]
515 else:
516
517
518
519 p = string.join(map(SCons.Util.to_String_for_subst, p), '')
520 else:
521 p = s(p)
522 r.append(p)
523 return r
524
525 subst_target_source = subst
526
528 import subprocess
529 if SCons.Util.is_List(command):
530 p = subprocess.Popen(command,
531 stdout=subprocess.PIPE,
532 stderr=subprocess.PIPE,
533 universal_newlines=True)
534 else:
535 p = subprocess.Popen(command,
536 stdout=subprocess.PIPE,
537 stderr=subprocess.PIPE,
538 universal_newlines=True,
539 shell=True)
540 out = p.stdout.read()
541 p.stdout.close()
542 err = p.stderr.read()
543 p.stderr.close()
544 status = p.wait()
545 if err:
546 import sys
547 sys.stderr.write(err)
548 if status:
549 raise OSError("'%s' exited %d" % (command, status))
550 return out
551
553 """
554 Adds the specified function as a method of this construction
555 environment with the specified name. If the name is omitted,
556 the default name is the name of the function itself.
557 """
558 method = MethodWrapper(self, function, name)
559 self.added_methods.append(method)
560
562 """
563 Removes the specified function's MethodWrapper from the
564 added_methods list, so we don't re-bind it when making a clone.
565 """
566 is_not_func = lambda dm, f=function: not dm.method is f
567 self.added_methods = filter(is_not_func, self.added_methods)
568
570 """
571 Produce a modified environment whose variables are overriden by
572 the overrides dictionaries. "overrides" is a dictionary that
573 will override the variables of this environment.
574
575 This function is much more efficient than Clone() or creating
576 a new Environment because it doesn't copy the construction
577 environment dictionary, it just wraps the underlying construction
578 environment, and doesn't even create a wrapper object if there
579 are no overrides.
580 """
581 if not overrides: return self
582 o = copy_non_reserved_keywords(overrides)
583 if not o: return self
584 overrides = {}
585 merges = None
586 for key, value in o.items():
587 if key == 'parse_flags':
588 merges = value
589 else:
590 overrides[key] = SCons.Subst.scons_subst_once(value, self, key)
591 env = OverrideEnvironment(self, overrides)
592 if merges: env.MergeFlags(merges)
593 return env
594
596 """
597 Parse the set of flags and return a dict with the flags placed
598 in the appropriate entry. The flags are treated as a typical
599 set of command-line flags for a GNU-like toolchain and used to
600 populate the entries in the dict immediately below. If one of
601 the flag strings begins with a bang (exclamation mark), it is
602 assumed to be a command and the rest of the string is executed;
603 the result of that evaluation is then added to the dict.
604 """
605 dict = {
606 'ASFLAGS' : SCons.Util.CLVar(''),
607 'CFLAGS' : SCons.Util.CLVar(''),
608 'CCFLAGS' : SCons.Util.CLVar(''),
609 'CPPDEFINES' : [],
610 'CPPFLAGS' : SCons.Util.CLVar(''),
611 'CPPPATH' : [],
612 'FRAMEWORKPATH' : SCons.Util.CLVar(''),
613 'FRAMEWORKS' : SCons.Util.CLVar(''),
614 'LIBPATH' : [],
615 'LIBS' : [],
616 'LINKFLAGS' : SCons.Util.CLVar(''),
617 'RPATH' : [],
618 }
619
620
621
622 def do_parse(arg, me, self = self, dict = dict):
623
624 if not arg:
625 return
626
627 if not SCons.Util.is_String(arg):
628 for t in arg: me(t, me)
629 return
630
631
632 if arg[0] == '!':
633 arg = self.backtick(arg[1:])
634
635
636 def append_define(name, dict = dict):
637 t = string.split(name, '=')
638 if len(t) == 1:
639 dict['CPPDEFINES'].append(name)
640 else:
641 dict['CPPDEFINES'].append([t[0], string.join(t[1:], '=')])
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663 params = shlex.split(arg)
664 append_next_arg_to = None
665 for arg in params:
666 if append_next_arg_to:
667 if append_next_arg_to == 'CPPDEFINES':
668 append_define(arg)
669 elif append_next_arg_to == '-include':
670 t = ('-include', self.fs.File(arg))
671 dict['CCFLAGS'].append(t)
672 elif append_next_arg_to == '-isysroot':
673 t = ('-isysroot', arg)
674 dict['CCFLAGS'].append(t)
675 dict['LINKFLAGS'].append(t)
676 elif append_next_arg_to == '-arch':
677 t = ('-arch', arg)
678 dict['CCFLAGS'].append(t)
679 dict['LINKFLAGS'].append(t)
680 else:
681 dict[append_next_arg_to].append(arg)
682 append_next_arg_to = None
683 elif not arg[0] in ['-', '+']:
684 dict['LIBS'].append(self.fs.File(arg))
685 elif arg[:2] == '-L':
686 if arg[2:]:
687 dict['LIBPATH'].append(arg[2:])
688 else:
689 append_next_arg_to = 'LIBPATH'
690 elif arg[:2] == '-l':
691 if arg[2:]:
692 dict['LIBS'].append(arg[2:])
693 else:
694 append_next_arg_to = 'LIBS'
695 elif arg[:2] == '-I':
696 if arg[2:]:
697 dict['CPPPATH'].append(arg[2:])
698 else:
699 append_next_arg_to = 'CPPPATH'
700 elif arg[:4] == '-Wa,':
701 dict['ASFLAGS'].append(arg[4:])
702 dict['CCFLAGS'].append(arg)
703 elif arg[:4] == '-Wl,':
704 if arg[:11] == '-Wl,-rpath=':
705 dict['RPATH'].append(arg[11:])
706 elif arg[:7] == '-Wl,-R,':
707 dict['RPATH'].append(arg[7:])
708 elif arg[:6] == '-Wl,-R':
709 dict['RPATH'].append(arg[6:])
710 else:
711 dict['LINKFLAGS'].append(arg)
712 elif arg[:4] == '-Wp,':
713 dict['CPPFLAGS'].append(arg)
714 elif arg[:2] == '-D':
715 if arg[2:]:
716 append_define(arg[2:])
717 else:
718 append_next_arg_to = 'CPPDEFINES'
719 elif arg == '-framework':
720 append_next_arg_to = 'FRAMEWORKS'
721 elif arg[:14] == '-frameworkdir=':
722 dict['FRAMEWORKPATH'].append(arg[14:])
723 elif arg[:2] == '-F':
724 if arg[2:]:
725 dict['FRAMEWORKPATH'].append(arg[2:])
726 else:
727 append_next_arg_to = 'FRAMEWORKPATH'
728 elif arg == '-mno-cygwin':
729 dict['CCFLAGS'].append(arg)
730 dict['LINKFLAGS'].append(arg)
731 elif arg == '-mwindows':
732 dict['LINKFLAGS'].append(arg)
733 elif arg == '-pthread':
734 dict['CCFLAGS'].append(arg)
735 dict['LINKFLAGS'].append(arg)
736 elif arg[:5] == '-std=':
737 dict['CFLAGS'].append(arg)
738 elif arg[0] == '+':
739 dict['CCFLAGS'].append(arg)
740 dict['LINKFLAGS'].append(arg)
741 elif arg in ['-include', '-isysroot', '-arch']:
742 append_next_arg_to = arg
743 else:
744 dict['CCFLAGS'].append(arg)
745
746 for arg in flags:
747 do_parse(arg, do_parse)
748 return dict
749
751 """
752 Merge the dict in args into the construction variables. If args
753 is not a dict, it is converted into a dict using ParseFlags.
754 If unique is not set, the flags are appended rather than merged.
755 """
756
757 if not SCons.Util.is_Dict(args):
758 args = self.ParseFlags(args)
759 if not unique:
760 apply(self.Append, (), args)
761 return self
762 for key, value in args.items():
763 if not value:
764 continue
765 try:
766 orig = self[key]
767 except KeyError:
768 orig = value
769 else:
770 if not orig:
771 orig = value
772 elif value:
773
774
775
776
777
778
779 try:
780 orig = orig + value
781 except (KeyError, TypeError):
782 try:
783 add_to_orig = orig.append
784 except AttributeError:
785 value.insert(0, orig)
786 orig = value
787 else:
788 add_to_orig(value)
789 t = []
790 if key[-4:] == 'PATH':
791
792 for v in orig:
793 if v not in t:
794 t.append(v)
795 else:
796
797 orig.reverse()
798 for v in orig:
799 if v not in t:
800 t.insert(0, v)
801 self[key] = t
802 return self
803
804
805
814
818
822
824 f = SCons.Defaults.DefaultEnvironment().copy_from_cache
825 return f(src, dst)
826
827 -class Base(SubstitutionEnvironment):
828 """Base class for "real" construction Environments. These are the
829 primary objects used to communicate dependency and construction
830 information to the build engine.
831
832 Keyword arguments supplied when the construction Environment
833 is created are construction variables used to initialize the
834 Environment.
835 """
836
837 if SCons.Memoize.use_memoizer:
838 __metaclass__ = SCons.Memoize.Memoized_Metaclass
839
840 memoizer_counters = []
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856 - def __init__(self,
857 platform=None,
858 tools=None,
859 toolpath=None,
860 options=None,
861 parse_flags = None,
862 **kw):
863 """
864 Initialization of a basic SCons construction environment,
865 including setting up special construction variables like BUILDER,
866 PLATFORM, etc., and searching for and applying available Tools.
867
868 Note that we do *not* call the underlying base class
869 (SubsitutionEnvironment) initialization, because we need to
870 initialize things in a very specific order that doesn't work
871 with the much simpler base class initialization.
872 """
873 if __debug__: logInstanceCreation(self, 'Environment.Base')
874 self._memo = {}
875 self.fs = SCons.Node.FS.get_default_fs()
876 self.ans = SCons.Node.Alias.default_ans
877 self.lookup_list = SCons.Node.arg2nodes_lookups
878 self._dict = semi_deepcopy(SCons.Defaults.ConstructionEnvironment)
879 self._init_special()
880 self.added_methods = []
881
882
883
884
885
886
887
888 self.decide_target = default_decide_target
889 self.decide_source = default_decide_source
890
891 self.copy_from_cache = default_copy_from_cache
892
893 self._dict['BUILDERS'] = BuilderDict(self._dict['BUILDERS'], self)
894
895 if platform is None:
896 platform = self._dict.get('PLATFORM', None)
897 if platform is None:
898 platform = SCons.Platform.Platform()
899 if SCons.Util.is_String(platform):
900 platform = SCons.Platform.Platform(platform)
901 self._dict['PLATFORM'] = str(platform)
902 platform(self)
903
904
905
906
907 apply(self.Replace, (), kw)
908 keys = kw.keys()
909 if options:
910 keys = keys + options.keys()
911 options.Update(self)
912
913 save = {}
914 for k in keys:
915 try:
916 save[k] = self._dict[k]
917 except KeyError:
918
919
920 pass
921
922 SCons.Tool.Initializers(self)
923
924 if tools is None:
925 tools = self._dict.get('TOOLS', None)
926 if tools is None:
927 tools = ['default']
928 apply_tools(self, tools, toolpath)
929
930
931
932
933 for key, val in save.items():
934 self._dict[key] = val
935
936
937 if parse_flags: self.MergeFlags(parse_flags)
938
939
940
941
942
943
945 """Fetch the builder with the specified name from the environment.
946 """
947 try:
948 return self._dict['BUILDERS'][name]
949 except KeyError:
950 return None
951
953 try:
954 path = self._CacheDir_path
955 except AttributeError:
956 path = SCons.Defaults.DefaultEnvironment()._CacheDir_path
957 try:
958 if path == self._last_CacheDir_path:
959 return self._last_CacheDir
960 except AttributeError:
961 pass
962 cd = SCons.CacheDir.CacheDir(path)
963 self._last_CacheDir_path = path
964 self._last_CacheDir = cd
965 return cd
966
968 """Return a factory function for creating Nodes for this
969 construction environment.
970 """
971 name = default
972 try:
973 is_node = issubclass(factory, SCons.Node.Node)
974 except TypeError:
975
976
977 pass
978 else:
979 if is_node:
980
981
982
983
984 try: name = factory.__name__
985 except AttributeError: pass
986 else: factory = None
987 if not factory:
988
989
990
991
992
993 factory = getattr(self.fs, name)
994 return factory
995
996 memoizer_counters.append(SCons.Memoize.CountValue('_gsm'))
997
999 try:
1000 return self._memo['_gsm']
1001 except KeyError:
1002 pass
1003
1004 result = {}
1005
1006 try:
1007 scanners = self._dict['SCANNERS']
1008 except KeyError:
1009 pass
1010 else:
1011
1012
1013
1014
1015 if not SCons.Util.is_List(scanners):
1016 scanners = [scanners]
1017 else:
1018 scanners = scanners[:]
1019 scanners.reverse()
1020 for scanner in scanners:
1021 for k in scanner.get_skeys(self):
1022 result[k] = scanner
1023
1024 self._memo['_gsm'] = result
1025
1026 return result
1027
1029 """Find the appropriate scanner given a key (usually a file suffix).
1030 """
1031 return self._gsm().get(skey)
1032
1034 """Delete the cached scanner map (if we need to).
1035 """
1036 try:
1037 del self._memo['_gsm']
1038 except KeyError:
1039 pass
1040
1042 """Update an environment's values directly, bypassing the normal
1043 checks that occur when users try to set items.
1044 """
1045 self._dict.update(dict)
1046
1048 try:
1049 return self.src_sig_type
1050 except AttributeError:
1051 t = SCons.Defaults.DefaultEnvironment().src_sig_type
1052 self.src_sig_type = t
1053 return t
1054
1056 try:
1057 return self.tgt_sig_type
1058 except AttributeError:
1059 t = SCons.Defaults.DefaultEnvironment().tgt_sig_type
1060 self.tgt_sig_type = t
1061 return t
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1073 """Append values to existing construction variables
1074 in an Environment.
1075 """
1076 kw = copy_non_reserved_keywords(kw)
1077 for key, val in kw.items():
1078
1079
1080
1081
1082 try:
1083 orig = self._dict[key]
1084 except KeyError:
1085
1086
1087 self._dict[key] = val
1088 else:
1089 try:
1090
1091
1092
1093
1094
1095 update_dict = orig.update
1096 except AttributeError:
1097 try:
1098
1099
1100
1101 self._dict[key] = orig + val
1102 except (KeyError, TypeError):
1103 try:
1104
1105 add_to_orig = orig.append
1106 except AttributeError:
1107
1108
1109
1110
1111
1112 if orig:
1113 val.insert(0, orig)
1114 self._dict[key] = val
1115 else:
1116
1117
1118 if val:
1119 add_to_orig(val)
1120 else:
1121
1122
1123 if SCons.Util.is_List(val):
1124 for v in val:
1125 orig[v] = None
1126 else:
1127 try:
1128 update_dict(val)
1129 except (AttributeError, TypeError, ValueError):
1130 if SCons.Util.is_Dict(val):
1131 for k, v in val.items():
1132 orig[k] = v
1133 else:
1134 orig[val] = None
1135 self.scanner_map_delete(kw)
1136
1137 - def AppendENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep):
1138 """Append path elements to the path 'name' in the 'ENV'
1139 dictionary for this environment. Will only add any particular
1140 path once, and will normpath and normcase all paths to help
1141 assure this. This can also handle the case where the env
1142 variable is a list instead of a string.
1143 """
1144
1145 orig = ''
1146 if self._dict.has_key(envname) and self._dict[envname].has_key(name):
1147 orig = self._dict[envname][name]
1148
1149 nv = SCons.Util.AppendPath(orig, newpath, sep)
1150
1151 if not self._dict.has_key(envname):
1152 self._dict[envname] = {}
1153
1154 self._dict[envname][name] = nv
1155
1157 """Append values to existing construction variables
1158 in an Environment, if they're not already there.
1159 """
1160 kw = copy_non_reserved_keywords(kw)
1161 for key, val in kw.items():
1162 if not self._dict.has_key(key) or self._dict[key] in ('', None):
1163 self._dict[key] = val
1164 elif SCons.Util.is_Dict(self._dict[key]) and \
1165 SCons.Util.is_Dict(val):
1166 self._dict[key].update(val)
1167 elif SCons.Util.is_List(val):
1168 dk = self._dict[key]
1169 if not SCons.Util.is_List(dk):
1170 dk = [dk]
1171 val = filter(lambda x, dk=dk: x not in dk, val)
1172 self._dict[key] = dk + val
1173 else:
1174 dk = self._dict[key]
1175 if SCons.Util.is_List(dk):
1176
1177
1178 if not val in dk:
1179 self._dict[key] = dk + [val]
1180 else:
1181 self._dict[key] = self._dict[key] + val
1182 self.scanner_map_delete(kw)
1183
1184 - def Clone(self, tools=[], toolpath=None, parse_flags = None, **kw):
1185 """Return a copy of a construction Environment. The
1186 copy is like a Python "deep copy"--that is, independent
1187 copies are made recursively of each objects--except that
1188 a reference is copied when an object is not deep-copyable
1189 (like a function). There are no references to any mutable
1190 objects in the original Environment.
1191 """
1192 clone = copy.copy(self)
1193 clone._dict = semi_deepcopy(self._dict)
1194
1195 try:
1196 cbd = clone._dict['BUILDERS']
1197 except KeyError:
1198 pass
1199 else:
1200 clone._dict['BUILDERS'] = BuilderDict(cbd, clone)
1201
1202
1203
1204
1205
1206 clone.added_methods = []
1207 for mw in self.added_methods:
1208 if mw == getattr(self, mw.name):
1209 clone.added_methods.append(mw.clone(clone))
1210
1211 clone._memo = {}
1212
1213
1214
1215 kw = copy_non_reserved_keywords(kw)
1216 new = {}
1217 for key, value in kw.items():
1218 new[key] = SCons.Subst.scons_subst_once(value, self, key)
1219 apply(clone.Replace, (), new)
1220
1221 apply_tools(clone, tools, toolpath)
1222
1223
1224 apply(clone.Replace, (), new)
1225
1226
1227 if parse_flags: clone.MergeFlags(parse_flags)
1228
1229 if __debug__: logInstanceCreation(self, 'Environment.EnvironmentClone')
1230 return clone
1231
1232 - def Copy(self, *args, **kw):
1239
1244
1245 - def _changed_content(self, dependency, target, prev_ni):
1246 return dependency.changed_content(target, prev_ni)
1247
1255
1256 - def _changed_timestamp_then_content(self, dependency, target, prev_ni):
1257 return dependency.changed_timestamp_then_content(target, prev_ni)
1258
1261
1264
1266 return self.fs.copy(src, dst)
1267
1269 return self.fs.copy2(src, dst)
1270
1294
1296 """Return the first available program in progs.
1297 """
1298 if not SCons.Util.is_List(progs):
1299 progs = [ progs ]
1300 for prog in progs:
1301 path = self.WhereIs(prog)
1302 if path: return prog
1303 return None
1304
1306 if not args:
1307 return self._dict
1308 dlist = map(lambda x, s=self: s._dict[x], args)
1309 if len(dlist) == 1:
1310 dlist = dlist[0]
1311 return dlist
1312
1313 - def Dump(self, key = None):
1314 """
1315 Using the standard Python pretty printer, dump the contents of the
1316 scons build environment to stdout.
1317
1318 If the key passed in is anything other than None, then that will
1319 be used as an index into the build environment dictionary and
1320 whatever is found there will be fed into the pretty printer. Note
1321 that this key is case sensitive.
1322 """
1323 import pprint
1324 pp = pprint.PrettyPrinter(indent=2)
1325 if key:
1326 dict = self.Dictionary(key)
1327 else:
1328 dict = self.Dictionary()
1329 return pp.pformat(dict)
1330
1331 - def FindIxes(self, paths, prefix, suffix):
1332 """
1333 Search a list of paths for something that matches the prefix and suffix.
1334
1335 paths - the list of paths or nodes.
1336 prefix - construction variable for the prefix.
1337 suffix - construction variable for the suffix.
1338 """
1339
1340 suffix = self.subst('$'+suffix)
1341 prefix = self.subst('$'+prefix)
1342
1343 for path in paths:
1344 dir,name = os.path.split(str(path))
1345 if name[:len(prefix)] == prefix and name[-len(suffix):] == suffix:
1346 return path
1347
1348 - def ParseConfig(self, command, function=None, unique=1):
1349 """
1350 Use the specified function to parse the output of the command
1351 in order to modify the current environment. The 'command' can
1352 be a string or a list of strings representing a command and
1353 its arguments. 'Function' is an optional argument that takes
1354 the environment, the output of the command, and the unique flag.
1355 If no function is specified, MergeFlags, which treats the output
1356 as the result of a typical 'X-config' command (i.e. gtk-config),
1357 will merge the output into the appropriate variables.
1358 """
1359 if function is None:
1360 def parse_conf(env, cmd, unique=unique):
1361 return env.MergeFlags(cmd, unique)
1362 function = parse_conf
1363 if SCons.Util.is_List(command):
1364 command = string.join(command)
1365 command = self.subst(command)
1366 return function(self, self.backtick(command))
1367
1368 - def ParseDepends(self, filename, must_exist=None, only_one=0):
1369 """
1370 Parse a mkdep-style file for explicit dependencies. This is
1371 completely abusable, and should be unnecessary in the "normal"
1372 case of proper SCons configuration, but it may help make
1373 the transition from a Make hierarchy easier for some people
1374 to swallow. It can also be genuinely useful when using a tool
1375 that can write a .d file, but for which writing a scanner would
1376 be too complicated.
1377 """
1378 filename = self.subst(filename)
1379 try:
1380 fp = open(filename, 'r')
1381 except IOError:
1382 if must_exist:
1383 raise
1384 return
1385 lines = SCons.Util.LogicalLines(fp).readlines()
1386 lines = filter(lambda l: l[0] != '#', lines)
1387 tdlist = []
1388 for line in lines:
1389 try:
1390 target, depends = string.split(line, ':', 1)
1391 except (AttributeError, TypeError, ValueError):
1392
1393
1394
1395
1396 pass
1397 else:
1398 tdlist.append((string.split(target), string.split(depends)))
1399 if only_one:
1400 targets = reduce(lambda x, y: x+y, map(lambda p: p[0], tdlist))
1401 if len(targets) > 1:
1402 raise SCons.Errors.UserError, "More than one dependency target found in `%s': %s" % (filename, targets)
1403 for target, depends in tdlist:
1404 self.Depends(target, depends)
1405
1409
1411 """Prepend values to existing construction variables
1412 in an Environment.
1413 """
1414 kw = copy_non_reserved_keywords(kw)
1415 for key, val in kw.items():
1416
1417
1418
1419
1420 try:
1421 orig = self._dict[key]
1422 except KeyError:
1423
1424
1425 self._dict[key] = val
1426 else:
1427 try:
1428
1429
1430
1431
1432
1433 update_dict = orig.update
1434 except AttributeError:
1435 try:
1436
1437
1438
1439 self._dict[key] = val + orig
1440 except (KeyError, TypeError):
1441 try:
1442
1443 add_to_val = val.append
1444 except AttributeError:
1445
1446
1447
1448
1449 if val:
1450 orig.insert(0, val)
1451 else:
1452
1453
1454
1455 if orig:
1456 add_to_val(orig)
1457 self._dict[key] = val
1458 else:
1459
1460
1461 if SCons.Util.is_List(val):
1462 for v in val:
1463 orig[v] = None
1464 else:
1465 try:
1466 update_dict(val)
1467 except (AttributeError, TypeError, ValueError):
1468 if SCons.Util.is_Dict(val):
1469 for k, v in val.items():
1470 orig[k] = v
1471 else:
1472 orig[val] = None
1473 self.scanner_map_delete(kw)
1474
1475 - def PrependENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep):
1476 """Prepend path elements to the path 'name' in the 'ENV'
1477 dictionary for this environment. Will only add any particular
1478 path once, and will normpath and normcase all paths to help
1479 assure this. This can also handle the case where the env
1480 variable is a list instead of a string.
1481 """
1482
1483 orig = ''
1484 if self._dict.has_key(envname) and self._dict[envname].has_key(name):
1485 orig = self._dict[envname][name]
1486
1487 nv = SCons.Util.PrependPath(orig, newpath, sep)
1488
1489 if not self._dict.has_key(envname):
1490 self._dict[envname] = {}
1491
1492 self._dict[envname][name] = nv
1493
1495 """Append values to existing construction variables
1496 in an Environment, if they're not already there.
1497 """
1498 kw = copy_non_reserved_keywords(kw)
1499 for key, val in kw.items():
1500 if not self._dict.has_key(key) or self._dict[key] in ('', None):
1501 self._dict[key] = val
1502 elif SCons.Util.is_Dict(self._dict[key]) and \
1503 SCons.Util.is_Dict(val):
1504 self._dict[key].update(val)
1505 elif SCons.Util.is_List(val):
1506 dk = self._dict[key]
1507 if not SCons.Util.is_List(dk):
1508 dk = [dk]
1509 val = filter(lambda x, dk=dk: x not in dk, val)
1510 self._dict[key] = val + dk
1511 else:
1512 dk = self._dict[key]
1513 if SCons.Util.is_List(dk):
1514
1515
1516 if not val in dk:
1517 self._dict[key] = [val] + dk
1518 else:
1519 self._dict[key] = val + dk
1520 self.scanner_map_delete(kw)
1521
1523 """Replace existing construction variables in an Environment
1524 with new construction variables and/or values.
1525 """
1526 try:
1527 kwbd = kw['BUILDERS']
1528 except KeyError:
1529 pass
1530 else:
1531 kwbd = semi_deepcopy(kwbd)
1532 del kw['BUILDERS']
1533 self.__setitem__('BUILDERS', kwbd)
1534 kw = copy_non_reserved_keywords(kw)
1535 self._update(semi_deepcopy(kw))
1536 self.scanner_map_delete(kw)
1537
1538 - def ReplaceIxes(self, path, old_prefix, old_suffix, new_prefix, new_suffix):
1539 """
1540 Replace old_prefix with new_prefix and old_suffix with new_suffix.
1541
1542 env - Environment used to interpolate variables.
1543 path - the path that will be modified.
1544 old_prefix - construction variable for the old prefix.
1545 old_suffix - construction variable for the old suffix.
1546 new_prefix - construction variable for the new prefix.
1547 new_suffix - construction variable for the new suffix.
1548 """
1549 old_prefix = self.subst('$'+old_prefix)
1550 old_suffix = self.subst('$'+old_suffix)
1551
1552 new_prefix = self.subst('$'+new_prefix)
1553 new_suffix = self.subst('$'+new_suffix)
1554
1555 dir,name = os.path.split(str(path))
1556 if name[:len(old_prefix)] == old_prefix:
1557 name = name[len(old_prefix):]
1558 if name[-len(old_suffix):] == old_suffix:
1559 name = name[:-len(old_suffix)]
1560 return os.path.join(dir, new_prefix+name+new_suffix)
1561
1563 for k in kw.keys():
1564 if self._dict.has_key(k):
1565 del kw[k]
1566 apply(self.Replace, (), kw)
1567
1570
1579
1580 - def WhereIs(self, prog, path=None, pathext=None, reject=[]):
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609 - def Action(self, *args, **kw):
1614 nargs = map(subst_string, args)
1615 nkw = self.subst_kw(kw)
1616 return apply(SCons.Action.Action, nargs, nkw)
1617
1627
1628 - def AddPostAction(self, files, action):
1629 nodes = self.arg2nodes(files, self.fs.Entry)
1630 action = SCons.Action.Action(action)
1631 uniq = {}
1632 for executor in map(lambda n: n.get_executor(), nodes):
1633 uniq[executor] = 1
1634 for executor in uniq.keys():
1635 executor.add_post_action(action)
1636 return nodes
1637
1638 - def Alias(self, target, source=[], action=None, **kw):
1639 tlist = self.arg2nodes(target, self.ans.Alias)
1640 if not SCons.Util.is_List(source):
1641 source = [source]
1642 source = filter(None, source)
1643
1644 if not action:
1645 if not source:
1646
1647
1648
1649
1650
1651
1652 return tlist
1653
1654
1655
1656 result = []
1657 for t in tlist:
1658 bld = t.get_builder(AliasBuilder)
1659 result.extend(bld(self, t, source))
1660 return result
1661
1662 nkw = self.subst_kw(kw)
1663 nkw.update({
1664 'action' : SCons.Action.Action(action),
1665 'source_factory' : self.fs.Entry,
1666 'multi' : 1,
1667 'is_explicit' : None,
1668 })
1669 bld = apply(SCons.Builder.Builder, (), nkw)
1670
1671
1672
1673
1674
1675 result = []
1676 for t in tlist:
1677
1678
1679
1680
1681 b = t.get_builder()
1682 if b is None or b is AliasBuilder:
1683 b = bld
1684 else:
1685 nkw['action'] = b.action + action
1686 b = apply(SCons.Builder.Builder, (), nkw)
1687 t.convert()
1688 result.extend(b(self, t, t.sources + source))
1689 return result
1690
1698
1700 if kw.has_key('build_dir'):
1701 kw['variant_dir'] = kw['build_dir']
1702 del kw['build_dir']
1703 return apply(self.VariantDir, args, kw)
1704
1708
1714
1715 - def Clean(self, targets, files):
1724
1736
1737 - def Command(self, target, source, action, **kw):
1738 """Builds the supplied target files from the supplied
1739 source files using the supplied action. Action may
1740 be any type that the Builder constructor will accept
1741 for an action."""
1742 bkw = {
1743 'action' : action,
1744 'target_factory' : self.fs.Entry,
1745 'source_factory' : self.fs.Entry,
1746 }
1747 try: bkw['source_scanner'] = kw['source_scanner']
1748 except KeyError: pass
1749 else: del kw['source_scanner']
1750 bld = apply(SCons.Builder.Builder, (), bkw)
1751 return apply(bld, (self, target, source), kw)
1752
1753 - def Depends(self, target, dependency):
1754 """Explicity specify that 'target's depend on 'dependency'."""
1755 tlist = self.arg2nodes(target, self.fs.Entry)
1756 dlist = self.arg2nodes(dependency, self.fs.Entry)
1757 for t in tlist:
1758 t.add_dependency(dlist)
1759 return tlist
1760
1761 - def Dir(self, name, *args, **kw):
1771
1773 """Tags a target so that it will not be cleaned by -c"""
1774 tlist = []
1775 for t in targets:
1776 tlist.extend(self.arg2nodes(t, self.fs.Entry))
1777 for t in tlist:
1778 t.set_noclean()
1779 return tlist
1780
1782 """Tags a target so that it will not be cached"""
1783 tlist = []
1784 for t in targets:
1785 tlist.extend(self.arg2nodes(t, self.fs.Entry))
1786 for t in tlist:
1787 t.set_nocache()
1788 return tlist
1789
1790 - def Entry(self, name, *args, **kw):
1791 """
1792 """
1793 s = self.subst(name)
1794 if SCons.Util.is_Sequence(s):
1795 result=[]
1796 for e in s:
1797 result.append(apply(self.fs.Entry, (e,) + args, kw))
1798 return result
1799 return apply(self.fs.Entry, (s,) + args, kw)
1800
1803
1804 - def Execute(self, action, *args, **kw):
1805 """Directly execute an action through an Environment
1806 """
1807 action = apply(self.Action, (action,) + args, kw)
1808 result = action([], [], self)
1809 if isinstance(result, SCons.Errors.BuildError):
1810 return result.status
1811 else:
1812 return result
1813
1814 - def File(self, name, *args, **kw):
1824
1829
1832
1839
1841 return self.fs.Glob(self.subst(pattern), ondisk, source, strings)
1842
1843 - def Ignore(self, target, dependency):
1850
1853
1854 - def Local(self, *targets):
1865
1873
1877
1878 - def Requires(self, target, prerequisite):
1879 """Specify that 'prerequisite' must be built before 'target',
1880 (but 'target' does not actually depend on 'prerequisite'
1881 and need not be rebuilt if it changes)."""
1882 tlist = self.arg2nodes(target, self.fs.Entry)
1883 plist = self.arg2nodes(prerequisite, self.fs.Entry)
1884 for t in tlist:
1885 t.add_prerequisite(plist)
1886 return tlist
1887
1896
1897 - def SConsignFile(self, name=".sconsign", dbm_module=None):
1898 if not name is None:
1899 name = self.subst(name)
1900 if not os.path.isabs(name):
1901 name = os.path.join(str(self.fs.SConstruct_dir), name)
1902 SCons.SConsign.File(name, dbm_module)
1903
1905 """Tell scons that side_effects are built as side
1906 effects of building targets."""
1907 side_effects = self.arg2nodes(side_effect, self.fs.Entry)
1908 targets = self.arg2nodes(target, self.fs.Entry)
1909
1910 for side_effect in side_effects:
1911 if side_effect.multiple_side_effect_has_builder():
1912 raise SCons.Errors.UserError, "Multiple ways to build the same target were specified for: %s" % str(side_effect)
1913 side_effect.add_source(targets)
1914 side_effect.side_effect = 1
1915 self.Precious(side_effect)
1916 for target in targets:
1917 target.side_effects.append(side_effect)
1918 return side_effects
1919
1921 """Arrange for a source code builder for (part of) a tree."""
1922 entries = self.arg2nodes(entry, self.fs.Entry)
1923 for entry in entries:
1924 entry.set_src_builder(builder)
1925 return entries
1926
1944
1946 """This function converts a string or list into a list of strings
1947 or Nodes. This makes things easier for users by allowing files to
1948 be specified as a white-space separated list to be split.
1949 The input rules are:
1950 - A single string containing names separated by spaces. These will be
1951 split apart at the spaces.
1952 - A single Node instance
1953 - A list containing either strings or Node instances. Any strings
1954 in the list are not split at spaces.
1955 In all cases, the function returns a list of Nodes and strings."""
1956 if SCons.Util.is_List(arg):
1957 return map(self.subst, arg)
1958 elif SCons.Util.is_String(arg):
1959 return string.split(self.subst(arg))
1960 else:
1961 return [self.subst(arg)]
1962
1984
1985 - def Value(self, value, built_value=None):
1989
1990 - def VariantDir(self, variant_dir, src_dir, duplicate=1):
1994
2020
2021
2022
2023 map( get_final_srcnode, sources )
2024
2025
2026 return list(set(sources))
2027
2029 """ returns the list of all targets of the Install and InstallAs Builder.
2030 """
2031 from SCons.Tool import install
2032 if install._UNIQUE_INSTALLED_FILES is None:
2033 install._UNIQUE_INSTALLED_FILES = SCons.Util.uniquer_hashables(install._INSTALLED_FILES)
2034 return install._UNIQUE_INSTALLED_FILES
2035
2037 """A proxy that overrides variables in a wrapped construction
2038 environment by returning values from an overrides dictionary in
2039 preference to values from the underlying subject environment.
2040
2041 This is a lightweight (I hope) proxy that passes through most use of
2042 attributes to the underlying Environment.Base class, but has just
2043 enough additional methods defined to act like a real construction
2044 environment with overridden values. It can wrap either a Base
2045 construction environment, or another OverrideEnvironment, which
2046 can in turn nest arbitrary OverrideEnvironments...
2047
2048 Note that we do *not* call the underlying base class
2049 (SubsitutionEnvironment) initialization, because we get most of those
2050 from proxying the attributes of the subject construction environment.
2051 But because we subclass SubstitutionEnvironment, this class also
2052 has inherited arg2nodes() and subst*() methods; those methods can't
2053 be proxied because they need *this* object's methods to fetch the
2054 values from the overrides dictionary.
2055 """
2056
2057 if SCons.Memoize.use_memoizer:
2058 __metaclass__ = SCons.Memoize.Memoized_Metaclass
2059
2060 - def __init__(self, subject, overrides={}):
2061 if __debug__: logInstanceCreation(self, 'Environment.OverrideEnvironment')
2062 self.__dict__['__subject'] = subject
2063 self.__dict__['overrides'] = overrides
2064
2065
2067 return getattr(self.__dict__['__subject'], name)
2069 setattr(self.__dict__['__subject'], name, value)
2070
2071
2073 try:
2074 return self.__dict__['overrides'][key]
2075 except KeyError:
2076 return self.__dict__['__subject'].__getitem__(key)
2082 try:
2083 del self.__dict__['overrides'][key]
2084 except KeyError:
2085 deleted = 0
2086 else:
2087 deleted = 1
2088 try:
2089 result = self.__dict__['__subject'].__delitem__(key)
2090 except KeyError:
2091 if not deleted:
2092 raise
2093 result = None
2094 return result
2095 - def get(self, key, default=None):
2096 """Emulates the get() method of dictionaries."""
2097 try:
2098 return self.__dict__['overrides'][key]
2099 except KeyError:
2100 return self.__dict__['__subject'].get(key, default)
2102 try:
2103 self.__dict__['overrides'][key]
2104 return 1
2105 except KeyError:
2106 return self.__dict__['__subject'].has_key(key)
2108 """Emulates the items() method of dictionaries."""
2109 d = self.__dict__['__subject'].Dictionary().copy()
2110 d.update(self.__dict__['overrides'])
2111 return d
2113 """Emulates the items() method of dictionaries."""
2114 return self.Dictionary().items()
2115
2116
2118 """Update an environment's values directly, bypassing the normal
2119 checks that occur when users try to set items.
2120 """
2121 self.__dict__['overrides'].update(dict)
2122
2124 return self.__dict__['__subject'].gvars()
2125
2130
2131
2135
2136
2137
2138
2139
2140
2141
2142 Environment = Base
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2157 class _NoSubstitutionProxy(Environment):
2158 def __init__(self, subject):
2159 self.__dict__['__subject'] = subject
2160 def __getattr__(self, name):
2161 return getattr(self.__dict__['__subject'], name)
2162 def __setattr__(self, name, value):
2163 return setattr(self.__dict__['__subject'], name, value)
2164 def raw_to_mode(self, dict):
2165 try:
2166 raw = dict['raw']
2167 except KeyError:
2168 pass
2169 else:
2170 del dict['raw']
2171 dict['mode'] = raw
2172 def subst(self, string, *args, **kwargs):
2173 return string
2174 def subst_kw(self, kw, *args, **kwargs):
2175 return kw
2176 def subst_list(self, string, *args, **kwargs):
2177 nargs = (string, self,) + args
2178 nkw = kwargs.copy()
2179 nkw['gvars'] = {}
2180 self.raw_to_mode(nkw)
2181 return apply(SCons.Subst.scons_subst_list, nargs, nkw)
2182 def subst_target_source(self, string, *args, **kwargs):
2183 nargs = (string, self,) + args
2184 nkw = kwargs.copy()
2185 nkw['gvars'] = {}
2186 self.raw_to_mode(nkw)
2187 return apply(SCons.Subst.scons_subst, nargs, nkw)
2188 return _NoSubstitutionProxy(subject)
2189