Anonymous avatar Anonymous committed 8e74dcb

LIBS and LIBPATH work, variable substitution changes.

Comments (0)

Files changed (9)

src/engine/SCons/Builder.py

 import os
 import os.path
 import SCons.Node.FS
-from SCons.Util import PathList, scons_str2nodes, scons_subst
+from SCons.Util import PathList, scons_str2nodes, scons_subst, scons_subst_list
 import string
 import types
 from UserList import UserList
 
     def execute(self, **kw):
         dict = apply(self.subst_dict, (), kw)
-        cmd_str = scons_subst(self.command, dict, {})
-        for cmd in string.split(cmd_str, '\n'):
-            if print_actions:
-                self.show(cmd)
-            if execute_actions:
-                args = string.split(cmd)
-                try:
-                    ENV = kw['env']['ENV']
-                except:
-                    import SCons.Defaults
-                    ENV = SCons.Defaults.ConstructionEnvironment['ENV']
-                ret = spawn(args[0], args, ENV)
-                if ret:
-                    return ret
+        cmd_list = scons_subst_list(self.command, dict, {})
+        for cmd_line in cmd_list:
+            if len(cmd_line):
+                if print_actions:
+                    self.show(string.join(cmd_line))
+                if execute_actions:
+                    try:
+                        ENV = kw['env']['ENV']
+                    except:
+                        import SCons.Defaults
+                        ENV = SCons.Defaults.ConstructionEnvironment['ENV']
+                    ret = spawn(cmd_line[0], cmd_line, ENV)
+                    if ret:
+                        return ret
         return 0
 
     def get_contents(self, **kw):

src/engine/SCons/BuilderTests.py

 
 test.write('act.py', """import os, string, sys
 f = open(sys.argv[1], 'w')
-f.write("act.py: " + string.join(sys.argv[2:]) + "\\n")
+f.write("act.py: '" + string.join(sys.argv[2:], "' '") + "'\\n")
 try:
     if sys.argv[3]:
-        f.write("act.py: " + os.environ[sys.argv[3]] + "\\n")
+        f.write("act.py: '" + os.environ[sys.argv[3]] + "'\\n")
 except:
     pass
 f.close()
 act_py = test.workpath('act.py')
 outfile = test.workpath('outfile')
 
+show_string = None
+
 class Environment:
             def subst(self, s):
                 return s
 	r = builder.execute()
 	assert r == 0
 	c = test.read(outfile, 'r')
-	assert c == "act.py: xyzzy\n", c
+        assert c == "act.py: 'xyzzy'\n", c
 
 	cmd2 = r'%s %s %s $TARGET' % (python, act_py, outfile)
 
 	r = builder.execute(target = 'foo')
 	assert r == 0
 	c = test.read(outfile, 'r')
-	assert c == "act.py: foo\n", c
+        assert c == "act.py: 'foo'\n", c
 
 	cmd3 = r'%s %s %s ${TARGETS}' % (python, act_py, outfile)
 
 	r = builder.execute(target = ['aaa', 'bbb'])
 	assert r == 0
 	c = test.read(outfile, 'r')
-	assert c == "act.py: aaa bbb\n", c
+        assert c == "act.py: 'aaa' 'bbb'\n", c
 
 	cmd4 = r'%s %s %s $SOURCES' % (python, act_py, outfile)
 
 	r = builder.execute(source = ['one', 'two'])
 	assert r == 0
 	c = test.read(outfile, 'r')
-	assert c == "act.py: one two\n", c
+        assert c == "act.py: 'one' 'two'\n", c
 
 	cmd4 = r'%s %s %s ${SOURCES[:2]}' % (python, act_py, outfile)
 
 	r = builder.execute(source = ['three', 'four', 'five'])
 	assert r == 0
 	c = test.read(outfile, 'r')
-	assert c == "act.py: three four\n", c
+        assert c == "act.py: 'three' 'four'\n", c
 
 	cmd5 = r'%s %s %s $TARGET XYZZY' % (python, act_py, outfile)
 
 	r = builder.execute(target = 'out5', env = {'ENV' : {'XYZZY' : 'xyzzy'}})
 	assert r == 0
 	c = test.read(outfile, 'r')
-	assert c == "act.py: out5 XYZZY\nact.py: xyzzy\n", c
+        assert c == "act.py: 'out5' 'XYZZY'\nact.py: 'xyzzy'\n", c
+
+        cmd7 = '%s %s %s one\n\n%s %s %s two' % (python, act_py, outfile,
+                                                 python, act_py, outfile)
+        expect7 = '%s %s %s one\n%s %s %s two\n' % (python, act_py, outfile,
+                                                    python, act_py, outfile)
+
+        builder = SCons.Builder.Builder(action = cmd7)
+
+        global show_string
+        show_string = ""
+        def my_show(string):
+            global show_string
+            show_string = show_string + string + "\n"
+        builder.action.show = my_show
+
+        r = builder.execute()
+        assert r == 0
+        assert show_string == expect7, show_string
 
 	def function1(**kw):
 	    open(kw['out'], 'w').write("function1\n")
 	r = builder.execute(out = outfile)
 	assert r.__class__ == class2b
 	c = test.read(outfile, 'r')
-	assert c == "act.py: syzygy\nfunction2\nclass2a\nclass2b\n", c
+        assert c == "act.py: 'syzygy'\nfunction2\nclass2a\nclass2b\n", c
 
     def test_get_contents(self):
         """Test returning the signature contents of a Builder

src/engine/SCons/Defaults.py

         'PROGSUFFIX' : '',
         'LIBPREFIX'  : 'lib',
         'LIBSUFFIX'  : '.a',
+        'LIBDIRPREFIX'          : '-L',
+        'LIBDIRSUFFIX'          : '',
+        'LIBLINKPREFIX'         : '-l',
+        'LIBLINKSUFFIX'         : '',
         'ENV'        : { 'PATH' : '/usr/local/bin:/bin:/usr/bin' },
     }
 
         'PROGSUFFIX' : '.exe',
         'LIBPREFIX'  : '',
         'LIBSUFFIX'  : '.lib',
