os.name is "posix" or "nt" or we don't care.
Added big comment about the kludginess of passing 'build_options'
  to the link methods and how to fix it.
Added 'gen_preprocess_options()' and 'gen_lib_options()' convenience
  functions -- the two cases are very similar for Unix C Compilers and
  VC++, so I figured I might as well unify the implementations.
diff --git a/Lib/distutils/ccompiler.py b/Lib/distutils/ccompiler.py
index 5f27ebc..b1167ac 100644
--- a/Lib/distutils/ccompiler.py
+++ b/Lib/distutils/ccompiler.py
@@ -290,6 +290,30 @@
         pass
     
 
+    # XXX passing in 'build_info' here is a kludge to deal with the
+    # oddities of one particular compiler (Visual C++).  For some reason,
+    # it needs to be told about ".def" files, and currently the
+    # 'build_info' hash allows this through a 'def_file' element.  The link
+    # methods for VC++ look for 'def_file' and transform it into the
+    # appropriate command-line options.  The current code is objectionable
+    # for a number of reasons: 1) if the link methods take 'build_info',
+    # why bother passing in libraries, library_dirs, etc.? 2) if the link
+    # methods do it, why not the compile methods? 3) build_info is part of
+    # the interface between setup.py and the 'build_ext' command -- it
+    # should stop there and not be propagated down into the compiler
+    # classes! and 4) I don't like elevating a platform- and
+    # compiler-specific oddity to "first-class" status in 'build_info' (oh
+    # well, at least it's not being reified in the compiler classes -- that
+    # would be really gross).
+    #
+    # Possible solutions:
+    #   - just pass build_info to all the compile/link methods, 
+    #     never mind all those other parameters and screw the
+    #     integrity of the interfaces
+    #   - add a mechanism for passing platform-specific and/or
+    #     compiler-specific compiler/linker options from setup.py
+    #     straight through to the appropriate compiler class
+
     def link_shared_lib (self,
                          objects,
                          output_libname,
@@ -367,9 +391,81 @@
     if plat == 'posix':
         from unixccompiler import UnixCCompiler
         return UnixCCompiler (verbose, dry_run)
-    elif plat in  ['nt', 'win95' ]:
+    elif plat == 'nt':
         from msvccompiler import MSVCCompiler
         return MSVCCompiler ( verbose, dry_run )
     else:
         raise DistutilsPlatformError, \
               "don't know how to compile C/C++ code on platform %s" % plat
+
+
+def gen_preprocess_options (macros, includes):
+    """Generate C pre-processor options (-D, -U, -I) as used by at
+       least two types of compilers: the typical Unix compiler and Visual
+       C++.  'macros' is the usual thing, a list of 1- or 2-tuples, where
+       (name,) means undefine (-U) macro 'name', and (name,value) means
+       define (-D) macro 'name' to 'value'.  'includes' is just a list of
+       directory names to be added to the header file search path (-I).
+       Returns a list of command-line options suitable for either
+       Unix compilers or Visual C++."""
+    
+    # XXX it would be nice (mainly aesthetic, and so we don't generate
+    # stupid-looking command lines) to go over 'macros' and eliminate
+    # redundant definitions/undefinitions (ie. ensure that only the
+    # latest mention of a particular macro winds up on the command
+    # line).  I don't think it's essential, though, since most (all?)
+    # Unix C compilers only pay attention to the latest -D or -U
+    # mention of a macro on their command line.  Similar situation for
+    # 'includes'.  I'm punting on both for now.  Anyways, weeding out
+    # redundancies like this should probably be the province of
+    # CCompiler, since the data structures used are inherited from it
+    # and therefore common to all CCompiler classes.
+
+    pp_opts = []
+    for macro in macros:
+        if len (macro) == 1:        # undefine this macro
+            pp_opts.append ("-U%s" % macro[0])
+        elif len (macro) == 2:
+            if macro[1] is None:    # define with no explicit value
+                pp_opts.append ("-D%s" % macro[0])
+            else:
+                # XXX *don't* need to be clever about quoting the
+                # macro value here, because we're going to avoid the
+                # shell at all costs when we spawn the command!
+                pp_opts.append ("-D%s=%s" % macro)
+
+    for dir in includes:
+        pp_opts.append ("-I%s" % dir)
+
+    return pp_opts
+
+# gen_preprocess_options ()
+
+
+def gen_lib_options (libraries, library_dirs, lib_format, dir_format):
+    """Generate linker options for searching library directories and
+       linking with specific libraries.  'libraries' and 'library_dirs'
+       are, respectively, lists of library names (not filenames!) and
+       search directories.  'lib_format' is a format string with exactly
+       one "%s", into which will be plugged each library name in turn;
+       'dir_format' is similar, but directory names will be plugged into
+       it.  Returns a list of command-line options suitable for use with
+       some compiler (depending on the two format strings passed in)."""
+
+    lib_opts = []
+
+    for dir in library_dirs:
+        lib_opts.append (dir_format % dir)
+
+    # XXX it's important that we *not* remove redundant library mentions!
+    # sometimes you really do have to say "-lfoo -lbar -lfoo" in order to
+    # resolve all symbols.  I just hope we never have to say "-lfoo obj.o
+    # -lbar" to get things to work -- that's certainly a possibility, but a
+    # pretty nasty way to arrange your C code.
+
+    for lib in libraries:
+        lib_opts.append (lib_format % lib)
+
+    return lib_opts
+
+# _gen_lib_options ()