From 74f98d3083cfbb859bf032dba37ed14bbb5219dd Mon Sep 17 00:00:00 2001 From: Steven Knight Date: Mon, 22 Apr 2002 19:21:26 +0000 Subject: Several bug fixes from Charles Crain. --- src/CHANGES.txt | 7 +++ src/engine/SCons/Action.py | 40 +++++++++++++-- src/engine/SCons/ActionTests.py | 55 +++++++++++++++++--- src/engine/SCons/Builder.py | 50 ++++++++++++++++-- src/engine/SCons/BuilderTests.py | 23 +++++++++ src/engine/SCons/Defaults.py | 100 ++++++++++++++++++------------------ src/engine/SCons/Node/FS.py | 6 ++- src/engine/SCons/Node/FSTests.py | 2 + src/engine/SCons/Script/__init__.py | 2 + src/engine/SCons/Util.py | 23 ++++++++- src/engine/SCons/UtilTests.py | 18 +++++-- test/YACC.py | 8 ++- test/long-lines.py | 9 ++++ 13 files changed, 273 insertions(+), 70 deletions(-) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 29857f9..b7b07e4 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -58,6 +58,13 @@ RELEASE 0.07 - - ListBuilder now passes all targets to the action, not just the first. + - Fix so that -c now deletes generated yacc .h files. + + - Builder actions and emitter functions can now be initialized, through + construction variables, to things other than strings. + + - Make top-relative '#/dir' lookups work like '#dir'. + From Steven Knight: - Fix so that -c -n does *not* remove the targets! diff --git a/src/engine/SCons/Action.py b/src/engine/SCons/Action.py index 38b5413..1941e1a 100644 --- a/src/engine/SCons/Action.py +++ b/src/engine/SCons/Action.py @@ -198,6 +198,15 @@ def _do_create_action(act): elif callable(act): return FunctionAction(act) elif SCons.Util.is_String(act): + var=SCons.Util.get_environment_var(act) + if var: + # This looks like a string that is purely an Environment + # variable reference, like "$FOO" or "${FOO}". We do + # something special here...we lazily evaluate the contents + # of that Environment variable, so a user could but something + # like a function or a CommandGenerator in that variable + # instead of a string. + return CommandGeneratorAction(LazyCmdGenerator(var)) listCmds = map(lambda x: CommandAction(string.split(x)), string.split(act, '\n')) if len(listCmds) == 1: @@ -314,11 +323,19 @@ class EnvDictProxy(UserDict.UserDict): def __init__(self, env): UserDict.UserDict.__init__(self, env) - def subst(self, string): - return SCons.Util.scons_subst(string, self.data, {}, _rm) + def subst(self, string, raw=0): + if raw: + regex_remove = None + else: + regex_remove = _rm + return SCons.Util.scons_subst(string, self.data, {}, regex_remove) - def subst_list(self, string): - return SCons.Util.scons_subst_list(string, self.data, {}, _rm) + def subst_list(self, string, raw=0): + if raw: + regex_remove = None + else: + regex_remove = _rm + return SCons.Util.scons_subst_list(string, self.data, {}, regex_remove) class CommandAction(ActionBase): """Class for command-execution actions.""" @@ -410,6 +427,21 @@ class CommandGeneratorAction(ActionBase): """ return apply(self.__generate(kw).get_contents, (), kw) +class LazyCmdGenerator: + """This is a simple callable class that acts as a command generator. + It holds on to a key into an Environment dictionary, then waits + until execution time to see what type it is, then tries to + create an Action out of it.""" + def __init__(self, var): + self.var = SCons.Util.to_String(var) + + def __call__(self, env, **kw): + if env.has_key(self.var): + return env[self.var] + else: + # The variable reference substitutes to nothing. + return '' + class FunctionAction(ActionBase): """Class for Python function actions.""" def __init__(self, function): diff --git a/src/engine/SCons/ActionTests.py b/src/engine/SCons/ActionTests.py index 648b77b..cda565d 100644 --- a/src/engine/SCons/ActionTests.py +++ b/src/engine/SCons/ActionTests.py @@ -178,14 +178,21 @@ class CommandGeneratorActionTestCase(unittest.TestCase): def f(dummy, env, self=self): self.dummy = dummy - assert env.subst('$FOO') == 'foo baz\nbar ack', env.subst('$FOO') - assert env.subst_list('$FOO') == [ [ 'foo', 'baz' ], - [ 'bar', 'ack' ] ], env.subst_list('$FOO') + assert env.subst("$FOO $( bar $) baz") == 'foo baz\nbar ack bar baz', env.subst("$FOO $( bar $) baz") + assert env.subst("$FOO $( bar $) baz", raw=1) == 'foo baz\nbar ack $( bar $) baz', env.subst("$FOO $( bar $) baz", raw=1) + assert env.subst_list("$FOO $( bar $) baz") == [ [ 'foo', 'baz' ], + [ 'bar', 'ack', 'bar', 'baz' ] ], env.subst_list("$FOO $( bar $) baz") + assert env.subst_list("$FOO $( bar $) baz", + raw=1) == [ [ 'foo', 'baz' ], + [ 'bar', 'ack', '$(', 'bar', '$)', 'baz' ] ], env.subst_list("$FOO $( bar $) baz", raw=1) return "$FOO" def func_action(env, dummy, self=self): - assert env.subst('$foo') == 'bar', env.subst('$foo') - assert env.subst_list('$foo') == [ [ 'bar' ] ], env.subst_list('$foo') - assert env.subst_list([ '$foo', 'bar' ]) == [[ 'bar', 'bar' ]], env.subst_list([ [ '$foo', 'bar' ] ]) + assert env.subst('$foo $( bar $)') == 'bar bar', env.subst('$foo $( bar $)') + assert env.subst('$foo $( bar $)', + raw=1) == 'bar $( bar $)', env.subst('$foo $( bar $)', raw=1) + assert env.subst_list([ '$foo', '$(', 'bar', '$)' ]) == [[ 'bar', 'bar' ]], env.subst_list([ '$foo', '$(', 'bar', '$)' ]) + assert env.subst_list([ '$foo', '$(', 'bar', '$)' ], + raw=1) == [[ 'bar', '$(', 'bar', '$)' ]], env.subst_list([ '$foo', '$(', 'bar', '$)' ], raw=1) self.dummy=dummy def f2(dummy, env, f=func_action): return f @@ -291,6 +298,39 @@ class ListActionTestCase(unittest.TestCase): c = a.get_contents(target=[], source=[]) assert c == "xyz", c +class LazyActionTestCase(unittest.TestCase): + def test_init(self): + """Test creation of a lazy-evaluation Action + """ + # Environment variable references should create a special + # type of CommandGeneratorAction that lazily evaluates the + # variable. + a9 = SCons.Action.Action('$FOO') + assert isinstance(a9, SCons.Action.CommandGeneratorAction), a9 + assert a9.generator.var == 'FOO', a9.generator.var + + a10 = SCons.Action.Action('${FOO}') + assert isinstance(a9, SCons.Action.CommandGeneratorAction), a10 + assert a10.generator.var == 'FOO', a10.generator.var + + def test_execute(self): + """Test executing a lazy-evalueation Action + """ + def f(s, env): + s.test=1 + return 0 + a = SCons.Action.Action('$BAR') + a.execute(s = self, env={'BAR':f}) + assert self.test == 1, self.test + + def test_get_contents(self): + """Test fetching the contents of a lazy-evaluation Action + """ + a = SCons.Action.Action("${FOO}") + c = a.get_contents(target=[], source=[], + env={'FOO':[["This", "is", "$(", "a", "$)", "test"]]}) + assert c == "This is test", c + if __name__ == "__main__": suite = unittest.TestSuite() @@ -300,7 +340,8 @@ if __name__ == "__main__": for tclass in [CommandActionTestCase, CommandGeneratorActionTestCase, FunctionActionTestCase, - ListActionTestCase]: + ListActionTestCase, + LazyActionTestCase]: for func in ["test_init", "test_execute", "test_get_contents"]: suite.addTest(tclass(func)) if not unittest.TextTestRunner().run(suite).wasSuccessful(): diff --git a/src/engine/SCons/Builder.py b/src/engine/SCons/Builder.py index 2a1b7d8..05330e4 100644 --- a/src/engine/SCons/Builder.py +++ b/src/engine/SCons/Builder.py @@ -82,6 +82,17 @@ def Builder(**kw): action_dict = kw['action'] kw['action'] = SCons.Action.CommandGenerator(DictCmdGenerator(action_dict)) kw['src_suffix'] = action_dict.keys() + + if kw.has_key('emitter') and \ + SCons.Util.is_String(kw['emitter']): + # This allows users to pass in an Environment + # variable reference (like "$FOO") as an emitter. + # We will look in that Environment variable for + # a callable to use as the actual emitter. + var = SCons.Util.get_environment_var(kw['emitter']) + if not var: + raise UserError, "Supplied emitter '%s' does not appear to refer to an Environment variable" % kw['emitter'] + kw['emitter'] = EmitterProxy(var) if kw.has_key('src_builder'): return apply(MultiStepBuilder, (), kw) @@ -129,6 +140,33 @@ def _adjust_suffix(suff): return '.' + suff return suff +class EmitterProxy: + """This is a callable class that can act as a + Builder emitter. It holds on to a string that + is a key into an Environment dictionary, and will + look there at actual build time to see if it holds + a callable. If so, we will call that as the actual + emitter.""" + def __init__(self, var): + self.var = SCons.Util.to_String(var) + + def __call__(self, target, source, env, **kw): + emitter = self.var + + # Recursively substitue the variable. + # We can't use env.subst() because it deals only + # in strings. Maybe we should change that? + while SCons.Util.is_String(emitter) and \ + env.has_key(emitter): + emitter = env[emitter] + if not callable(emitter): + return (target, source) + args = { 'target':target, + 'source':source, + 'env':env } + args.update(kw) + return apply(emitter, (), args) + class BuilderBase: """Base class for Builders, objects that create output nodes (files) from input nodes (files). @@ -374,9 +412,15 @@ class MultiStepBuilder(BuilderBase): dictArgs['env'] = env tgt = apply(src_bld, (), dictArgs) if not SCons.Util.is_List(tgt): - final_sources.append(tgt) - else: - final_sources.extend(tgt) + tgt = [ tgt ] + + # Only supply the builder with sources it is capable + # of building. + tgt = filter(lambda x, + suf=self.src_suffixes(env, kw): + os.path.splitext(SCons.Util.to_String(x))[1] in \ + suf, tgt) + final_sources.extend(tgt) else: final_sources.append(snode) dictKwArgs = kw diff --git a/src/engine/SCons/BuilderTests.py b/src/engine/SCons/BuilderTests.py index e30079c..12178ed 100644 --- a/src/engine/SCons/BuilderTests.py +++ b/src/engine/SCons/BuilderTests.py @@ -86,6 +86,10 @@ class Environment: return {} def autogenerate(self, dir=''): return {} + def __getitem__(self, item): + return self.d[item] + def has_key(self, item): + return self.d.has_key(item) env = Environment() @@ -743,6 +747,25 @@ class BuilderTestCase(unittest.TestCase): assert 'foo' in map(str, tgt.sources), map(str, tgt.sources) assert 'bar' in map(str, tgt.sources), map(str, tgt.sources) + env2=Environment(FOO=emit) + builder2=SCons.Builder.Builder(name="builder2", action='foo', + emitter="$FOO") + + tgt = builder2(env2, target='foo', source='bar') + assert str(tgt) == 'foo', str(tgt) + assert str(tgt.sources[0]) == 'bar', str(tgt.sources[0]) + + tgt = builder2(env2, target='foo', source='bar', foo=1) + assert len(tgt) == 2, len(tgt) + assert 'foo' in map(str, tgt), map(str, tgt) + assert 'bar' in map(str, tgt), map(str, tgt) + + tgt = builder2(env2, target='foo', source='bar', bar=1) + assert str(tgt) == 'foo', str(tgt) + assert len(tgt.sources) == 2, len(tgt.sources) + assert 'foo' in map(str, tgt.sources), map(str, tgt.sources) + assert 'bar' in map(str, tgt.sources), map(str, tgt.sources) + if __name__ == "__main__": suite = unittest.makeSuite(BuilderTestCase, 'test_') if not unittest.TextTestRunner().run(suite).wasSuccessful(): diff --git a/src/engine/SCons/Defaults.py b/src/engine/SCons/Defaults.py index 8856db5..6acf4de 100644 --- a/src/engine/SCons/Defaults.py +++ b/src/engine/SCons/Defaults.py @@ -77,17 +77,28 @@ class SharedCmdGenerator: return self.action_shared else: return self.action_static - + +def yaccEmitter(target, source, env, **kw): + # Yacc can be configured to emit a .h file as well + # as a .c file. Append that as a target. + if len(source) and os.path.splitext(SCons.Util.to_String(source[0]))[1] in \ + [ '.y', '.yy']: + target.append(os.path.splitext(SCons.Util.to_String(target[0]))[0] + \ + '.h') + return (target, source) + CFile = SCons.Builder.Builder(name = 'CFile', action = { '.l' : '$LEXCOM', '.y' : '$YACCCOM', }, + emitter = yaccEmitter, suffix = '$CFILESUFFIX') CXXFile = SCons.Builder.Builder(name = 'CXXFile', action = { '.ll' : '$LEXCOM', '.yy' : '$YACCCOM', }, + emitter = yaccEmitter, suffix = '$CXXFILESUFFIX') CXXAction = SCons.Action.Action("$CXXCOM") @@ -134,22 +145,33 @@ Object = SCons.Builder.Builder(name = 'Object', src_suffix = static_obj.src_suffixes(), src_builder = [CFile, CXXFile]) -def win32LinkGenerator(env, target, source, **kw): - cmd = env.subst_list([ '$LINK', '$LINKFLAGS', '/OUT:' + str(target[0]) ])[0] - cmd.extend(['$('] + env.subst_list('$_LIBDIRFLAGS')[0] + ['$)']) - cmd.extend(env.subst_list('$_LIBFLAGS')[0]) - cmd.extend(map(lambda x: str(x), source)) +def win32TempFileMunge(env, cmd_list): + """Given a list of command line arguments, see if it is too + long to pass to the win32 command line interpreter. If so, + create a temp file, then pass "@tempfile" as the sole argument + to the supplied command (which is the first element of cmd_list). + Otherwise, just return [cmd_list].""" + cmd = env.subst_list(cmd_list)[0] cmdlen = reduce(lambda x, y: x + len(y), cmd, 0) + len(cmd) if cmdlen <= 2048: - return [cmd] + return [cmd_list] else: import tempfile - tmp = tempfile.mktemp() - args = filter(lambda x: x != '$(' and x != '$)', cmd[1:]) - args = map(SCons.Util.quote_spaces, args) + # We do a normpath because mktemp() has what appears to be + # a bug in Win32 that will use a forward slash as a path + # delimiter. Win32's link mistakes that for a command line + # switch and barfs. + tmp = os.path.normpath(tempfile.mktemp()) + args = map(SCons.Util.quote_spaces, cmd[1:]) open(tmp, 'w').write(string.join(args, " ") + "\n") return [ [cmd[0], '@' + tmp], ['del', tmp] ] + +def win32LinkGenerator(env, target, source, **kw): + args = [ '$LINK', '$LINKFLAGS', '/OUT:%s' % target[0], + '$(', '$_LIBDIRFLAGS', '$)', '$_LIBFLAGS' ] + args.extend(map(SCons.Util.to_String, source)) + return win32TempFileMunge(env, args) kw = { 'name' : 'Program', @@ -197,7 +219,7 @@ def win32LibGenerator(target, source, env, shared=1): else: # Just treat it as a generic source file. listCmd.append(str(src)) - return [ listCmd ] + return win32TempFileMunge(env, listCmd) def win32LibEmitter(target, source, env, shared=0): if shared: @@ -226,32 +248,19 @@ def win32LibEmitter(target, source, env, shared=0): env.subst("$LIBSUFFIX"))) return (target, source) -PosixLibrary = SCons.Builder.Builder(name = 'Library', - generator = \ - SharedCmdGenerator(shared="$SHLINKCOM", - static="$ARCOM"), - prefix = \ - LibAffixGenerator(static='$LIBPREFIX', - shared='$SHLIBPREFIX'), - suffix = \ - LibAffixGenerator(static='$LIBSUFFIX', - shared='$SHLIBSUFFIX'), - src_suffix = '$OBJSUFFIX', - src_builder = Object) - -Win32Library = SCons.Builder.Builder(name = 'Library', - generator = \ - SharedCmdGenerator(shared=SCons.Action.CommandGeneratorAction(win32LibGenerator), - static="$ARCOM"), - emitter = win32LibEmitter, - prefix = \ - LibAffixGenerator(static='$LIBPREFIX', - shared='$SHLIBPREFIX'), - suffix = \ - LibAffixGenerator(static='$LIBSUFFIX', - shared='$SHLIBSUFFIX'), - src_suffix = '$OBJSUFFIX', - src_builder = Object) +Library = SCons.Builder.Builder(name = 'Library', + generator = \ + SharedCmdGenerator(shared="$SHLINKCOM", + static="$ARCOM"), + emitter="$LIBEMITTER", + prefix = \ + LibAffixGenerator(static='$LIBPREFIX', + shared='$SHLIBPREFIX'), + suffix = \ + LibAffixGenerator(static='$LIBSUFFIX', + shared='$SHLIBSUFFIX'), + src_suffix = '$OBJSUFFIX', + src_builder = Object) LaTeXAction = SCons.Action.Action('$LATEXCOM') @@ -414,14 +423,10 @@ def make_win32_env_from_paths(include, lib, path): 'SHF77PPCOM' : '$SHF77 $SHF77FLAGS $CPPFLAGS $_INCFLAGS /c $SOURCES /Fo$TARGET', 'LINK' : 'link', 'LINKFLAGS' : '/nologo', - # XXX - We'd like to do this as follows, but '$LINKCOM' in - # a Builder above gets expanded too soon to stick a function - # right in the environment like this. Revisit this when this - # capability has been added (cf. bug report #537058). - #'LINKCOM' : win32Link, + 'LINKCOM' : SCons.Action.CommandGenerator(win32LinkGenerator), 'SHLINK' : '$LINK', 'SHLINKFLAGS': '$LINKFLAGS /dll', - 'SHLINKCOM' : '$SHLINK $SHLINKFLAGS /OUT:$TARGET $_LIBDIRFLAGS $_LIBFLAGS $SOURCES', + 'SHLINKCOM' : SCons.Action.CommandGenerator(win32LibGenerator), 'AR' : 'lib', 'ARFLAGS' : '/nologo', 'ARCOM' : '$AR $ARFLAGS /OUT:$TARGET $SOURCES', @@ -449,7 +454,7 @@ def make_win32_env_from_paths(include, lib, path): 'PSCOM' : '$DVIPS $DVIPSFLAGS -o $TARGET $SOURCES', 'PSPREFIX' : '', 'PSSUFFIX' : '.ps', - 'BUILDERS' : [Alias, CFile, CXXFile, DVI, Win32Library, Object, + 'BUILDERS' : [Alias, CFile, CXXFile, DVI, Library, Object, PDF, PostScript, Program], 'SCANNERS' : [CScan], 'OBJPREFIX' : '', @@ -464,6 +469,7 @@ def make_win32_env_from_paths(include, lib, path): 'LIBDIRSUFFIX' : '', 'LIBLINKPREFIX' : '', 'LIBLINKSUFFIX' : '$LIBSUFFIX', + 'LIBEMITTER' : win32LibEmitter, 'INCPREFIX' : '/I', 'INCSUFFIX' : '', 'WIN32DEFPREFIX' : '/def:', @@ -491,8 +497,6 @@ def make_win32_env(version): if os.name == 'posix': - Library = PosixLibrary - arcom = '$AR $ARFLAGS $TARGET $SOURCES' ranlib = 'ranlib' if SCons.Util.WhereIs(ranlib): @@ -557,7 +561,7 @@ if os.name == 'posix': 'PSCOM' : '$DVIPS $DVIPSFLAGS -o $TARGET $SOURCES', 'PSPREFIX' : '', 'PSSUFFIX' : '.ps', - 'BUILDERS' : [Alias, CFile, CXXFile, DVI, PosixLibrary, Object, + 'BUILDERS' : [Alias, CFile, CXXFile, DVI, Library, Object, PDF, PostScript, Program], 'SCANNERS' : [CScan], 'OBJPREFIX' : '', @@ -578,8 +582,6 @@ if os.name == 'posix': } elif os.name == 'nt': - Library = Win32Library - versions = None try: versions = get_devstudio_versions() diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index 1c506c9..861fbaf 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -204,7 +204,11 @@ class FS: self.__setTopLevelDir() if name[0] == '#': directory = self.Top - name = os.path.join('./', name[1:]) + name = os.path.normpath(name[1:]) + if name[0] == os.sep: + # Correct such that '#/foo' is equivalent + # to '#foo'. + name = name[1:] elif not directory: directory = self._cwd return (os.path.normpath(name), directory) diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py index 6b35adb..0259deb 100644 --- a/src/engine/SCons/Node/FSTests.py +++ b/src/engine/SCons/Node/FSTests.py @@ -232,6 +232,8 @@ class FSTestCase(unittest.TestCase): Dir_test('.', './', sub_dir, sub) Dir_test('./.', './', sub_dir, sub) Dir_test('foo/./bar', 'foo/bar/', sub_dir_foo_bar, 'foo/') + Dir_test('#foo/bar', 'foo/bar/', sub_dir_foo_bar, 'foo/') + Dir_test('#/foo/bar', 'foo/bar/', sub_dir_foo_bar, 'foo/') try: f2 = fs.File(string.join(['f1', 'f2'], sep), directory = d1) diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py index 09b85be..105c28f 100644 --- a/src/engine/SCons/Script/__init__.py +++ b/src/engine/SCons/Script/__init__.py @@ -124,6 +124,8 @@ class CleanTask(SCons.Taskmaster.Task): os.unlink(t.path) except OSError: pass + else: + print "Removed " + t.path except IndexError: pass diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py index 0abbd1e..08edde7 100644 --- a/src/engine/SCons/Util.py +++ b/src/engine/SCons/Util.py @@ -139,6 +139,23 @@ class PathList(UserList.UserList): # suffix and basepath. return self.__class__([ UserList.UserList.__getitem__(self, item), ]) +_env_var = re.compile(r'^\$([_a-zA-Z]\w*|{[^}]*})$') + +def get_environment_var(varstr): + """Given a string, first determine if it looks like a reference + to a single environment variable, like "$FOO" or "${FOO}". + If so, return that variable with no decorations ("FOO"). + If not, return None.""" + mo=_env_var.match(to_String(varstr)) + if mo: + var = mo.group(1) + if var[0] == '{': + return var[1:-1] + else: + return var + else: + return None + def quote_spaces(arg): if ' ' in arg or '\t' in arg: return '"%s"' % arg @@ -272,8 +289,10 @@ def is_List(e): def to_String(s): """Better than str() because it will preserve a unicode object without converting it to ASCII.""" - if is_String(s): - return s + if hasattr(types, 'UnicodeType') and \ + (type(s) is types.UnicodeType or \ + (isinstance(s, UserString) and type(s.data) is types.UnicodeType)): + return unicode(s) else: return str(s) diff --git a/src/engine/SCons/UtilTests.py b/src/engine/SCons/UtilTests.py index b424506..34dba99 100644 --- a/src/engine/SCons/UtilTests.py +++ b/src/engine/SCons/UtilTests.py @@ -268,25 +268,29 @@ class UtilTestCase(unittest.TestCase): import UserString s1=UserString.UserString('blah') - assert to_String(s1) is s1, s1 + assert to_String(s1) == s1, s1 assert to_String(s1) == 'blah', s1 class Derived(UserString.UserString): pass s2 = Derived('foo') - assert to_String(s2) is s2, s2 + assert to_String(s2) == s2, s2 assert to_String(s2) == 'foo', s2 if hasattr(types, 'UnicodeType'): s3=UserString.UserString(unicode('bar')) - assert to_String(s3) is s3, s3 + assert to_String(s3) == s3, s3 assert to_String(s3) == unicode('bar'), s3 + assert type(to_String(s3)) is types.UnicodeType, \ + type(to_String(s3)) except ImportError: pass if hasattr(types, 'UnicodeType'): s4 = unicode('baz') assert to_String(s4) == unicode('baz'), to_String(s4) + assert type(to_String(s4)) is types.UnicodeType, \ + type(to_String(s4)) def test_WhereIs(self): test = TestCmd.TestCmd(workdir = '') @@ -349,6 +353,14 @@ class UtilTestCase(unittest.TestCase): wi = WhereIs('xxx', path = pathdirs_1234, pathext = '.BAT;.EXE') assert string.lower(wi) == string.lower(test.workpath(sub3_xxx_exe)), wi + def test_get_env_var(self): + """Testing get_environment_var().""" + assert get_environment_var("$FOO") == "FOO", get_environment_var("$FOO") + assert get_environment_var("${BAR}") == "BAR", get_environment_var("${BAR}") + assert get_environment_var("${BAR}FOO") == None, get_environment_var("${BAR}FOO") + assert get_environment_var("$BAR ") == None, get_environment_var("$BAR ") + assert get_environment_var("FOO$BAR") == None, get_environment_var("FOO$BAR") + if __name__ == "__main__": suite = unittest.makeSuite(UtilTestCase, 'test_') if not unittest.TextTestRunner().run(suite).wasSuccessful(): diff --git a/test/YACC.py b/test/YACC.py index 3e8ea35..486200c 100644 --- a/test/YACC.py +++ b/test/YACC.py @@ -98,7 +98,7 @@ os.system(string.join(sys.argv[1:], " ")) """ % string.replace(test.workpath('wrapper.out'), '\\', '\\\\')) test.write('SConstruct', """ -foo = Environment() +foo = Environment(YACCFLAGS='-d') yacc = foo.Dictionary('YACC') bar = Environment(YACC = r'%s wrapper.py ' + yacc) foo.Program(target = 'foo', source = 'foo.y') @@ -150,4 +150,10 @@ newline: '\n'; test.run(program = test.workpath('bar'), stdin = "b\n", stdout = "bar.y\n") + test.fail_test(not os.path.exists(test.workpath('foo.h'))) + + test.run(arguments = '-c .') + + test.fail_test(os.path.exists(test.workpath('foo.h'))) + test.pass_test() diff --git a/test/long-lines.py b/test/long-lines.py index bde101a..9cf24d8 100644 --- a/test/long-lines.py +++ b/test/long-lines.py @@ -25,6 +25,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os +import os.path import string import sys import TestSCons @@ -32,8 +33,12 @@ import TestSCons test = TestSCons.TestSCons() if sys.platform == 'win32': + lib_='' + _dll = '.dll' linkflag = '/LIBPATH:' + test.workpath() else: + lib_='lib' + _dll='.so' linkflag = '-L' + test.workpath() test.write('SConstruct', """ @@ -42,6 +47,8 @@ while len(linkflags) <= 8100: linkflags = linkflags + r' %s' env = Environment(LINKFLAGS = '$LINKXXX', LINKXXX = linkflags) env.Program(target = 'foo', source = 'foo.c') +# Library(shared=1) uses $LINKFLAGS by default. +env.Library(target = 'bar', source = 'foo.c', shared=1) """ % (linkflag, linkflag)) test.write('foo.c', r""" @@ -58,4 +65,6 @@ test.run(arguments = '.') test.run(program = test.workpath('foo'), stdout = "foo.c\n") +test.fail_test(not os.path.exists(lib_+'bar'+_dll)) + test.pass_test() -- cgit v0.12