summaryrefslogtreecommitdiffstats
path: root/src/engine
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2002-10-03 21:01:02 (GMT)
committerSteven Knight <knight@baldmt.com>2002-10-03 21:01:02 (GMT)
commit313be3374d81ff22c10b8ec09c465cabd835062f (patch)
tree9385dedc5fcd031f98ebd15791c5c15c62303144 /src/engine
parentdffe09bd431aeeb996ad14763154abe5c412b93e (diff)
downloadSCons-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.py3
-rw-r--r--src/engine/SCons/Defaults.py3
-rw-r--r--src/engine/SCons/Environment.py76
-rw-r--r--src/engine/SCons/EnvironmentTests.py5
-rw-r--r--src/engine/SCons/Tool/mslink.py26
-rw-r--r--src/engine/SCons/Tool/msvc.py75
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')