+        'LIBDIRPREFIX'          : '/L',
+        'LIBDIRSUFFIX'          : '',
+        'LIBLINKPREFIX'         : '',
+        'LIBLINKSUFFIX'         : '$LIBSUFFIX',
         'ENV'        : {
                         'PATH'    : r'C:\Python20;C:\WINNT\system32;C:\WINNT;C:\Program Files\Microsoft Visual Studio\VC98\Bin\;',
                         'PATHEXT' : '.COM;.EXE;.BAT;.CMD',

src/engine/SCons/Environment.py

 import SCons.Util
 import SCons.Builder
 from SCons.Errors import UserError
+from UserList import UserList
 
 def Command():
     pass	# XXX
     Environment.
     """
 
+    # See the documentation for the __autogenerate() method
+    # for an explanation of this variable...
+    AUTO_GEN_VARS = ( ( '_LIBFLAGS',
+                        'LIBS',
+                        'LIBLINKPREFIX',
+                        'LIBLINKSUFFIX' ),
+                      ( '_LIBDIRFLAGS',
+                        'LIBPATH',
+                        'LIBDIRPREFIX',
+                        'LIBDIRSUFFIX' ) )
+
     def __init__(self, **kw):
 	import SCons.Defaults
 	self._dict = copy.deepcopy(SCons.Defaults.ConstructionEnvironment)
         if kw.has_key('SCANNERS') and type(kw['SCANNERS']) != type([]):
                 kw['SCANNERS'] = [kw['SCANNERS']]
 	self._dict.update(copy.deepcopy(kw))
+        self.__autogenerate()
 
 	class BuilderWrapper:
 	    """Wrapper class that allows an environment to
         for s in self._dict['SCANNERS']:
             setattr(self, s.name, s)
 
+    def __autogenerate(self):
+        """Autogenerate the "interpolated" environment variables.
+        We read a static structure that tells us how.  AUTO_GEN_VARS
+        is a tuple of tuples.  Each inner tuple has four elements,
+        each strings referring to an environment variable, and describing
+        how to autogenerate a particular variable.  The elements are:
+
+        0 - The variable to generate
+        1 - The "source" variable, usually a list
+        2 - The "prefix" variable
+        3 - The "suffix" variable
+
+        The autogenerated variable is a list, consisting of every
+        element of the source list, or a single element if the source
+        is a string, with the prefix and suffix
+        concatenated."""
+
+        for strVarAuto, strSrc, strPref, strSuff, in self.AUTO_GEN_VARS:
+            if self._dict.has_key(strSrc):
+                src_var = self._dict[strSrc]
+                if type(src_var) is types.ListType or \
+                   isinstance(src_var, UserList):
+                    src_var = map(str, src_var)
+                else:
+                    src_var = [ str(src_var), ]
+            else:
+                src_var = []
+
+            try:
+                prefix = str(self._dict[strPref])
+            except KeyError:
+                prefix=''
+
+            try:
+                suffix = str(self._dict[strSuff])
+            except KeyError:
+                suffix =''
+
+            self._dict[strVarAuto] = map(lambda x, suff=suffix, pref=prefix: \
+                                         pref + str(x) + suff,
+                                         src_var)
+
     def __cmp__(self, other):
 	return cmp(self._dict, other._dict)
 
 	construction variables and/or values.
 	"""
 	self._dict.update(copy.deepcopy(kw))
+        self.__autogenerate()
 
     def	Depends(self, target, dependency):
 	"""Explicity specify that 'target's depend on 'dependency'."""

src/engine/SCons/EnvironmentTests.py

 	"""
 	env = Environment(AAA = 'a', BBB = 'b')
 	str = env.subst("$AAA ${AAA}A $BBBB $BBB")
-	assert str == "a aA  b", str
+	assert str == "a aA b", str
 	env = Environment(AAA = '$BBB', BBB = 'b', BBBA = 'foo')
 	str = env.subst("$AAA ${AAA}A ${AAA}B $BBB")
-	assert str == "b foo  b", str
+	assert str == "b foo b", str
 	env = Environment(AAA = '$BBB', BBB = '$CCC', CCC = 'c')
 	str = env.subst("$AAA ${AAA}A ${AAA}B $BBB")
-	assert str == "c   c", str
+	assert str == "c c", str
 
-
+    def test_autogenerate(self):
+        """Test autogenerated environment variables."""
+        env = Environment(LIBS = [ 'foo', 'bar', 'baz' ],
+                          LIBLINKPREFIX = 'foo',
+                          LIBLINKSUFFIX = 'bar')
+        assert len(env.Dictionary('_LIBFLAGS')) == 3, env.Dictionary('_LIBFLAGS')
+        assert env.Dictionary('_LIBFLAGS')[0] == 'foofoobar', \
+               env.Dictionary('_LIBFLAGS')[0]
+        assert env.Dictionary('_LIBFLAGS')[1] == 'foobarbar', \
+               env.Dictionary('_LIBFLAGS')[1]
+        assert env.Dictionary('_LIBFLAGS')[2] == 'foobazbar', \
+               env.Dictionary('_LIBFLAGS')[2]
 
 if __name__ == "__main__":
     suite = unittest.makeSuite(EnvironmentTestCase, 'test_')

src/engine/SCons/Node/NodeTests.py

 
 
 built_it = None
+built_target =  None
+built_source =  None
 
 class Builder:
     def execute(self, **kw):
-	global built_it
+        global built_it, built_target, built_source
 	built_it = 1
+        built_target = kw['target']
+        built_source = kw['source']
         return 0
     def get_contents(self, env):
         return 7
     def test_build(self):
 	"""Test building a node
 	"""
+        class MyNode(SCons.Node.Node):
+            def __str__(self):
+                return self.path
 	# Make sure it doesn't blow up if no builder is set.
-	node = SCons.Node.Node()
+        node = MyNode()
 	node.build()
 	assert built_it == None
 
-	node = SCons.Node.Node()
+        node = MyNode()
 	node.builder_set(Builder())
 	node.env_set(Environment())
-	node.path = "xxx"	# XXX FAKE SUBCLASS ATTRIBUTE
-	node.sources = "yyy"	# XXX FAKE SUBCLASS ATTRIBUTE
+        node.path = "xxx"
+        node.sources = ["yyy", "zzz"]
 	node.build()
 	assert built_it
+        assert built_target == "xxx", built_target
+        assert built_source == ["yyy", "zzz"], built_source
 
     def test_builder_set(self):
 	"""Test setting a Node's Builder

src/engine/SCons/Node/__init__.py

         """Actually build the node.   Return the status from the build."""
 	if not self.builder:
 	    return None
-	sources_str = string.join(map(lambda x: str(x), self.sources))
-	stat = self.builder.execute(env = self.env.Dictionary(),
-				    target = str(self), source = sources_str)
+        sources = map(lambda x: str(x), self.sources)
+        stat = self.builder.execute(env = self.env.Dictionary(),
+                                    target = str(self), source = sources)
 	if stat != 0:
 	    raise BuildError(node = self, stat = stat)
 	return stat

src/engine/SCons/Util.py

 import re
 from UserList import UserList
 import SCons.Node.FS
+import cStringIO
 
 def scons_str2nodes(arg, node_factory=SCons.Node.FS.default_fs.File):
     """This function converts a string or list into a list of Node instances.
         # suffix and basepath.
         return self.__class__([ UserList.__getitem__(self, item), ])
 
+_cv = re.compile(r'\$([_a-zA-Z]\w*|{[^}]*})')
+_space_sep = re.compile(r'[\t ]+(?![^{]*})')
 
+def scons_subst_list(strSubst, locals, globals):
+    """
+    This function is similar to scons_subst(), but with
+    one important difference.  Instead of returning a single
+    string, this function returns a list of lists.
+    The first (outer) list is a list of lines, where the
+    substituted stirng has been broken along newline characters.
+    The inner lists are lists of command line arguments, i.e.,
+    the argv array that should be passed to a spawn or exec
+    function.
 
-_tok = r'[_a-zA-Z]\w*'
-_cv = re.compile(r'\$(%s|{%s(\[[-0-9:]*\])?(\.\w+)?})' % (_tok, _tok))
+    One important thing this guy does is preserve environment
+    variables that are lists.  For instance, if you have
+    an environment variable that is a Python list (or UserList-
+    derived class) that contains path names with spaces in them,
+    then the entire path will be returned as a single argument.
+    This is the only way to know where the 'split' between arguments
+    is for executing a command line."""
 
-def scons_subst(string, locals, globals):
+    def repl(m, locals=locals, globals=globals):
+        key = m.group(1)
+        if key[:1] == '{' and key[-1:] == '}':
+            key = key[1:-1]
+	try:
+            e = eval(key, locals, globals)
+            if not e:
+                s = ''
+            elif type(e) is types.ListType or \
+                 isinstance(e, UserList):
+                s = string.join(map(str, e), '\0')
+            else:
+                s = _space_sep.sub('\0', str(e))
+	except NameError:
+	    s = ''
+	return s
+    n = 1
+
+    # Tokenize the original string...
+    strSubst = _space_sep.sub('\0', strSubst)
+    
+    # Now, do the substitution
+    while n != 0:
+        strSubst, n = _cv.subn(repl, strSubst)
+    # Now parse the whole list into tokens.
+    listLines = string.split(strSubst, '\n')
+    return map(lambda x: filter(lambda y: y, string.split(x, '\0')),
+               listLines)
+
+def scons_subst(strSubst, locals, globals):
     """Recursively interpolates dictionary variables into
     the specified string, returning the expanded result.
     Variables are specified by a $ prefix in the string and
     surrounded by curly braces to separate the name from
     trailing characters.
     """
-    def repl(m, locals=locals, globals=globals):
-        key = m.group(1)
-        if key[:1] == '{' and key[-1:] == '}':
-            key = key[1:-1]
-	try:
-            e = eval(key, locals, globals)
-            if e is None:
-                s = ''
-            else:
-                s = str(e)
-	except NameError:
-	    s = ''
-	return s
-    n = 1
-    while n != 0:
-        string, n = _cv.subn(repl, string)
-    return string
-
+    cmd_list = scons_subst_list(strSubst, locals, globals)
+    return string.join(map(string.join, cmd_list), '\n')

src/engine/SCons/UtilTests.py

 import unittest
 import SCons.Node
 import SCons.Node.FS
-from SCons.Util import scons_str2nodes, scons_subst, PathList
+from SCons.Util import scons_str2nodes, scons_subst, PathList, scons_subst_list
 
 
 class UtilTestCase(unittest.TestCase):
         assert newcom == cvt("test foo")
 
         newcom = scons_subst("test $xxx", loc, {})
-        assert newcom == cvt("test "), newcom
+        assert newcom == cvt("test"), newcom
 
+    def test_subst_list(self):
+        """Testing the scons_subst_list() method..."""
+        loc = {}
+        loc['TARGETS'] = PathList(map(os.path.normpath, [ "./foo/bar.exe",
+                                                          "/bar/baz with spaces.obj",
+                                                          "../foo/baz.obj" ]))
+        loc['TARGET'] = loc['TARGETS'][0]
+        loc['SOURCES'] = PathList(map(os.path.normpath, [ "./foo/blah with spaces.cpp",
+                                                          "/bar/ack.cpp",
+                                                          "../foo/ack.c" ]))
+        loc['xxx'] = None
+        loc['NEWLINE'] = 'before\nafter'
 
+        if os.sep == '/':
+            def cvt(str):
+                return str
+        else:
+            def cvt(str):
+                return string.replace(str, '/', os.sep)
 
+        cmd_list = scons_subst_list("$TARGETS", loc, {})
+        assert cmd_list[0][1] == cvt("/bar/baz with spaces.obj"), cmd_list[0][1]
+
+        cmd_list = scons_subst_list("$SOURCES $NEWLINE $TARGETS", loc, {})
+        assert len(cmd_list) == 2, cmd_list
+        assert cmd_list[0][0] == cvt('foo/blah with spaces.cpp'), cmd_list[0][0]
+        assert cmd_list[1][2] == cvt("/bar/baz with spaces.obj"), cmd_list[1]
+
+        cmd_list = scons_subst_list("$SOURCES$NEWLINE", loc, {})
+        assert len(cmd_list) == 2, cmd_list
+        assert cmd_list[1][0] == 'after', cmd_list[1][0]
+        assert cmd_list[0][2] == cvt('../foo/ack.cbefore'), cmd_list[0][2]
+        
 if __name__ == "__main__":
     suite = unittest.makeSuite(UtilTestCase, 'test_')
     if not unittest.TextTestRunner().run(suite).wasSuccessful():
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.