diff options
author | Steven Knight <knight@baldmt.com> | 2002-10-03 21:01:02 (GMT) |
---|---|---|
committer | Steven Knight <knight@baldmt.com> | 2002-10-03 21:01:02 (GMT) |
commit | 313be3374d81ff22c10b8ec09c465cabd835062f (patch) | |
tree | 9385dedc5fcd031f98ebd15791c5c15c62303144 /src/engine | |
parent | dffe09bd431aeeb996ad14763154abe5c412b93e (diff) | |
download | SCons-313be3374d81ff22c10b8ec09c465cabd835062f.zip SCons-313be3374d81ff22c10b8ec09c465cabd835062f.tar.gz SCons-313be3374d81ff22c10b8ec09c465cabd835062f.tar.bz2 |
Add MSVC PCH and PDB support. (Anthony Roach)
Diffstat (limited to 'src/engine')
-rw-r--r-- | src/engine/SCons/ActionTests.py | 3 | ||||
-rw-r--r-- | src/engine/SCons/Defaults.py | 3 | ||||
-rw-r--r-- | src/engine/SCons/Environment.py | 76 | ||||
-rw-r--r-- | src/engine/SCons/EnvironmentTests.py | 5 | ||||
-rw-r--r-- | src/engine/SCons/Tool/mslink.py | 26 | ||||
-rw-r--r-- | src/engine/SCons/Tool/msvc.py | 75 |
6 files changed, 135 insertions, 53 deletions
diff --git a/src/engine/SCons/ActionTests.py b/src/engine/SCons/ActionTests.py index 6ce52d5..289e7fe 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 d70be0d..4e8cf4e 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 24315a1..1a1dd49 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 70e28ff..40c4f93 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 35bd868..3fdd4d8 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 37d3e1d..1ba9ede 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') |