Serious overhaul of the C compiler interface and the two classes that
implement it (so far):
  * moved filename generation methods into CCompiler base class,
    driven by data supplied by implementation classes
  * moved a bunch of common code from UnixCCompiler to convenience
    methods in CCompiler
  * overhauled MSVCCompiler's compile/link methods to look and act
    as much as possible like UnixCCompiler's, in order to regularize
    both interface and behaviour (especially by using those new
    convenience methods)
diff --git a/Lib/distutils/msvccompiler.py b/Lib/distutils/msvccompiler.py
index 2dd8dc1..847c611 100644
--- a/Lib/distutils/msvccompiler.py
+++ b/Lib/distutils/msvccompiler.py
@@ -5,12 +5,13 @@
 
 
 # created 1999/08/19, Perry Stoll
-# 
+# hacked by Robin Becker and Thomas Heller to do a better job of
+#   finding DevStudio (through the registry)
+
 __revision__ = "$Id$"
 
-import os
-import sys
-import string
+import sys, os, string
+from types import *
 from distutils.errors import *
 from distutils.ccompiler import \
      CCompiler, gen_preprocess_options, gen_lib_options
@@ -137,6 +138,20 @@
 
     compiler_type = 'msvc'
 
+    # Private class data (need to distinguish C from C++ source for compiler)
+    _c_extensions = ['.c']
+    _cpp_extensions = ['.cc','.cpp']
+
+    # Needed for the filename generation methods provided by the
+    # base class, CCompiler.
+    src_extensions = _c_extensions + _cpp_extensions
+    obj_extension = '.obj'
+    static_lib_extension = '.lib'
+    shared_lib_extension = '.dll'
+    static_lib_format = shared_lib_format = '%s%s'
+    exe_extension = '.exe'
+
+
     def __init__ (self,
                   verbose=0,
                   dry_run=0,
@@ -169,9 +184,7 @@
 
         self.preprocess_options = None
         self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3' ]
-        self.compile_options_debug = [
-            '/nologo', '/Od', '/MDd', '/W3', '/Z7', '/D_DEBUG'
-            ]
+        self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/Z7', '/D_DEBUG']
 
         self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']
         self.ldflags_shared_debug = [
@@ -181,21 +194,7 @@
 
 
     # -- Worker methods ------------------------------------------------
-    # (must be implemented by subclasses)
 
-    _c_extensions = [ '.c' ]
-    _cpp_extensions = [ '.cc', '.cpp' ]
-
-    _obj_ext = '.obj'
-    _exe_ext = '.exe'
-    _shared_lib_ext = '.dll'
-    _static_lib_ext = '.lib'
-
-    # XXX the 'output_dir' parameter is ignored by the methods in this
-    # class!  I just put it in to be consistent with CCompiler and
-    # UnixCCompiler, but someone who actually knows Visual C++ will
-    # have to make it work...
-    
     def compile (self,
                  sources,
                  output_dir=None,
@@ -205,48 +204,43 @@
                  extra_preargs=None,
                  extra_postargs=None):
 
-        if macros is None:
-            macros = []
-        if include_dirs is None:
-            include_dirs = []
+        (output_dir, macros, include_dirs) = \
+            self._fix_compile_args (output_dir, macros, include_dirs)
+        (objects, skip_sources) = self._prep_compile (sources, output_dir)
 
-        objectFiles = []
+        if extra_postargs is None:
+            extra_postargs = []
 
-        base_pp_opts = \
-            gen_preprocess_options (self.macros + macros,
-                                    self.include_dirs + include_dirs)
-
-        base_pp_opts.append('/c')
-
+        pp_opts = gen_preprocess_options (macros, include_dirs)
+        compile_opts = extra_preargs or []
+        compile_opts.append ('/c')
         if debug:
-            compile_options = self.compile_options_debug
+            compile_opts.extend (self.compile_options_debug)
         else:
-            compile_options = self.compile_options
+            compile_opts.extend (self.compile_options)
         
-        for srcFile in sources:
-            base,ext = os.path.splitext(srcFile)
-            objFile = base + ".obj"
+        for i in range (len (sources)):
+            src = sources[i] ; obj = objects[i]
+            ext = (os.path.splitext (src))[1]
 
-            if ext in self._c_extensions:
-                fileOpt = "/Tc"
-            elif ext in self._cpp_extensions:
-                fileOpt = "/Tp"
+            if skip_sources[src]:
+                self.announce ("skipping %s (%s up-to-date)" % (src, obj))
+            else:
+                if ext in self._c_extensions:
+                    input_opt = "/Tc" + src
+                elif ext in self._cpp_extensions:
+                    input_opt = "/Tp" + src
 
-            inputOpt  = fileOpt + srcFile
-            outputOpt = "/Fo"   + objFile
+                output_opt = "/Fo" + obj
 
-            cc_args = compile_options + \
-                      base_pp_opts + \
-                      [outputOpt, inputOpt]
+                self.mkpath (os.path.dirname (obj))
+                self.spawn ([self.cc] + compile_opts + pp_opts +
+                            [input_opt, output_opt] +
+                            extra_postargs)
 
-            if extra_preargs:
-                cc_args[:0] = extra_preargs
-            if extra_postargs:
-                cc_args.extend (extra_postargs)
+        return objects
 
-            self.spawn ([self.cc] + cc_args)
-            objectFiles.append( objFile )
-        return objectFiles
+    # compile ()
 
 
     # XXX the signature of this method is different from CCompiler and
@@ -263,25 +257,30 @@
                          extra_preargs=None,
                          extra_postargs=None):
 
-        if libraries is None:
-            libraries = []
-        if library_dirs is None:
-            library_dirs = []
+        (objects, output_dir, libraries, library_dirs) = \
+            self._fix_link_args (objects, output_dir, takes_libs=1,
+                                 libraries=libraries,
+                                 library_dirs=library_dirs)
         
-        lib_opts = gen_lib_options (self.libraries + libraries,
-                                    self.library_dirs + library_dirs,
-                                    "%s.lib", "/LIBPATH:%s")
+        output_filename = \
+            self.library_filename (output_libname, output_dir=output_dir)
 
-        ld_args = self.ldflags_static + lib_opts + \
-                  objects + ['/OUT:' + output_filename]
-        if debug:
-            pass                        # XXX what goes here?
-        if extra_preargs:
-            ld_args[:0] = extra_preargs
-        if extra_postargs:
-            ld_args.extend (extra_postargs)
+        if self._need_link (objects, output_filename):
+            lib_opts = gen_lib_options (libraries, library_dirs,
+                                        "%s.lib", "/LIBPATH:%s")
+            ld_args = self.ldflags_static + lib_opts + \
+                      objects + ['/OUT:' + output_filename]
+            if debug:
+                pass                    # XXX what goes here?
+            if extra_preargs:
+                ld_args[:0] = extra_preargs
+            if extra_postargs:
+                ld_args.extend (extra_postargs)
+            self.spawn ([self.link] + ld_args)
+        else:
+            self.announce ("skipping %s (up-to-date)" % output_filename)
 
-        self.spawn ( [ self.link ] + ld_args )
+    # link_static_lib ()
     
 
     def link_shared_lib (self,
@@ -294,8 +293,6 @@
                          extra_preargs=None,
                          extra_postargs=None):
 
-        # XXX should we sanity check the library name? (eg. no
-        # slashes)
         self.link_shared_object (objects,
                                  self.shared_library_name(output_libname),
                                  output_dir=output_dir,
@@ -315,70 +312,48 @@
                             debug=0,
                             extra_preargs=None,
                             extra_postargs=None):
-        """Link a bunch of stuff together to create a shared object
-           file.  Much like 'link_shared_lib()', except the output
-           filename is explicitly supplied as 'output_filename'."""
-        if libraries is None:
-            libraries = []
-        if library_dirs is None:
-            library_dirs = []
+
+        (objects, output_dir, libraries, library_dirs) = \
+            self._fix_link_args (objects, output_dir, takes_libs=1,
+                                 libraries=libraries, library_dirs=library_dirs)
         
-        lib_opts = gen_lib_options (self,
-                                    self.library_dirs + library_dirs,
-                                    self.libraries + libraries)
+        lib_opts = gen_lib_options (self, library_dirs, libraries)
+        if type (output_dir) not in (StringType, NoneType):
+            raise TypeError, "'output_dir' must be a string or None"
+        if output_dir is not None:
+            output_filename = os.path.join (output_dir, output_filename)
 
-        if debug:
-            ldflags = self.ldflags_shared_debug
-            basename, ext = os.path.splitext (output_filename)
-            #XXX not sure this belongs here
-            # extensions in debug_mode are named 'module_d.pyd'
-            output_filename = basename + '_d' + ext
+        if self._need_link (objects, output_filename):
+
+            if debug:
+                ldflags = self.ldflags_shared_debug
+                # XXX not sure this belongs here
+                # extensions in debug_mode are named 'module_d.pyd'
+                basename, ext = os.path.splitext (output_filename)
+                output_filename = basename + '_d' + ext
+            else:
+                ldflags = self.ldflags_shared
+
+            ld_args = ldflags + lib_opts + \
+                      objects + ['/OUT:' + output_filename]
+
+            if extra_preargs:
+                ld_args[:0] = extra_preargs
+            if extra_postargs:
+                ld_args.extend (extra_postargs)
+
+            self.mkpath (os.path.dirname (output_filename))
+            self.spawn ([self.link] + ld_args)
+
         else:
-            ldflags = self.ldflags_shared
+            self.announce ("skipping %s (up-to-date)" % output_filename)
 
-        ld_args = ldflags + lib_opts + \
-                  objects + ['/OUT:' + output_filename]
+    # link_shared_object ()
+    
 
-        if extra_preargs:
-            ld_args[:0] = extra_preargs
-        if extra_postargs:
-            ld_args.extend (extra_postargs)
-
-        self.spawn ( [ self.link ] + ld_args )
-
-
-    # -- Filename mangling methods -------------------------------------
-
-    def _change_extensions( self, filenames, newExtension ):
-        object_filenames = []
-
-        for srcFile in filenames:
-            base,ext = os.path.splitext( srcFile )
-            # XXX should we strip off any existing path?
-            object_filenames.append( base + newExtension )
-
-        return object_filenames
-
-    def object_filenames (self, source_filenames):
-        """Return the list of object filenames corresponding to each
-           specified source filename."""
-        return self._change_extensions( source_filenames, self._obj_ext )
-
-    def shared_object_filename (self, source_filename):
-        """Return the shared object filename corresponding to a
-           specified source filename."""
-        return self._change_extensions( source_filenames, self._shared_lib_ext )
-
-    def library_filename (self, libname):
-        """Return the static library filename corresponding to the
-           specified library name."""
-        return "%s%s" %( libname, self._static_lib_ext )
-
-    def shared_library_filename (self, libname):
-        """Return the shared library filename corresponding to the
-           specified library name."""
-        return "%s%s" %( libname, self._shared_lib_ext )
-
+    # -- Miscellaneous methods -----------------------------------------
+    # These are all used by the 'gen_lib_options() function, in
+    # ccompiler.py.
 
     def library_dir_option (self, dir):
         return "/LIBPATH:" + dir