From: stevenknight Date: Thu, 3 Oct 2002 21:01:02 +0000 (+0000) Subject: Add MSVC PCH and PDB support. (Anthony Roach) X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=7b1ad0b713a91a2262f711014d9f2828572fb9fa;p=scons.git Add MSVC PCH and PDB support. (Anthony Roach) git-svn-id: http://scons.tigris.org/svn/scons/trunk@473 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- diff --git a/doc/man/scons.1 b/doc/man/scons.1 index 47e21410..34cbcd4c 100644 --- a/doc/man/scons.1 +++ b/doc/man/scons.1 @@ -902,6 +902,19 @@ A synonym for the .B StaticObject builder. +.IP PCH +Builds a Microsoft Visual C++ precompiled header. Calling this builder +returns a list of two targets: the PCH as the first element, and the object +file as the second element. Normally the object file is ignored. This builder is only +provided when Microsoft Visual C++ is being used as the compiler. +The PCH builder is generally used in +conjuction with the PCH construction variable to force object files to use +the precompiled header: + +.ES +env['PCH'] = env.PCH('StdAfx.cpp')[0] +.EE + .IP Program Builds an executable given one or more object files or C, C++ or Fortran source files. @@ -1787,6 +1800,47 @@ The prefix used for (static) object file names. .IP OBJSUFFIX The suffix used for (static) object file names. +.IP PCH +The Microsoft Visual C++ precompiled header that will be used when compiling +object files. This variable is ignored by tools other than Microsoft Visual C++. +When this variable is +defined SCons will add options to the compiler command line to +cause it to use the precompiled header, and will also set up the +dependencies for the PCH file. This variable must reference a File instance created either +with File() or returned by the PCH builder: + +.ES +env['PCH'] = env.PCH('StdAfx.cpp')[0] +.EE + +.IP PCHSTOP +This variable specifies how much of a source file is precompiled. This +variable is ignored by tools other than Microsoft Visual C++, or when +the PCH variable is not being used. When this variable is define it +must be a string that is the name of the header that +is included at the end of the precompiled portion of the source files, or +the empty string if the "#pragma hrdstop" construct is being used: + +.ES +env['PCHSTOP'] = File('StdAfx.h') +.EE + + + +.IP PDB +The Microsoft Visual C++ PDB file that will store debugging information for +object files, shared libraries, and programs. This variable is ignored by +tools other than Microsoft Visual C++. +When this variable is +defined SCons will add options to the compiler and linker command line to +cause them to generate external debugging information, and will also set up the +dependencies for the PDB file. This variable must reference +a File instance created with File(): + +.ES +env['PDB'] = File('hello.pdb') +.EE + .IP PDFCOM The command line used to convert TeX DVI files into a PDF file. @@ -3202,6 +3256,72 @@ CC: The C compiler. .EE +.SS Using Microsoft Visual C++ precompiled headers + +Since windows.h includes everything and the kitchen sink, it can take quite +some time to compile it over and over again for a bunch of object files, so +Microsoft provides a mechanism to compile a set of headers once and then +include the previously compiled headers in any object file. This +technology is called precompiled headers. The general recipe is to create a +file named "StdAfx.cpp" that includes a single header named "StdAfx.h", and +then include every header you want to precompile in "StdAfx.h", and finally +include "StdAfx.h" as the first header in all the source files you are +compiling to object files. For example: + +StdAfx.h: +.ES +#include +#include +.EE + +StdAfx.cpp: +.ES +#include +.EE + +Foo.cpp: +.ES +#include + +/* do some stuff */ +.EE + +Bar.cpp: +.ES +#include + +/* do some other stuff */ +.EE + +SConstruct: +.ES +env=Environment() +env['PCHSTOP'] = File('StdAfx.h') +env['PCH'] = env.PCH('StdAfx.cpp')[0] +env.Program('MyApp', ['Foo.cpp', 'Bar.cpp']) +.EE + +For more information see the document for the PCH builder, and the PCH and +PCHSTOP construction variables. To learn about the details of precompiled +headers consult the MSDN documention for /Yc, /Yu, and /Yp. + +.SS Using Microsoft Visual C++ external debugging information + +Since including debugging information in programs and shared libraries can +cause their size to increase significantly, Microsoft provides a mechanism +for including the debugging information in an external file called a PDB +file. SCons supports PDB files through the PDB construction +variable. + +SConstruct: +.ES +env=Environment() +env['PDB'] = File('MyApp.pdb') +env.Program('MyApp', ['Foo.cpp', 'Bar.cpp']) +.EE + +For more information see the document for the PDB construction variable. + .SH ENVIRONMENT .IP SCONS_LIB_DIR diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 0d506287..838e178e 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -79,6 +79,9 @@ RELEASE 0.09 - - Add an Options() object for friendlier accomodation of command- line arguments. + - Add support for Microsoft VC++ precompiled header (.pch) + and debugger (.pdb) files. + From sam th: - Dynamically check for the existence of utilities with which to diff --git a/src/engine/SCons/ActionTests.py b/src/engine/SCons/ActionTests.py index 6ce52d56..289e7fe4 100644 --- a/src/engine/SCons/ActionTests.py +++ b/src/engine/SCons/ActionTests.py @@ -40,7 +40,8 @@ import TestCmd import UserDict import SCons.Environment -Environment = SCons.Environment.EnvProxy +def Environment(dict): + return apply(SCons.Environment.Environment, (), dict) class ActionTestCase(unittest.TestCase): diff --git a/src/engine/SCons/Defaults.py b/src/engine/SCons/Defaults.py index d70be0d2..4e8cf4e8 100644 --- a/src/engine/SCons/Defaults.py +++ b/src/engine/SCons/Defaults.py @@ -133,6 +133,7 @@ ASPPAction = SCons.Action.Action([ StaticCheckSet, "$ASPPCOM" ]) def StaticObject(): """A function for generating the static object Builder.""" return SCons.Builder.Builder(action = {}, + emitter="$OBJEMITTER", prefix = '$OBJPREFIX', suffix = '$OBJSUFFIX', src_builder = ['CFile', 'CXXFile']) @@ -142,6 +143,7 @@ def SharedObject(): return SCons.Builder.Builder(action = {}, prefix = '$SHOBJPREFIX', suffix = '$SHOBJSUFFIX', + emitter="$OBJEMITTER", src_builder = ['CFile', 'CXXFile']) ProgScan = SCons.Scanner.Prog.ProgScan() @@ -176,6 +178,7 @@ def PDF(): suffix = '$PDFSUFFIX') Program = SCons.Builder.Builder(action=[ StaticCheck, '$LINKCOM' ], + emitter='$PROGEMITTER', prefix='$PROGPREFIX', suffix='$PROGSUFFIX', src_suffix='$OBJSUFFIX', diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py index 24315a10..1a1dd49c 100644 --- a/src/engine/SCons/Environment.py +++ b/src/engine/SCons/Environment.py @@ -111,42 +111,6 @@ class BuilderDict(UserDict): _rm = re.compile(r'\$[()]') -class EnvProxy(UserDict): - """This is a dictionary-like class that is returned - by Environment.Override(). - - In addition to providing - normal dictionary-like access to the variables in the - Environment, it also exposes the functions subst() - and subst_list(), allowing users to easily do variable - interpolation when writing their FunctionActions - and CommandGeneratorActions.""" - - def __init__(self, env): - UserDict.__init__(self, env) - - 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, raw=0): - if raw: - regex_remove = None - else: - regex_remove = _rm - return SCons.Util.scons_subst_list(string, self.data, {}, regex_remove) - - def Override(self, overrides): - if overrides: - proxy = EnvProxy(self) - proxy.update(overrides) - return proxy - else: - return self - class Environment: """Base class for construction Environments. These are the primary objects used to communicate dependency and @@ -453,8 +417,8 @@ class Environment: return side_effects[0] else: return side_effects - - def subst(self, string): + + def subst(self, string, raw=0): """Recursively interpolates construction variables from the Environment into the specified string, returning the expanded result. Construction variables are specified by a $ prefix @@ -464,12 +428,20 @@ class Environment: may be surrounded by curly braces to separate the name from trailing characters. """ - return SCons.Util.scons_subst(string, self._dict, {}) - - def subst_list(self, string): + if raw: + regex_remove = None + else: + regex_remove = _rm + return SCons.Util.scons_subst(string, self._dict, {}, regex_remove) + + def subst_list(self, string, raw=0): """Calls through to SCons.Util.scons_subst_list(). See the documentation for that function.""" - return SCons.Util.scons_subst_list(string, self._dict, {}) + if raw: + regex_remove = None + else: + regex_remove = _rm + return SCons.Util.scons_subst_list(string, self._dict, {}, regex_remove) def get_scanner(self, skey): """Find the appropriate scanner given a key (usually a file suffix). @@ -518,17 +490,23 @@ class Environment: def Override(self, overrides): """ - Produce a modified psuedo-environment whose variables + Produce a modified environment whose variables are overriden by the overrides dictionaries. - overrides - a dictionaru that will override + overrides - a dictionary that will override the variables of this environment. + + This function is much more efficient than Copy() + or creating a new Environment because it doesn't do + a deep copy of the dictionary, and doesn't do a copy + at all if there are no overrides. """ if overrides: - proxy = EnvProxy(self._dict) - proxy.update(overrides) - return proxy + env = copy.copy(self) + env._dict = copy.copy(self._dict) + env._dict.update(overrides) + return env else: return self @@ -536,6 +514,10 @@ class Environment: "Emulates the get() method of dictionaries.""" return self._dict.get(key, default) + def items(self): + "Emulates the items() method of dictionaries.""" + return self._dict.items() + class VarInterpolator: def __init__(self, dest, src, prefix, suffix): self.dest = dest diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py index 70e28ffe..40c4f932 100644 --- a/src/engine/SCons/EnvironmentTests.py +++ b/src/engine/SCons/EnvironmentTests.py @@ -95,12 +95,17 @@ class Scanner: class EnvironmentTestCase(unittest.TestCase): def test_Override(self): + "Test overriding construction variables" env = Environment(ONE=1, TWO=2) assert env['ONE'] == 1 assert env['TWO'] == 2 env2 = env.Override({'TWO':'10'}) assert env2['ONE'] == 1 assert env2['TWO'] == '10' + assert env['TWO'] == 2 + env2.Replace(ONE = "won") + assert env2['ONE'] == "won" + assert env['ONE'] == 1 def test_Builder_calls(self): """Test Builder calls through different environments diff --git a/src/engine/SCons/Tool/mslink.py b/src/engine/SCons/Tool/mslink.py index 35bd8686..3fdd4d8b 100644 --- a/src/engine/SCons/Tool/mslink.py +++ b/src/engine/SCons/Tool/mslink.py @@ -40,6 +40,7 @@ import SCons.Defaults import SCons.Errors import SCons.Action import SCons.Util +import msvc from SCons.Tool.msvc import get_msdev_paths @@ -68,6 +69,10 @@ def win32TempFileMunge(env, cmd_list, for_signature): def win32LinkGenerator(env, target, source, for_signature): args = [ '$LINK', '$LINKFLAGS', '/OUT:%s' % target[0], '$(', '$_LIBDIRFLAGS', '$)', '$_LIBFLAGS' ] + + if env.has_key('PDB') and env['PDB']: + args.extend(['/PDB:%s'%env['PDB'], '/DEBUG']) + args.extend(map(SCons.Util.to_String, source)) return win32TempFileMunge(env, args, for_signature) @@ -75,6 +80,9 @@ def win32LibGenerator(target, source, env, for_signature): listCmd = [ "$SHLINK", "$SHLINKFLAGS" ] no_import_lib = env.get('no_import_lib', 0) + if env.has_key('PDB') and env['PDB']: + listCmd.extend(['/PDB:%s'%env['PDB'], '/DEBUG']) + for tgt in target: ext = os.path.splitext(str(tgt))[1] if ext == env.subst("$LIBSUFFIX"): @@ -94,9 +102,12 @@ def win32LibGenerator(target, source, env, for_signature): else: # Just treat it as a generic source file. listCmd.append(str(src)) + return win32TempFileMunge(env, listCmd, for_signature) def win32LibEmitter(target, source, env): + msvc.validate_vars(env) + dll = None no_import_lib = env.get('no_import_lib', 0) @@ -116,6 +127,11 @@ def win32LibEmitter(target, source, env): # append a def file to the list of sources source.append("%s%s" % (os.path.splitext(str(dll))[0], env.subst("$WIN32DEFSUFFIX"))) + + if env.has_key('PDB') and env['PDB']: + env.SideEffect(env['PDB'], target) + env.Precious(env['PDB']) + if not no_import_lib and \ not env.subst("$LIBSUFFIX") in \ map(lambda x: os.path.split(str(x))[1], target): @@ -125,6 +141,15 @@ def win32LibEmitter(target, source, env): env.subst("$LIBSUFFIX"))) return (target, source) +def prog_emitter(target, source, env): + msvc.validate_vars(env) + + if env.has_key('PDB') and env['PDB']: + env.SideEffect(env['PDB'], target) + env.Precious(env['PDB']) + + return (target,source) + ShLibAction = SCons.Action.CommandGenerator(win32LibGenerator) LinkAction = SCons.Action.CommandGenerator(win32LinkGenerator) @@ -140,6 +165,7 @@ def generate(env, platform): env['LINK'] = 'link' env['LINKFLAGS'] = '/nologo' env['LINKCOM'] = LinkAction + env['PROGEMITTER'] = prog_emitter env['LIBDIRPREFIX']='/LIBPATH:' env['LIBDIRSUFFIX']='' env['LIBLINKPREFIX']='' diff --git a/src/engine/SCons/Tool/msvc.py b/src/engine/SCons/Tool/msvc.py index 37d3e1dc..1ba9ede5 100644 --- a/src/engine/SCons/Tool/msvc.py +++ b/src/engine/SCons/Tool/msvc.py @@ -39,6 +39,8 @@ import string import SCons.Action import SCons.Tool import SCons.Errors +import SCons.Builder +import SCons.Util CSuffixes = ['.c', '.C'] CXXSuffixes = ['.cc', '.cpp', '.cxx', '.c++', '.C++'] @@ -187,6 +189,62 @@ def get_msdev_paths(version=None): exe_path = '' return (include_path, lib_path, exe_path) +def validate_vars(env): + """Validate the PDB, PCH, and PCHSTOP construction variables.""" + if env.has_key('PDB') and env['PDB']: + if not isinstance(env['PDB'], SCons.Node.FS.File): + raise SCons.Errors.UserError, "The PDB construction variable must be a File instance: %s"%env['PDB'] + + if env.has_key('PCH') and env['PCH']: + if not isinstance(env['PCH'], SCons.Node.FS.File): + raise SCons.Errors.UserError, "The PCH construction variable must be a File instance: %s"%env['PCH'] + if not env.has_key('PCHSTOP'): + raise SCons.Errors.UserError, "The PCHSTOP construction must be defined if PCH is defined." + if not SCons.Util.is_String(env['PCHSTOP']): + raise SCons.Errors.UserError, "The PCHSTOP construction variable must be a string: %r"%env['PCHSTOP'] + +def pch_emitter(target, source, env): + """Sets up the PDB dependencies for a pch file, and adds the object + file target.""" + + validate_vars(env) + + pch = None + obj = None + + for t in target: + if os.path.splitext(str(t))[1] == '.pch': + pch = t + if os.path.splitext(str(t))[1] == '.obj': + obj = t + + if not obj: + obj = os.path.splitext(str(pch))[0]+'.obj' + + target = [pch, obj] # pch must be first, and obj second for the PCHCOM to work + + if env.has_key('PDB') and env['PDB']: + env.SideEffect(env['PDB'], target) + env.Precious(env['PDB']) + + return (target, source) + +def object_emitter(target, source, env): + """Sets up the PDB and PCH dependencies for an object file.""" + + validate_vars(env) + + if env.has_key('PDB') and env['PDB']: + env.SideEffect(env['PDB'], target) + env.Precious(env['PDB']) + + if env.has_key('PCH') and env['PCH']: + env.Depends(target, env['PCH']) + + return (target, source) + +pch_builder = SCons.Builder.Builder(action='$PCHCOM', suffix='.pch', emitter=pch_emitter) + def generate(env, platform): """Add Builders and construction variables for MSVC++ to an Environment.""" static_obj, shared_obj = SCons.Tool.createObjBuilders(env) @@ -199,20 +257,24 @@ def generate(env, platform): static_obj.add_action(suffix, SCons.Defaults.CXXAction) shared_obj.add_action(suffix, SCons.Defaults.ShCXXAction) + env['CCPDBFLAGS'] = '${(PDB and "/Zi /Fd%s"%PDB) or ""}' + env['CCPCHFLAGS'] = '${(PCH and "/Yu%s /Fp%s"%(PCHSTOP or "",PCH)) or ""}' + env['CCCOMFLAGS'] = '$CPPFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET $CCPCHFLAGS $CCPDBFLAGS' env['CC'] = 'cl' env['CCFLAGS'] = '/nologo' - env['CCCOM'] = '$CC $CCFLAGS $CPPFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET' + env['CCCOM'] = '$CC $CCFLAGS $CCCOMFLAGS' env['SHCC'] = '$CC' env['SHCCFLAGS'] = '$CCFLAGS' - env['SHCCCOM'] = '$SHCC $SHCCFLAGS $CPPFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET' + env['SHCCCOM'] = '$SHCC $SHCCFLAGS $CCCOMFLAGS' env['CXX'] = '$CC' env['CXXFLAGS'] = '$CCFLAGS' - env['CXXCOM'] = '$CXX $CXXFLAGS $CPPFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET' + env['CXXCOM'] = '$CXX $CXXFLAGS $CCCOMFLAGS' env['SHCXX'] = '$CXX' env['SHCXXFLAGS'] = '$CXXFLAGS' - env['SHCXXCOM'] = '$SHCXX $SHCXXFLAGS $CPPFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET' + env['SHCXXCOM'] = '$SHCXX $SHCXXFLAGS $CCCOMFLAGS' env['INCPREFIX'] = '/I' - env['INCSUFFIX'] = '' + env['INCSUFFIX'] = '' + env['OBJEMITTER'] = object_emitter include_path, lib_path, exe_path = get_msdev_paths() env['ENV']['INCLUDE'] = include_path @@ -221,5 +283,8 @@ def generate(env, platform): env['CFILESUFFIX'] = '.c' env['CXXFILESUFFIX'] = '.cc' + env['PCHCOM'] = '$CXX $CXXFLAGS $CPPFLAGS $_CPPINCFLAGS /c $SOURCES /Fo${TARGETS[1]} /Yc$PCHSTOP /Fp${TARGETS[0]} $CCPDBFLAGS' + env['BUILDERS']['PCH'] = pch_builder + def exists(env): return env.Detect('cl') diff --git a/test/msvc.py b/test/msvc.py new file mode 100644 index 00000000..0e3c3c2a --- /dev/null +++ b/test/msvc.py @@ -0,0 +1,223 @@ +#!/usr/bin/env python +# +# Copyright (c) 2001, 2002 Steven Knight +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +import TestSCons +import sys +import os.path +import os +import TestCmd +import time + +test = TestSCons.TestSCons(match = TestCmd.match_re) + +if sys.platform != 'win32': + test.pass_test() + +##### +# Test the basics + +test.write('SConstruct',""" +env=Environment() +env['PCH'] = env.PCH('StdAfx.cpp')[0] +env['PDB'] = File('test.pdb') +env['PCHSTOP'] = 'StdAfx.h' +env.Program('test', 'test.cpp') + +env.Object('fast', 'foo.cpp') +env.Object('slow', 'foo.cpp', PCH=0) +""") + +test.write('test.cpp', ''' +#include "StdAfx.h" + +int main(void) +{ + return 1; +} +''') + +test.write('foo.cpp', ''' +#include "StdAfx.h" +''') + +test.write('StdAfx.h', ''' +#include +''') + +test.write('StdAfx.cpp', ''' +#include "StdAfx.h" +''') + +test.run(arguments='test.exe') + +test.fail_test(not os.path.exists(test.workpath('test.pdb'))) +test.fail_test(not os.path.exists(test.workpath('StdAfx.pch'))) +test.fail_test(not os.path.exists(test.workpath('StdAfx.obj'))) + +test.run(arguments='-c .') + +test.fail_test(os.path.exists(test.workpath('test.pdb'))) +test.fail_test(os.path.exists(test.workpath('StdAfx.pch'))) +test.fail_test(os.path.exists(test.workpath('StdAfx.obj'))) + +test.run(arguments='test.exe') + +test.fail_test(not os.path.exists(test.workpath('test.pdb'))) +test.fail_test(not os.path.exists(test.workpath('StdAfx.pch'))) +test.fail_test(not os.path.exists(test.workpath('StdAfx.obj'))) + +test.run(arguments='-c test.pdb') +test.fail_test(os.path.exists(test.workpath('test.exe'))) +test.fail_test(os.path.exists(test.workpath('test.obj'))) +test.fail_test(os.path.exists(test.workpath('test.pdb'))) +test.fail_test(os.path.exists(test.workpath('StdAfx.pch'))) +test.fail_test(os.path.exists(test.workpath('StdAfx.obj'))) + +test.run(arguments='StdAfx.pch') + +test.fail_test(not os.path.exists(test.workpath('test.pdb'))) +test.fail_test(not os.path.exists(test.workpath('StdAfx.pch'))) +test.fail_test(not os.path.exists(test.workpath('StdAfx.obj'))) + +start = time.time() +test.run(arguments='fast.obj') +fast = time.time() - start + +start = time.time() +test.run(arguments='slow.obj') +slow = time.time() - start + +# using precompiled headers should be significantly faster +assert fast < slow*0.75 + + +########## +# Test a hierarchical build + +test.subdir('src', 'build', 'out') + +test.write('SConstruct',""" +BuildDir('build', 'src', duplicate=0) +SConscript('build/SConscript') +""") + +test.write('src/SConscript',""" +env=Environment() +env['PCH'] = env.PCH('StdAfx.cpp')[0] +env['PDB'] = File('#out/test.pdb') +env['PCHSTOP'] = 'StdAfx.h' +env.Program('#out/test.exe', 'test.cpp') +""") + +test.write('src/test.cpp', ''' +#include "StdAfx.h" + +int main(void) +{ + return 1; +} +''') + +test.write('src/StdAfx.h', ''' +#include +''') + +test.write('src/StdAfx.cpp', ''' +#include "StdAfx.h" +''') + +test.run(arguments='out') + +test.fail_test(not os.path.exists(test.workpath('out/test.pdb'))) +test.fail_test(not os.path.exists(test.workpath('build/StdAfx.pch'))) +test.fail_test(not os.path.exists(test.workpath('build/StdAfx.obj'))) + +test.run(arguments='-c out') + +test.fail_test(os.path.exists(test.workpath('out/test.pdb'))) +test.fail_test(os.path.exists(test.workpath('build/StdAfx.pch'))) +test.fail_test(os.path.exists(test.workpath('build/StdAfx.obj'))) + +##### +# Test error reporting + +test.write('SConstruct',""" +env=Environment() +env['PCH'] = env.PCH('StdAfx.cpp') +env['PDB'] = File('test.pdb') +env['PCHSTOP'] = 'StdAfx.h' +env.Program('test', 'test.cpp') +""") + +test.run(status=2, stderr=r''' +SCons error: The PCH construction variable must be a File instance: .+ +File "SConstruct", line 6, in \? +''') + +test.write('SConstruct',""" +env=Environment() +env['PCH'] = env.PCH('StdAfx.cpp')[0] +env['PDB'] = 'test.pdb' +env['PCHSTOP'] = 'StdAfx.h' +env.Program('test', 'test.cpp') +""") + +test.run(status=2, stderr=''' +SCons error: The PDB construction variable must be a File instance: test.pdb +File "SConstruct", line 6, in \? +''') + +test.write('SConstruct',""" +env=Environment() +env['PCH'] = env.PCH('StdAfx.cpp')[0] +env['PDB'] = File('test.pdb') +env.Program('test', 'test.cpp') +""") + +test.run(status=2, stderr=''' +SCons error: The PCHSTOP construction must be defined if PCH is defined. +File "SConstruct", line 5, in \? +''') + +test.write('SConstruct',""" +env=Environment() +env['PCH'] = env.PCH('StdAfx.cpp')[0] +env['PDB'] = File('test.pdb') +env['PCHSTOP'] = File('StdAfx.h') +env.Program('test', 'test.cpp') +""") + +test.run(status=2, stderr=''' +SCons error: The PCHSTOP construction variable must be a string: .+ +File "SConstruct", line 6, in \? +''') + +test.pass_test() + + + + + diff --git a/test/option--debug.py b/test/option--debug.py index 6561a057..d70cfc99 100644 --- a/test/option--debug.py +++ b/test/option--debug.py @@ -121,7 +121,7 @@ tree = """scons: \".\" is up to date. +-foo.h """ test.run(arguments = "--debug=tree .") -test.fail_test(string.find(test.stdout(), tree) != 0) +test.fail_test(string.find(test.stdout(), tree) == -1) test.run(arguments = "--debug=pdb", stdin = "n\ns\nq\n") test.fail_test(string.find(test.stdout(), "(Pdb)") == -1) diff --git a/test/win32pathmadness.py b/test/win32pathmadness.py index cb6cb57a..2e5b6e59 100644 --- a/test/win32pathmadness.py +++ b/test/win32pathmadness.py @@ -91,11 +91,11 @@ upper = os.path.join(string.upper(drive),rest) lower = os.path.join(string.lower(drive),rest) test.run(chdir=upper) -test.run(chdir=lower, stdout="""\ +test.run(chdir=lower, stdout=test.wrap_stdout("""\ scons: .* is up to date. scons: .* is up to date. scons: .* is up to date. -""") +""")) test.write('SConstruct', """ env=Environment() @@ -122,10 +122,10 @@ test.write('b.h', """ """) test.run(arguments='a.lib b.lib') -test.run(arguments='b.lib a.lib', stdout="""\ +test.run(arguments='b.lib a.lib', stdout=test.wrap_stdout("""\ scons: .* is up to date. scons: .* is up to date. -""") +"""))