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 __revision__ = "src/engine/SCons/Environment.py 2014/09/27 12:51:43 garyo"
35
36
37 import copy
38 import os
39 import sys
40 import re
41 import shlex
42 from collections import UserDict
43
44 import SCons.Action
45 import SCons.Builder
46 import SCons.Debug
47 from SCons.Debug import logInstanceCreation
48 import SCons.Defaults
49 import SCons.Errors
50 import SCons.Memoize
51 import SCons.Node
52 import SCons.Node.Alias
53 import SCons.Node.FS
54 import SCons.Node.Python
55 import SCons.Platform
56 import SCons.SConf
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 semi_deepcopy_dict = SCons.Util.semi_deepcopy_dict
77
78
79
80
81 UserError = SCons.Errors.UserError
82
85
86 AliasBuilder = SCons.Builder.Builder(action = alias_builder,
87 target_factory = SCons.Node.Alias.default_ans.Alias,
88 source_factory = SCons.Node.FS.Entry,
89 multi = 1,
90 is_explicit = None,
91 name='AliasBuilder')
92
108
109
110
111
112 reserved_construction_var_names = [
113 'CHANGED_SOURCES',
114 'CHANGED_TARGETS',
115 'SOURCE',
116 'SOURCES',
117 'TARGET',
118 'TARGETS',
119 'UNCHANGED_SOURCES',
120 'UNCHANGED_TARGETS',
121 ]
122
123 future_reserved_construction_var_names = [
124
125
126
127 ]
128
137
141
146
159
163
167
169 """Delete duplicates from a sequence, keeping the first or last."""
170 seen={}
171 result=[]
172 if keep_last:
173 l.reverse()
174 for i in l:
175 try:
176 if i not in seen:
177 result.append(i)
178 seen[i]=1
179 except TypeError:
180
181 result.append(i)
182 if keep_last:
183 result.reverse()
184 return result
185
186
187
188
189
190
191
192
193
194
195
196
197
198
200 """
201 A generic Wrapper class that associates a method (which can
202 actually be any callable) with an object. As part of creating this
203 MethodWrapper object an attribute with the specified (by default,
204 the name of the supplied method) is added to the underlying object.
205 When that new "method" is called, our __call__() method adds the
206 object as the first argument, simulating the Python behavior of
207 supplying "self" on method calls.
208
209 We hang on to the name by which the method was added to the underlying
210 base class so that we can provide a method to "clone" ourselves onto
211 a new underlying object being copied (without which we wouldn't need
212 to save that info).
213 """
214 - def __init__(self, object, method, name=None):
215 if name is None:
216 name = method.__name__
217 self.object = object
218 self.method = method
219 self.name = name
220 setattr(self.object, name, self)
221
223 nargs = (self.object,) + args
224 return self.method(*nargs, **kwargs)
225
226 - def clone(self, new_object):
227 """
228 Returns an object that re-binds the underlying "method" to
229 the specified new object.
230 """
231 return self.__class__(new_object, self.method, self.name)
232
234 """
235 A MethodWrapper subclass that that associates an environment with
236 a Builder.
237
238 This mainly exists to wrap the __call__() function so that all calls
239 to Builders can have their argument lists massaged in the same way
240 (treat a lone argument as the source, treat two arguments as target
241 then source, make sure both target and source are lists) without
242 having to have cut-and-paste code to do it.
243
244 As a bit of obsessive backwards compatibility, we also intercept
245 attempts to get or set the "env" or "builder" attributes, which were
246 the names we used before we put the common functionality into the
247 MethodWrapper base class. We'll keep this around for a while in case
248 people shipped Tool modules that reached into the wrapper (like the
249 Tool/qt.py module does, or did). There shouldn't be a lot attribute
250 fetching or setting on these, so a little extra work shouldn't hurt.
251 """
253 if source is _null:
254 source = target
255 target = None
256 if target is not None and not SCons.Util.is_List(target):
257 target = [target]
258 if source is not None and not SCons.Util.is_List(source):
259 source = [source]
260 return MethodWrapper.__call__(self, target, source, *args, **kw)
261
263 return '<BuilderWrapper %s>' % repr(self.name)
264
267
269 if name == 'env':
270 return self.object
271 elif name == 'builder':
272 return self.method
273 else:
274 raise AttributeError(name)
275
277 if name == 'env':
278 self.object = value
279 elif name == 'builder':
280 self.method = value
281 else:
282 self.__dict__[name] = value
283
284
285
286
287
288
289
290
291
292
293
294
296 """This is a dictionary-like class used by an Environment to hold
297 the Builders. We need to do this because every time someone changes
298 the Builders in the Environment's BUILDERS dictionary, we must
299 update the Environment's attributes."""
301
302
303
304 self.env = env
305 UserDict.__init__(self, dict)
306
308
309
310 raise TypeError( 'cannot semi_deepcopy a BuilderDict' )
311
313 try:
314 method = getattr(self.env, item).method
315 except AttributeError:
316 pass
317 else:
318 self.env.RemoveMethod(method)
319 UserDict.__setitem__(self, item, val)
320 BuilderWrapper(self.env, val, item)
321
323 UserDict.__delitem__(self, item)
324 delattr(self.env, item)
325
329
330
331
332 _is_valid_var = re.compile(r'[_a-zA-Z]\w*$')
333
335 """Return if the specified string is a legitimate construction
336 variable.
337 """
338 return _is_valid_var.match(varstr)
339
340
341
343 """Base class for different flavors of construction environments.
344
345 This class contains a minimal set of methods that handle contruction
346 variable expansion and conversion of strings to Nodes, which may or
347 may not be actually useful as a stand-alone class. Which methods
348 ended up in this class is pretty arbitrary right now. They're
349 basically the ones which we've empirically determined are common to
350 the different construction environment subclasses, and most of the
351 others that use or touch the underlying dictionary of construction
352 variables.
353
354 Eventually, this class should contain all the methods that we
355 determine are necessary for a "minimal" interface to the build engine.
356 A full "native Python" SCons environment has gotten pretty heavyweight
357 with all of the methods and Tools and construction variables we've
358 jammed in there, so it would be nice to have a lighter weight
359 alternative for interfaces that don't need all of the bells and
360 whistles. (At some point, we'll also probably rename this class
361 "Base," since that more reflects what we want this class to become,
362 but because we've released comments that tell people to subclass
363 Environment.Base to create their own flavors of construction
364 environment, we'll save that for a future refactoring when this
365 class actually becomes useful.)
366 """
367
368 if SCons.Memoize.use_memoizer:
369 __metaclass__ = SCons.Memoize.Memoized_Metaclass
370
381
382
401
403 return cmp(self._dict, other._dict)
404
406 special = self._special_del.get(key)
407 if special:
408 special(self, key)
409 else:
410 del self._dict[key]
411
413 return self._dict[key]
414
416
417
418
419
420
421
422
423
424
425
426
427
428 if key in self._special_set_keys:
429 self._special_set[key](self, key, value)
430 else:
431
432
433
434
435 if key not in self._dict \
436 and not _is_valid_var.match(key):
437 raise SCons.Errors.UserError("Illegal construction variable `%s'" % key)
438 self._dict[key] = value
439
440 - def get(self, key, default=None):
441 """Emulates the get() method of dictionaries."""
442 return self._dict.get(key, default)
443
445 return key in self._dict
446
449
451 return list(self._dict.items())
452
454 if node_factory is _null:
455 node_factory = self.fs.File
456 if lookup_list is _null:
457 lookup_list = self.lookup_list
458
459 if not args:
460 return []
461
462 args = SCons.Util.flatten(args)
463
464 nodes = []
465 for v in args:
466 if SCons.Util.is_String(v):
467 n = None
468 for l in lookup_list:
469 n = l(v)
470 if n is not None:
471 break
472 if n is not None:
473 if SCons.Util.is_String(n):
474
475 kw['raw'] = 1
476 n = self.subst(n, **kw)
477 if node_factory:
478 n = node_factory(n)
479 if SCons.Util.is_List(n):
480 nodes.extend(n)
481 else:
482 nodes.append(n)
483 elif node_factory:
484
485 kw['raw'] = 1
486 v = node_factory(self.subst(v, **kw))
487 if SCons.Util.is_List(v):
488 nodes.extend(v)
489 else:
490 nodes.append(v)
491 else:
492 nodes.append(v)
493
494 return nodes
495
498
501
502 - def subst(self, string, raw=0, target=None, source=None, conv=None, executor=None):
503 """Recursively interpolates construction variables from the
504 Environment into the specified string, returning the expanded
505 result. Construction variables are specified by a $ prefix
506 in the string and begin with an initial underscore or
507 alphabetic character followed by any number of underscores
508 or alphanumeric characters. The construction variable names
509 may be surrounded by curly braces to separate the name from
510 trailing characters.
511 """
512 gvars = self.gvars()
513 lvars = self.lvars()
514 lvars['__env__'] = self
515 if executor:
516 lvars.update(executor.get_lvars())
517 return SCons.Subst.scons_subst(string, self, raw, target, source, gvars, lvars, conv)
518
519 - def subst_kw(self, kw, raw=0, target=None, source=None):
520 nkw = {}
521 for k, v in kw.items():
522 k = self.subst(k, raw, target, source)
523 if SCons.Util.is_String(v):
524 v = self.subst(v, raw, target, source)
525 nkw[k] = v
526 return nkw
527
528 - def subst_list(self, string, raw=0, target=None, source=None, conv=None, executor=None):
537
538 - def subst_path(self, path, target=None, source=None):
539 """Substitute a path list, turning EntryProxies into Nodes
540 and leaving Nodes (and other objects) as-is."""
541
542 if not SCons.Util.is_List(path):
543 path = [path]
544
545 def s(obj):
546 """This is the "string conversion" routine that we have our
547 substitutions use to return Nodes, not strings. This relies
548 on the fact that an EntryProxy object has a get() method that
549 returns the underlying Node that it wraps, which is a bit of
550 architectural dependence that we might need to break or modify
551 in the future in response to additional requirements."""
552 try:
553 get = obj.get
554 except AttributeError:
555 obj = SCons.Util.to_String_for_subst(obj)
556 else:
557 obj = get()
558 return obj
559
560 r = []
561 for p in path:
562 if SCons.Util.is_String(p):
563 p = self.subst(p, target=target, source=source, conv=s)
564 if SCons.Util.is_List(p):
565 if len(p) == 1:
566 p = p[0]
567 else:
568
569
570
571 p = ''.join(map(SCons.Util.to_String_for_subst, p))
572 else:
573 p = s(p)
574 r.append(p)
575 return r
576
577 subst_target_source = subst
578
580 import subprocess
581
582 kw = { 'stdin' : 'devnull',
583 'stdout' : subprocess.PIPE,
584 'stderr' : subprocess.PIPE,
585 'universal_newlines' : True,
586 }
587
588
589 if not SCons.Util.is_List(command): kw['shell'] = True
590
591 p = SCons.Action._subproc(self, command, **kw)
592 out,err = p.communicate()
593 status = p.wait()
594 if err:
595 sys.stderr.write(unicode(err))
596 if status:
597 raise OSError("'%s' exited %d" % (command, status))
598 return out
599
601 """
602 Adds the specified function as a method of this construction
603 environment with the specified name. If the name is omitted,
604 the default name is the name of the function itself.
605 """
606 method = MethodWrapper(self, function, name)
607 self.added_methods.append(method)
608
610 """
611 Removes the specified function's MethodWrapper from the
612 added_methods list, so we don't re-bind it when making a clone.
613 """
614 self.added_methods = [dm for dm in self.added_methods if not dm.method is function]
615
617 """
618 Produce a modified environment whose variables are overriden by
619 the overrides dictionaries. "overrides" is a dictionary that
620 will override the variables of this environment.
621
622 This function is much more efficient than Clone() or creating
623 a new Environment because it doesn't copy the construction
624 environment dictionary, it just wraps the underlying construction
625 environment, and doesn't even create a wrapper object if there
626 are no overrides.
627 """
628 if not overrides: return self
629 o = copy_non_reserved_keywords(overrides)
630 if not o: return self
631 overrides = {}
632 merges = None
633 for key, value in o.items():
634 if key == 'parse_flags':
635 merges = value
636 else:
637 overrides[key] = SCons.Subst.scons_subst_once(value, self, key)
638 env = OverrideEnvironment(self, overrides)
639 if merges: env.MergeFlags(merges)
640 return env
641
643 """
644 Parse the set of flags and return a dict with the flags placed
645 in the appropriate entry. The flags are treated as a typical
646 set of command-line flags for a GNU-like toolchain and used to
647 populate the entries in the dict immediately below. If one of
648 the flag strings begins with a bang (exclamation mark), it is
649 assumed to be a command and the rest of the string is executed;
650 the result of that evaluation is then added to the dict.
651 """
652 dict = {
653 'ASFLAGS' : SCons.Util.CLVar(''),
654 'CFLAGS' : SCons.Util.CLVar(''),
655 'CCFLAGS' : SCons.Util.CLVar(''),
656 'CXXFLAGS' : SCons.Util.CLVar(''),
657 'CPPDEFINES' : [],
658 'CPPFLAGS' : SCons.Util.CLVar(''),
659 'CPPPATH' : [],
660 'FRAMEWORKPATH' : SCons.Util.CLVar(''),
661 'FRAMEWORKS' : SCons.Util.CLVar(''),
662 'LIBPATH' : [],
663 'LIBS' : [],
664 'LINKFLAGS' : SCons.Util.CLVar(''),
665 'RPATH' : [],
666 }
667
668 def do_parse(arg):
669
670 if not arg:
671 return
672
673 if not SCons.Util.is_String(arg):
674 for t in arg: do_parse(t)
675 return
676
677
678 if arg[0] == '!':
679 arg = self.backtick(arg[1:])
680
681
682 def append_define(name, dict = dict):
683 t = name.split('=')
684 if len(t) == 1:
685 dict['CPPDEFINES'].append(name)
686 else:
687 dict['CPPDEFINES'].append([t[0], '='.join(t[1:])])
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709 params = shlex.split(arg)
710 append_next_arg_to = None
711 for arg in params:
712 if append_next_arg_to:
713 if append_next_arg_to == 'CPPDEFINES':
714 append_define(arg)
715 elif append_next_arg_to == '-include':
716 t = ('-include', self.fs.File(arg))
717 dict['CCFLAGS'].append(t)
718 elif append_next_arg_to == '-isysroot':
719 t = ('-isysroot', arg)
720 dict['CCFLAGS'].append(t)
721 dict['LINKFLAGS'].append(t)
722 elif append_next_arg_to == '-arch':
723 t = ('-arch', arg)
724 dict['CCFLAGS'].append(t)
725 dict['LINKFLAGS'].append(t)
726 else:
727 dict[append_next_arg_to].append(arg)
728 append_next_arg_to = None
729 elif not arg[0] in ['-', '+']:
730 dict['LIBS'].append(self.fs.File(arg))
731 elif arg == '-dylib_file':
732 dict['LINKFLAGS'].append(arg)
733 append_next_arg_to = 'LINKFLAGS'
734 elif arg[:2] == '-L':
735 if arg[2:]:
736 dict['LIBPATH'].append(arg[2:])
737 else:
738 append_next_arg_to = 'LIBPATH'
739 elif arg[:2] == '-l':
740 if arg[2:]:
741 dict['LIBS'].append(arg[2:])
742 else:
743 append_next_arg_to = 'LIBS'
744 elif arg[:2] == '-I':
745 if arg[2:]:
746 dict['CPPPATH'].append(arg[2:])
747 else:
748 append_next_arg_to = 'CPPPATH'
749 elif arg[:4] == '-Wa,':
750 dict['ASFLAGS'].append(arg[4:])
751 dict['CCFLAGS'].append(arg)
752 elif arg[:4] == '-Wl,':
753 if arg[:11] == '-Wl,-rpath=':
754 dict['RPATH'].append(arg[11:])
755 elif arg[:7] == '-Wl,-R,':
756 dict['RPATH'].append(arg[7:])
757 elif arg[:6] == '-Wl,-R':
758 dict['RPATH'].append(arg[6:])
759 else:
760 dict['LINKFLAGS'].append(arg)
761 elif arg[:4] == '-Wp,':
762 dict['CPPFLAGS'].append(arg)
763 elif arg[:2] == '-D':
764 if arg[2:]:
765 append_define(arg[2:])
766 else:
767 append_next_arg_to = 'CPPDEFINES'
768 elif arg == '-framework':
769 append_next_arg_to = 'FRAMEWORKS'
770 elif arg[:14] == '-frameworkdir=':
771 dict['FRAMEWORKPATH'].append(arg[14:])
772 elif arg[:2] == '-F':
773 if arg[2:]:
774 dict['FRAMEWORKPATH'].append(arg[2:])
775 else:
776 append_next_arg_to = 'FRAMEWORKPATH'
777 elif arg in ['-mno-cygwin',
778 '-pthread',
779 '-openmp',
780 '-fopenmp']:
781 dict['CCFLAGS'].append(arg)
782 dict['LINKFLAGS'].append(arg)
783 elif arg == '-mwindows':
784 dict['LINKFLAGS'].append(arg)
785 elif arg[:5] == '-std=':
786 if arg[5:].find('++')!=-1:
787 key='CXXFLAGS'
788 else:
789 key='CFLAGS'
790 dict[key].append(arg)
791 elif arg[0] == '+':
792 dict['CCFLAGS'].append(arg)
793 dict['LINKFLAGS'].append(arg)
794 elif arg in ['-include', '-isysroot', '-arch']:
795 append_next_arg_to = arg
796 else:
797 dict['CCFLAGS'].append(arg)
798
799 for arg in flags:
800 do_parse(arg)
801 return dict
802
804 """
805 Merge the dict in args into the construction variables of this
806 env, or the passed-in dict. If args is not a dict, it is
807 converted into a dict using ParseFlags. If unique is not set,
808 the flags are appended rather than merged.
809 """
810
811 if dict is None:
812 dict = self
813 if not SCons.Util.is_Dict(args):
814 args = self.ParseFlags(args)
815 if not unique:
816 self.Append(**args)
817 return self
818 for key, value in args.items():
819 if not value:
820 continue
821 try:
822 orig = self[key]
823 except KeyError:
824 orig = value
825 else:
826 if not orig:
827 orig = value
828 elif value:
829
830
831
832
833
834
835 try:
836 orig = orig + value
837 except (KeyError, TypeError):
838 try:
839 add_to_orig = orig.append
840 except AttributeError:
841 value.insert(0, orig)
842 orig = value
843 else:
844 add_to_orig(value)
845 t = []
846 if key[-4:] == 'PATH':
847
848 for v in orig:
849 if v not in t:
850 t.append(v)
851 else:
852
853 orig.reverse()
854 for v in orig:
855 if v not in t:
856 t.insert(0, v)
857 self[key] = t
858 return self
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
883
887
889 f = SCons.Defaults.DefaultEnvironment().copy_from_cache
890 return f(src, dst)
891
892 -class Base(SubstitutionEnvironment):
893 """Base class for "real" construction Environments. These are the
894 primary objects used to communicate dependency and construction
895 information to the build engine.
896
897 Keyword arguments supplied when the construction Environment
898 is created are construction variables used to initialize the
899 Environment.
900 """
901
902 memoizer_counters = []
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918 - def __init__(self,
919 platform=None,
920 tools=None,
921 toolpath=None,
922 variables=None,
923 parse_flags = None,
924 **kw):
925 """
926 Initialization of a basic SCons construction environment,
927 including setting up special construction variables like BUILDER,
928 PLATFORM, etc., and searching for and applying available Tools.
929
930 Note that we do *not* call the underlying base class
931 (SubsitutionEnvironment) initialization, because we need to
932 initialize things in a very specific order that doesn't work
933 with the much simpler base class initialization.
934 """
935 if SCons.Debug.track_instances: logInstanceCreation(self, 'Environment.Base')
936 self._memo = {}
937 self.fs = SCons.Node.FS.get_default_fs()
938 self.ans = SCons.Node.Alias.default_ans
939 self.lookup_list = SCons.Node.arg2nodes_lookups
940 self._dict = semi_deepcopy(SCons.Defaults.ConstructionEnvironment)
941 self._init_special()
942 self.added_methods = []
943
944
945
946
947
948
949
950 self.decide_target = default_decide_target
951 self.decide_source = default_decide_source
952
953 self.copy_from_cache = default_copy_from_cache
954
955 self._dict['BUILDERS'] = BuilderDict(self._dict['BUILDERS'], self)
956
957 if platform is None:
958 platform = self._dict.get('PLATFORM', None)
959 if platform is None:
960 platform = SCons.Platform.Platform()
961 if SCons.Util.is_String(platform):
962 platform = SCons.Platform.Platform(platform)
963 self._dict['PLATFORM'] = str(platform)
964 platform(self)
965
966 self._dict['HOST_OS'] = self._dict.get('HOST_OS',None)
967 self._dict['HOST_ARCH'] = self._dict.get('HOST_ARCH',None)
968
969
970 self._dict['TARGET_OS'] = self._dict.get('TARGET_OS',None)
971 self._dict['TARGET_ARCH'] = self._dict.get('TARGET_ARCH',None)
972
973
974
975
976
977 if 'options' in kw:
978
979
980 variables = kw['options']
981 del kw['options']
982 self.Replace(**kw)
983 keys = list(kw.keys())
984 if variables:
985 keys = keys + list(variables.keys())
986 variables.Update(self)
987
988 save = {}
989 for k in keys:
990 try:
991 save[k] = self._dict[k]
992 except KeyError:
993
994
995 pass
996
997 SCons.Tool.Initializers(self)
998
999 if tools is None:
1000 tools = self._dict.get('TOOLS', None)
1001 if tools is None:
1002 tools = ['default']
1003 apply_tools(self, tools, toolpath)
1004
1005
1006
1007
1008 for key, val in save.items():
1009 self._dict[key] = val
1010
1011
1012 if parse_flags: self.MergeFlags(parse_flags)
1013
1014
1015
1016
1017
1018
1020 """Fetch the builder with the specified name from the environment.
1021 """
1022 try:
1023 return self._dict['BUILDERS'][name]
1024 except KeyError:
1025 return None
1026
1028 try:
1029 path = self._CacheDir_path
1030 except AttributeError:
1031 path = SCons.Defaults.DefaultEnvironment()._CacheDir_path
1032 try:
1033 if path == self._last_CacheDir_path:
1034 return self._last_CacheDir
1035 except AttributeError:
1036 pass
1037 cd = SCons.CacheDir.CacheDir(path)
1038 self._last_CacheDir_path = path
1039 self._last_CacheDir = cd
1040 return cd
1041
1043 """Return a factory function for creating Nodes for this
1044 construction environment.
1045 """
1046 name = default
1047 try:
1048 is_node = issubclass(factory, SCons.Node.FS.Base)
1049 except TypeError:
1050
1051
1052 pass
1053 else:
1054 if is_node:
1055
1056
1057
1058
1059 try: name = factory.__name__
1060 except AttributeError: pass
1061 else: factory = None
1062 if not factory:
1063
1064
1065
1066
1067
1068 factory = getattr(self.fs, name)
1069 return factory
1070
1071 memoizer_counters.append(SCons.Memoize.CountValue('_gsm'))
1072
1074 try:
1075 return self._memo['_gsm']
1076 except KeyError:
1077 pass
1078
1079 result = {}
1080
1081 try:
1082 scanners = self._dict['SCANNERS']
1083 except KeyError:
1084 pass
1085 else:
1086
1087
1088
1089
1090 if not SCons.Util.is_List(scanners):
1091 scanners = [scanners]
1092 else:
1093 scanners = scanners[:]
1094 scanners.reverse()
1095 for scanner in scanners:
1096 for k in scanner.get_skeys(self):
1097 if k and self['PLATFORM'] == 'win32':
1098 k = k.lower()
1099 result[k] = scanner
1100
1101 self._memo['_gsm'] = result
1102
1103 return result
1104
1106 """Find the appropriate scanner given a key (usually a file suffix).
1107 """
1108 if skey and self['PLATFORM'] == 'win32':
1109 skey = skey.lower()
1110 return self._gsm().get(skey)
1111
1113 """Delete the cached scanner map (if we need to).
1114 """
1115 try:
1116 del self._memo['_gsm']
1117 except KeyError:
1118 pass
1119
1121 """Update an environment's values directly, bypassing the normal
1122 checks that occur when users try to set items.
1123 """
1124 self._dict.update(dict)
1125
1127 try:
1128 return self.src_sig_type
1129 except AttributeError:
1130 t = SCons.Defaults.DefaultEnvironment().src_sig_type
1131 self.src_sig_type = t
1132 return t
1133
1135 try:
1136 return self.tgt_sig_type
1137 except AttributeError:
1138 t = SCons.Defaults.DefaultEnvironment().tgt_sig_type
1139 self.tgt_sig_type = t
1140 return t
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1152 """Append values to existing construction variables
1153 in an Environment.
1154 """
1155 kw = copy_non_reserved_keywords(kw)
1156 for key, val in kw.items():
1157
1158
1159
1160
1161 try:
1162 if key == 'CPPDEFINES' and SCons.Util.is_String(self._dict[key]):
1163 self._dict[key] = [self._dict[key]]
1164 orig = self._dict[key]
1165 except KeyError:
1166
1167
1168 if key == 'CPPDEFINES' and SCons.Util.is_String(val):
1169 self._dict[key] = [val]
1170 else:
1171 self._dict[key] = val
1172 else:
1173 try:
1174
1175
1176
1177
1178
1179 update_dict = orig.update
1180 except AttributeError:
1181 try:
1182
1183
1184
1185 self._dict[key] = orig + val
1186 except (KeyError, TypeError):
1187 try:
1188
1189 add_to_orig = orig.append
1190 except AttributeError:
1191
1192
1193
1194
1195
1196 if orig:
1197 val.insert(0, orig)
1198 self._dict[key] = val
1199 else:
1200
1201
1202 if val:
1203 add_to_orig(val)
1204 else:
1205
1206
1207 if SCons.Util.is_List(val):
1208 if key == 'CPPDEFINES':
1209 tmp = []
1210 for (k, v) in orig.iteritems():
1211 if v is not None:
1212 tmp.append((k, v))
1213 else:
1214 tmp.append((k,))
1215 orig = tmp
1216 orig += val
1217 self._dict[key] = orig
1218 else:
1219 for v in val:
1220 orig[v] = None
1221 else:
1222 try:
1223 update_dict(val)
1224 except (AttributeError, TypeError, ValueError):
1225 if SCons.Util.is_Dict(val):
1226 for k, v in val.items():
1227 orig[k] = v
1228 else:
1229 orig[val] = None
1230 self.scanner_map_delete(kw)
1231
1232
1233
1240
1241 - def AppendENVPath(self, name, newpath, envname = 'ENV',
1242 sep = os.pathsep, delete_existing=1):
1243 """Append path elements to the path 'name' in the 'ENV'
1244 dictionary for this environment. Will only add any particular
1245 path once, and will normpath and normcase all paths to help
1246 assure this. This can also handle the case where the env
1247 variable is a list instead of a string.
1248
1249 If delete_existing is 0, a newpath which is already in the path
1250 will not be moved to the end (it will be left where it is).
1251 """
1252
1253 orig = ''
1254 if envname in self._dict and name in self._dict[envname]:
1255 orig = self._dict[envname][name]
1256
1257 nv = SCons.Util.AppendPath(orig, newpath, sep, delete_existing,
1258 canonicalize=self._canonicalize)
1259
1260 if envname not in self._dict:
1261 self._dict[envname] = {}
1262
1263 self._dict[envname][name] = nv
1264
1266 """Append values to existing construction variables
1267 in an Environment, if they're not already there.
1268 If delete_existing is 1, removes existing values first, so
1269 values move to end.
1270 """
1271 kw = copy_non_reserved_keywords(kw)
1272 for key, val in kw.items():
1273 if SCons.Util.is_List(val):
1274 val = _delete_duplicates(val, delete_existing)
1275 if key not in self._dict or self._dict[key] in ('', None):
1276 self._dict[key] = val
1277 elif SCons.Util.is_Dict(self._dict[key]) and \
1278 SCons.Util.is_Dict(val):
1279 self._dict[key].update(val)
1280 elif SCons.Util.is_List(val):
1281 dk = self._dict[key]
1282 if key == 'CPPDEFINES':
1283 tmp = []
1284 for i in val:
1285 if SCons.Util.is_List(i):
1286 if len(i) >= 2:
1287 tmp.append((i[0], i[1]))
1288 else:
1289 tmp.append((i[0],))
1290 elif SCons.Util.is_Tuple(i):
1291 tmp.append(i)
1292 else:
1293 tmp.append((i,))
1294 val = tmp
1295
1296 if SCons.Util.is_Dict(dk):
1297 tmp = []
1298 for (k, v) in dk.iteritems():
1299 if v is not None:
1300 tmp.append((k, v))
1301 else:
1302 tmp.append((k,))
1303 dk = tmp
1304 elif SCons.Util.is_String(dk):
1305 dk = [(dk,)]
1306 else:
1307 tmp = []
1308 for i in dk:
1309 if SCons.Util.is_List(i):
1310 if len(i) >= 2:
1311 tmp.append((i[0], i[1]))
1312 else:
1313 tmp.append((i[0],))
1314 elif SCons.Util.is_Tuple(i):
1315 tmp.append(i)
1316 else:
1317 tmp.append((i,))
1318 dk = tmp
1319 else:
1320 if not SCons.Util.is_List(dk):
1321 dk = [dk]
1322 if delete_existing:
1323 dk = [x for x in dk if x not in val]
1324 else:
1325 val = [x for x in val if x not in dk]
1326 self._dict[key] = dk + val
1327 else:
1328 dk = self._dict[key]
1329 if SCons.Util.is_List(dk):
1330 if key == 'CPPDEFINES':
1331 tmp = []
1332 for i in dk:
1333 if SCons.Util.is_List(i):
1334 if len(i) >= 2:
1335 tmp.append((i[0], i[1]))
1336 else:
1337 tmp.append((i[0],))
1338 elif SCons.Util.is_Tuple(i):
1339 tmp.append(i)
1340 else:
1341 tmp.append((i,))
1342 dk = tmp
1343
1344 if SCons.Util.is_Dict(val):
1345 tmp = []
1346 for (k, v) in val.iteritems():
1347 if v is not None:
1348 tmp.append((k, v))
1349 else:
1350 tmp.append((k,))
1351 val = tmp
1352 elif SCons.Util.is_String(val):
1353 val = [(val,)]
1354 if delete_existing:
1355 dk = filter(lambda x, val=val: x not in val, dk)
1356 self._dict[key] = dk + val
1357 else:
1358 dk = [x for x in dk if x not in val]
1359 self._dict[key] = dk + val
1360 else:
1361
1362
1363 if delete_existing:
1364 dk = filter(lambda x, val=val: x not in val, dk)
1365 self._dict[key] = dk + [val]
1366 else:
1367 if not val in dk:
1368 self._dict[key] = dk + [val]
1369 else:
1370 if key == 'CPPDEFINES':
1371 if SCons.Util.is_String(dk):
1372 dk = [dk]
1373 elif SCons.Util.is_Dict(dk):
1374 tmp = []
1375 for (k, v) in dk.iteritems():
1376 if v is not None:
1377 tmp.append((k, v))
1378 else:
1379 tmp.append((k,))
1380 dk = tmp
1381 if SCons.Util.is_String(val):
1382 if val in dk:
1383 val = []
1384 else:
1385 val = [val]
1386 elif SCons.Util.is_Dict(val):
1387 tmp = []
1388 for i,j in val.iteritems():
1389 if j is not None:
1390 tmp.append((i,j))
1391 else:
1392 tmp.append(i)
1393 val = tmp
1394 if delete_existing:
1395 dk = [x for x in dk if x not in val]
1396 self._dict[key] = dk + val
1397 self.scanner_map_delete(kw)
1398
1399 - def Clone(self, tools=[], toolpath=None, parse_flags = None, **kw):
1400 """Return a copy of a construction Environment. The
1401 copy is like a Python "deep copy"--that is, independent
1402 copies are made recursively of each objects--except that
1403 a reference is copied when an object is not deep-copyable
1404 (like a function). There are no references to any mutable
1405 objects in the original Environment.
1406 """
1407
1408 builders = self._dict.get('BUILDERS', {})
1409
1410 clone = copy.copy(self)
1411
1412 clone._dict = semi_deepcopy_dict(self._dict, ['BUILDERS'])
1413 clone._dict['BUILDERS'] = BuilderDict(builders, clone)
1414
1415
1416
1417
1418
1419 clone.added_methods = []
1420 for mw in self.added_methods:
1421 if mw == getattr(self, mw.name):
1422 clone.added_methods.append(mw.clone(clone))
1423
1424 clone._memo = {}
1425
1426
1427
1428 kw = copy_non_reserved_keywords(kw)
1429 new = {}
1430 for key, value in kw.items():
1431 new[key] = SCons.Subst.scons_subst_once(value, self, key)
1432 clone.Replace(**new)
1433
1434 apply_tools(clone, tools, toolpath)
1435
1436
1437 clone.Replace(**new)
1438
1439
1440 if parse_flags: clone.MergeFlags(parse_flags)
1441
1442 if SCons.Debug.track_instances: logInstanceCreation(self, 'Environment.EnvironmentClone')
1443 return clone
1444
1445 - def Copy(self, *args, **kw):
1452
1457
1458 - def _changed_content(self, dependency, target, prev_ni):
1459 return dependency.changed_content(target, prev_ni)
1460
1468
1469 - def _changed_timestamp_then_content(self, dependency, target, prev_ni):
1470 return dependency.changed_timestamp_then_content(target, prev_ni)
1471
1474
1477
1479 return self.fs.copy(src, dst)
1480
1482 return self.fs.copy2(src, dst)
1483
1507
1509 """Return the first available program in progs.
1510 """
1511 if not SCons.Util.is_List(progs):
1512 progs = [ progs ]
1513 for prog in progs:
1514 path = self.WhereIs(prog)
1515 if path: return prog
1516 return None
1517
1519 if not args:
1520 return self._dict
1521 dlist = [self._dict[x] for x in args]
1522 if len(dlist) == 1:
1523 dlist = dlist[0]
1524 return dlist
1525
1526 - def Dump(self, key = None):
1527 """
1528 Using the standard Python pretty printer, dump the contents of the
1529 scons build environment to stdout.
1530
1531 If the key passed in is anything other than None, then that will
1532 be used as an index into the build environment dictionary and
1533 whatever is found there will be fed into the pretty printer. Note
1534 that this key is case sensitive.
1535 """
1536 import pprint
1537 pp = pprint.PrettyPrinter(indent=2)
1538 if key:
1539 dict = self.Dictionary(key)
1540 else:
1541 dict = self.Dictionary()
1542 return pp.pformat(dict)
1543
1544 - def FindIxes(self, paths, prefix, suffix):
1545 """
1546 Search a list of paths for something that matches the prefix and suffix.
1547
1548 paths - the list of paths or nodes.
1549 prefix - construction variable for the prefix.
1550 suffix - construction variable for the suffix.
1551 """
1552
1553 suffix = self.subst('$'+suffix)
1554 prefix = self.subst('$'+prefix)
1555
1556 for path in paths:
1557 dir,name = os.path.split(str(path))
1558 if name[:len(prefix)] == prefix and name[-len(suffix):] == suffix:
1559 return path
1560
1561 - def ParseConfig(self, command, function=None, unique=1):
1562 """
1563 Use the specified function to parse the output of the command
1564 in order to modify the current environment. The 'command' can
1565 be a string or a list of strings representing a command and
1566 its arguments. 'Function' is an optional argument that takes
1567 the environment, the output of the command, and the unique flag.
1568 If no function is specified, MergeFlags, which treats the output
1569 as the result of a typical 'X-config' command (i.e. gtk-config),
1570 will merge the output into the appropriate variables.
1571 """
1572 if function is None:
1573 def parse_conf(env, cmd, unique=unique):
1574 return env.MergeFlags(cmd, unique)
1575 function = parse_conf
1576 if SCons.Util.is_List(command):
1577 command = ' '.join(command)
1578 command = self.subst(command)
1579 return function(self, self.backtick(command))
1580
1581 - def ParseDepends(self, filename, must_exist=None, only_one=0):
1582 """
1583 Parse a mkdep-style file for explicit dependencies. This is
1584 completely abusable, and should be unnecessary in the "normal"
1585 case of proper SCons configuration, but it may help make
1586 the transition from a Make hierarchy easier for some people
1587 to swallow. It can also be genuinely useful when using a tool
1588 that can write a .d file, but for which writing a scanner would
1589 be too complicated.
1590 """
1591 filename = self.subst(filename)
1592 try:
1593 fp = open(filename, 'r')
1594 except IOError:
1595 if must_exist:
1596 raise
1597 return
1598 lines = SCons.Util.LogicalLines(fp).readlines()
1599 lines = [l for l in lines if l[0] != '#']
1600 tdlist = []
1601 for line in lines:
1602 try:
1603 target, depends = line.split(':', 1)
1604 except (AttributeError, ValueError):
1605
1606
1607 pass
1608 else:
1609 tdlist.append((target.split(), depends.split()))
1610 if only_one:
1611 targets = []
1612 for td in tdlist:
1613 targets.extend(td[0])
1614 if len(targets) > 1:
1615 raise SCons.Errors.UserError(
1616 "More than one dependency target found in `%s': %s"
1617 % (filename, targets))
1618 for target, depends in tdlist:
1619 self.Depends(target, depends)
1620
1624
1626 """Prepend values to existing construction variables
1627 in an Environment.
1628 """
1629 kw = copy_non_reserved_keywords(kw)
1630 for key, val in kw.items():
1631
1632
1633
1634
1635 try:
1636 orig = self._dict[key]
1637 except KeyError:
1638
1639
1640 self._dict[key] = val
1641 else:
1642 try:
1643
1644
1645
1646
1647
1648 update_dict = orig.update
1649 except AttributeError:
1650 try:
1651
1652
1653
1654 self._dict[key] = val + orig
1655 except (KeyError, TypeError):
1656 try:
1657
1658 add_to_val = val.append
1659 except AttributeError:
1660
1661
1662
1663
1664 if val:
1665 orig.insert(0, val)
1666 else:
1667
1668
1669
1670 if orig:
1671 add_to_val(orig)
1672 self._dict[key] = val
1673 else:
1674
1675
1676 if SCons.Util.is_List(val):
1677 for v in val:
1678 orig[v] = None
1679 else:
1680 try:
1681 update_dict(val)
1682 except (AttributeError, TypeError, ValueError):
1683 if SCons.Util.is_Dict(val):
1684 for k, v in val.items():
1685 orig[k] = v
1686 else:
1687 orig[val] = None
1688 self.scanner_map_delete(kw)
1689
1690 - def PrependENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep,
1691 delete_existing=1):
1692 """Prepend path elements to the path 'name' in the 'ENV'
1693 dictionary for this environment. Will only add any particular
1694 path once, and will normpath and normcase all paths to help
1695 assure this. This can also handle the case where the env
1696 variable is a list instead of a string.
1697
1698 If delete_existing is 0, a newpath which is already in the path
1699 will not be moved to the front (it will be left where it is).
1700 """
1701
1702 orig = ''
1703 if envname in self._dict and name in self._dict[envname]:
1704 orig = self._dict[envname][name]
1705
1706 nv = SCons.Util.PrependPath(orig, newpath, sep, delete_existing,
1707 canonicalize=self._canonicalize)
1708
1709 if envname not in self._dict:
1710 self._dict[envname] = {}
1711
1712 self._dict[envname][name] = nv
1713
1715 """Prepend values to existing construction variables
1716 in an Environment, if they're not already there.
1717 If delete_existing is 1, removes existing values first, so
1718 values move to front.
1719 """
1720 kw = copy_non_reserved_keywords(kw)
1721 for key, val in kw.items():
1722 if SCons.Util.is_List(val):
1723 val = _delete_duplicates(val, not delete_existing)
1724 if key not in self._dict or self._dict[key] in ('', None):
1725 self._dict[key] = val
1726 elif SCons.Util.is_Dict(self._dict[key]) and \
1727 SCons.Util.is_Dict(val):
1728 self._dict[key].update(val)
1729 elif SCons.Util.is_List(val):
1730 dk = self._dict[key]
1731 if not SCons.Util.is_List(dk):
1732 dk = [dk]
1733 if delete_existing:
1734 dk = [x for x in dk if x not in val]
1735 else:
1736 val = [x for x in val if x not in dk]
1737 self._dict[key] = val + dk
1738 else:
1739 dk = self._dict[key]
1740 if SCons.Util.is_List(dk):
1741
1742
1743 if delete_existing:
1744 dk = [x for x in dk if x not in val]
1745 self._dict[key] = [val] + dk
1746 else:
1747 if not val in dk:
1748 self._dict[key] = [val] + dk
1749 else:
1750 if delete_existing:
1751 dk = [x for x in dk if x not in val]
1752 self._dict[key] = val + dk
1753 self.scanner_map_delete(kw)
1754
1756 """Replace existing construction variables in an Environment
1757 with new construction variables and/or values.
1758 """
1759 try:
1760 kwbd = kw['BUILDERS']
1761 except KeyError:
1762 pass
1763 else:
1764 kwbd = BuilderDict(kwbd,self)
1765 del kw['BUILDERS']
1766 self.__setitem__('BUILDERS', kwbd)
1767 kw = copy_non_reserved_keywords(kw)
1768 self._update(semi_deepcopy(kw))
1769 self.scanner_map_delete(kw)
1770
1771 - def ReplaceIxes(self, path, old_prefix, old_suffix, new_prefix, new_suffix):
1772 """
1773 Replace old_prefix with new_prefix and old_suffix with new_suffix.
1774
1775 env - Environment used to interpolate variables.
1776 path - the path that will be modified.
1777 old_prefix - construction variable for the old prefix.
1778 old_suffix - construction variable for the old suffix.
1779 new_prefix - construction variable for the new prefix.
1780 new_suffix - construction variable for the new suffix.
1781 """
1782 old_prefix = self.subst('$'+old_prefix)
1783 old_suffix = self.subst('$'+old_suffix)
1784
1785 new_prefix = self.subst('$'+new_prefix)
1786 new_suffix = self.subst('$'+new_suffix)
1787
1788 dir,name = os.path.split(str(path))
1789 if name[:len(old_prefix)] == old_prefix:
1790 name = name[len(old_prefix):]
1791 if name[-len(old_suffix):] == old_suffix:
1792 name = name[:-len(old_suffix)]
1793 return os.path.join(dir, new_prefix+name+new_suffix)
1794
1796 for k in kw.keys():
1797 if k in self._dict:
1798 del kw[k]
1799 self.Replace(**kw)
1800
1803
1812
1813 - def WhereIs(self, prog, path=None, pathext=None, reject=[]):
1814 """Find prog in the path.
1815 """
1816 if path is None:
1817 try:
1818 path = self['ENV']['PATH']
1819 except KeyError:
1820 pass
1821 elif SCons.Util.is_String(path):
1822 path = self.subst(path)
1823 if pathext is None:
1824 try:
1825 pathext = self['ENV']['PATHEXT']
1826 except KeyError:
1827 pass
1828 elif SCons.Util.is_String(pathext):
1829 pathext = self.subst(pathext)
1830 prog = SCons.Util.CLVar(self.subst(prog))
1831 path = SCons.Util.WhereIs(prog[0], path, pathext, reject)
1832 if path: return path
1833 return None
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843 - def Action(self, *args, **kw):
1844 def subst_string(a, self=self):
1845 if SCons.Util.is_String(a):
1846 a = self.subst(a)
1847 return a
1848 nargs = list(map(subst_string, args))
1849 nkw = self.subst_kw(kw)
1850 return SCons.Action.Action(*nargs, **nkw)
1851
1861
1862 - def AddPostAction(self, files, action):
1863 nodes = self.arg2nodes(files, self.fs.Entry)
1864 action = SCons.Action.Action(action)
1865 uniq = {}
1866 for executor in [n.get_executor() for n in nodes]:
1867 uniq[executor] = 1
1868 for executor in uniq.keys():
1869 executor.add_post_action(action)
1870 return nodes
1871
1872 - def Alias(self, target, source=[], action=None, **kw):
1924
1932
1940
1944
1950
1951 - def Clean(self, targets, files):
1960
1972
1973 - def Command(self, target, source, action, **kw):
1974 """Builds the supplied target files from the supplied
1975 source files using the supplied action. Action may
1976 be any type that the Builder constructor will accept
1977 for an action."""
1978 bkw = {
1979 'action' : action,
1980 'target_factory' : self.fs.Entry,
1981 'source_factory' : self.fs.Entry,
1982 }
1983 try: bkw['source_scanner'] = kw['source_scanner']
1984 except KeyError: pass
1985 else: del kw['source_scanner']
1986 bld = SCons.Builder.Builder(**bkw)
1987 return bld(self, target, source, **kw)
1988
1989 - def Depends(self, target, dependency):
1990 """Explicity specify that 'target's depend on 'dependency'."""
1991 tlist = self.arg2nodes(target, self.fs.Entry)
1992 dlist = self.arg2nodes(dependency, self.fs.Entry)
1993 for t in tlist:
1994 t.add_dependency(dlist)
1995 return tlist
1996
1997 - def Dir(self, name, *args, **kw):
2007
2009 """Tags a target so that it will not be cleaned by -c"""
2010 tlist = []
2011 for t in targets:
2012 tlist.extend(self.arg2nodes(t, self.fs.Entry))
2013 for t in tlist:
2014 t.set_noclean()
2015 return tlist
2016
2018 """Tags a target so that it will not be cached"""
2019 tlist = []
2020 for t in targets:
2021 tlist.extend(self.arg2nodes(t, self.fs.Entry))
2022 for t in tlist:
2023 t.set_nocache()
2024 return tlist
2025
2026 - def Entry(self, name, *args, **kw):
2027 """
2028 """
2029 s = self.subst(name)
2030 if SCons.Util.is_Sequence(s):
2031 result=[]
2032 for e in s:
2033 result.append(self.fs.Entry(e, *args, **kw))
2034 return result
2035 return self.fs.Entry(s, *args, **kw)
2036
2039
2040 - def Execute(self, action, *args, **kw):
2041 """Directly execute an action through an Environment
2042 """
2043 action = self.Action(action, *args, **kw)
2044 result = action([], [], self)
2045 if isinstance(result, SCons.Errors.BuildError):
2046 errstr = result.errstr
2047 if result.filename:
2048 errstr = result.filename + ': ' + errstr
2049 sys.stderr.write("scons: *** %s\n" % errstr)
2050 return result.status
2051 else:
2052 return result
2053
2054 - def File(self, name, *args, **kw):
2064
2069
2072
2079
2080 - def Glob(self, pattern, ondisk=True, source=False, strings=False):
2081 return self.fs.Glob(self.subst(pattern), ondisk, source, strings)
2082
2083 - def Ignore(self, target, dependency):
2090
2093
2094 - def Local(self, *targets):
2105
2113
2121
2125
2126 - def Requires(self, target, prerequisite):
2127 """Specify that 'prerequisite' must be built before 'target',
2128 (but 'target' does not actually depend on 'prerequisite'
2129 and need not be rebuilt if it changes)."""
2130 tlist = self.arg2nodes(target, self.fs.Entry)
2131 plist = self.arg2nodes(prerequisite, self.fs.Entry)
2132 for t in tlist:
2133 t.add_prerequisite(plist)
2134 return tlist
2135
2144
2145 - def SConsignFile(self, name=".sconsign", dbm_module=None):
2146 if name is not None:
2147 name = self.subst(name)
2148 if not os.path.isabs(name):
2149 name = os.path.join(str(self.fs.SConstruct_dir), name)
2150 if name:
2151 name = os.path.normpath(name)
2152 sconsign_dir = os.path.dirname(name)
2153 if sconsign_dir and not os.path.exists(sconsign_dir):
2154 self.Execute(SCons.Defaults.Mkdir(sconsign_dir))
2155 SCons.SConsign.File(name, dbm_module)
2156
2158 """Tell scons that side_effects are built as side
2159 effects of building targets."""
2160 side_effects = self.arg2nodes(side_effect, self.fs.Entry)
2161 targets = self.arg2nodes(target, self.fs.Entry)
2162
2163 for side_effect in side_effects:
2164 if side_effect.multiple_side_effect_has_builder():
2165 raise SCons.Errors.UserError("Multiple ways to build the same target were specified for: %s" % str(side_effect))
2166 side_effect.add_source(targets)
2167 side_effect.side_effect = 1
2168 self.Precious(side_effect)
2169 for target in targets:
2170 target.side_effects.append(side_effect)
2171 return side_effects
2172
2182
2200
2202 """This function converts a string or list into a list of strings
2203 or Nodes. This makes things easier for users by allowing files to
2204 be specified as a white-space separated list to be split.
2205 The input rules are:
2206 - A single string containing names separated by spaces. These will be
2207 split apart at the spaces.
2208 - A single Node instance
2209 - A list containing either strings or Node instances. Any strings
2210 in the list are not split at spaces.
2211 In all cases, the function returns a list of Nodes and strings."""
2212 if SCons.Util.is_List(arg):
2213 return list(map(self.subst, arg))
2214 elif SCons.Util.is_String(arg):
2215 return self.subst(arg).split()
2216 else:
2217 return [self.subst(arg)]
2218
2240
2241 - def Value(self, value, built_value=None):
2245
2246 - def VariantDir(self, variant_dir, src_dir, duplicate=1):
2250
2265 build_source(node.all_children())
2266
2267 def final_source(node):
2268 while (node != node.srcnode()):
2269 node = node.srcnode()
2270 return node
2271 sources = map( final_source, sources );
2272
2273 return list(set(sources))
2274
2276 """ returns the list of all targets of the Install and InstallAs Builder.
2277 """
2278 from SCons.Tool import install
2279 if install._UNIQUE_INSTALLED_FILES is None:
2280 install._UNIQUE_INSTALLED_FILES = SCons.Util.uniquer_hashables(install._INSTALLED_FILES)
2281 return install._UNIQUE_INSTALLED_FILES
2282
2283
2285 """A proxy that overrides variables in a wrapped construction
2286 environment by returning values from an overrides dictionary in
2287 preference to values from the underlying subject environment.
2288
2289 This is a lightweight (I hope) proxy that passes through most use of
2290 attributes to the underlying Environment.Base class, but has just
2291 enough additional methods defined to act like a real construction
2292 environment with overridden values. It can wrap either a Base
2293 construction environment, or another OverrideEnvironment, which
2294 can in turn nest arbitrary OverrideEnvironments...
2295
2296 Note that we do *not* call the underlying base class
2297 (SubsitutionEnvironment) initialization, because we get most of those
2298 from proxying the attributes of the subject construction environment.
2299 But because we subclass SubstitutionEnvironment, this class also
2300 has inherited arg2nodes() and subst*() methods; those methods can't
2301 be proxied because they need *this* object's methods to fetch the
2302 values from the overrides dictionary.
2303 """
2304
2305 - def __init__(self, subject, overrides={}):
2309
2310
2312 return getattr(self.__dict__['__subject'], name)
2314 setattr(self.__dict__['__subject'], name, value)
2315
2316
2318 try:
2319 return self.__dict__['overrides'][key]
2320 except KeyError:
2321 return self.__dict__['__subject'].__getitem__(key)
2327 try:
2328 del self.__dict__['overrides'][key]
2329 except KeyError:
2330 deleted = 0
2331 else:
2332 deleted = 1
2333 try:
2334 result = self.__dict__['__subject'].__delitem__(key)
2335 except KeyError:
2336 if not deleted:
2337 raise
2338 result = None
2339 return result
2340 - def get(self, key, default=None):
2341 """Emulates the get() method of dictionaries."""
2342 try:
2343 return self.__dict__['overrides'][key]
2344 except KeyError:
2345 return self.__dict__['__subject'].get(key, default)
2347 try:
2348 self.__dict__['overrides'][key]
2349 return 1
2350 except KeyError:
2351 return key in self.__dict__['__subject']
2353 if self.__dict__['overrides'].__contains__(key):
2354 return 1
2355 return self.__dict__['__subject'].__contains__(key)
2357 """Emulates the items() method of dictionaries."""
2358 d = self.__dict__['__subject'].Dictionary().copy()
2359 d.update(self.__dict__['overrides'])
2360 return d
2362 """Emulates the items() method of dictionaries."""
2363 return list(self.Dictionary().items())
2364
2365
2367 """Update an environment's values directly, bypassing the normal
2368 checks that occur when users try to set items.
2369 """
2370 self.__dict__['overrides'].update(dict)
2371
2373 return self.__dict__['__subject'].gvars()
2374
2379
2380
2384
2385
2386
2387
2388
2389
2390
2391 Environment = Base
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2406 class _NoSubstitutionProxy(Environment):
2407 def __init__(self, subject):
2408 self.__dict__['__subject'] = subject
2409 def __getattr__(self, name):
2410 return getattr(self.__dict__['__subject'], name)
2411 def __setattr__(self, name, value):
2412 return setattr(self.__dict__['__subject'], name, value)
2413 def executor_to_lvars(self, kwdict):
2414 if kwdict.has_key('executor'):
2415 kwdict['lvars'] = kwdict['executor'].get_lvars()
2416 del kwdict['executor']
2417 else:
2418 kwdict['lvars'] = {}
2419 def raw_to_mode(self, dict):
2420 try:
2421 raw = dict['raw']
2422 except KeyError:
2423 pass
2424 else:
2425 del dict['raw']
2426 dict['mode'] = raw
2427 def subst(self, string, *args, **kwargs):
2428 return string
2429 def subst_kw(self, kw, *args, **kwargs):
2430 return kw
2431 def subst_list(self, string, *args, **kwargs):
2432 nargs = (string, self,) + args
2433 nkw = kwargs.copy()
2434 nkw['gvars'] = {}
2435 self.executor_to_lvars(nkw)
2436 self.raw_to_mode(nkw)
2437 return SCons.Subst.scons_subst_list(*nargs, **nkw)
2438 def subst_target_source(self, string, *args, **kwargs):
2439 nargs = (string, self,) + args
2440 nkw = kwargs.copy()
2441 nkw['gvars'] = {}
2442 self.executor_to_lvars(nkw)
2443 self.raw_to_mode(nkw)
2444 return SCons.Subst.scons_subst(*nargs, **nkw)
2445 return _NoSubstitutionProxy(subject)
2446
2447
2448
2449
2450
2451
2452