]> git.saurik.com Git - wxWidgets.git/commitdiff
Latest distutils
authorRobin Dunn <robin@alldunn.com>
Wed, 27 Aug 2003 00:20:37 +0000 (00:20 +0000)
committerRobin Dunn <robin@alldunn.com>
Wed, 27 Aug 2003 00:20:37 +0000 (00:20 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@23252 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

13 files changed:
wxPython/distutils/README_1st.txt
wxPython/distutils/ccompiler.py
wxPython/distutils/cmd.py
wxPython/distutils/command/__init__.py
wxPython/distutils/command/bdist_wininst.py
wxPython/distutils/command/build_py.py
wxPython/distutils/command/build_scripts.py
wxPython/distutils/command/register.py
wxPython/distutils/cygwinccompiler.py
wxPython/distutils/dist.py
wxPython/distutils/log.py
wxPython/distutils/msvccompiler.py
wxPython/distutils/unixccompiler.py

index 5a06b95c5622d0b498018824c7d34f4b4e0be616..7edc1b7be30356b0d35ae938854731ae90526214 100644 (file)
@@ -1,18 +1,9 @@
 This is a copy of the Distutils package from Python (currently version
-2.3a2.)  This newer copy of distutils is used for all versions of
+2.3.)  This newer copy of distutils is used for all versions of
 Python to avoid some problems in the older versions that show up in
 wxPython builds and to avoid having to make some ugly hacks in local
 modules to work around them.
 
-There is one little 1-line customization (hack) in msvccompiler.py
-that allows the CFLAGS to be given on the RC.EXE command line.  This
-is required so the wx.rc files can be found when it is #included. I've
-submitted this patch to the Python project so if it gets into the main
-Distutils distribution I can remove this code.  (However, the newer
-version of distutils should still always be used, at least on Windows,
-so it will need to wait until there it a Distutils distribution that
-can be installed on the older Pythons.)
-
 I have not yet applied any patches specifically for MSCV 7 yet.  So
 far it appears that if you have the PATH setup properly (like I
 usually do) that distutils works as is.
index bfcf1279f17978901e02e4b15e36daf3fb8e5649..751ec0694bcdb62bc9d9d990b56a46ccb51ac447 100644 (file)
@@ -883,6 +883,51 @@ class CCompiler:
         """
         raise NotImplementedError
 
+    def has_function(self, funcname,
+                     includes=None,
+                     include_dirs=None,
+                     libraries=None,
+                     library_dirs=None):
+        """Return a boolean indicating whether funcname is supported on
+        the current platform.  The optional arguments can be used to
+        augment the compilation environment.
+        """
+
+        # this can't be included at module scope because it tries to
+        # import math which might not be available at that point - maybe
+        # the necessary logic should just be inlined?
+        import tempfile
+        if includes is None:
+            includes = []
+        if include_dirs is None:
+            include_dirs = []
+        if libraries is None:
+            libraries = []
+        if library_dirs is None:
+            library_dirs = []
+        fd, fname = tempfile.mkstemp(".c", funcname, text=True)
+        f = os.fdopen(fd, "w")
+        for incl in includes:
+            f.write("""#include "%s"\n""" % incl)
+        f.write("""\
+main (int argc, char **argv) {
+    %s();
+}
+""" % funcname)
+        f.close()
+        try:
+            objects = self.compile([fname], include_dirs=include_dirs)
+        except CompileError:
+            return False
+
+        try:
+            self.link_executable(objects, "a.out",
+                                 libraries=libraries,
+                                 library_dirs=library_dirs)
+        except (LinkError, TypeError):
+            return False
+        return True
+
     def find_library_file (self, dirs, lib, debug=0):
         """Search the specified list of directories for a static or shared
         library file 'lib' and return the full path to that file.  If
@@ -932,6 +977,8 @@ class CCompiler:
         obj_names = []
         for src_name in source_filenames:
             base, ext = os.path.splitext(src_name)
+            base = os.path.splitdrive(base)[1] # Chop off the drive
+            base = base[os.path.isabs(base):]  # If abs, chop off leading /
             if ext not in self.src_extensions:
                 raise UnknownFileError, \
                       "unknown file type '%s' (from '%s')" % (ext, src_name)
index 1165f95124f8a4b5b93336011915cf4c1ce4f293..7e7a4cd5ff661f7b9e28dd7fbb9e32c068351e4d 100644 (file)
@@ -191,7 +191,7 @@ class Command:
         """If the current verbosity level is of greater than or equal to
         'level' print 'msg' to stdout.
         """
-        log.debug(msg)
+        log.log(level, msg)
 
     def debug_print (self, msg):
         """Print 'msg' to stdout if the global DEBUG (taken from the
index fc6117166b8ad067f3d46ef0652e9a466375d34d..870005dca72b339b842ecc55f66aaa218c752c5e 100644 (file)
@@ -19,6 +19,7 @@ __all__ = ['build',
            'install_scripts',
            'install_data',
            'sdist',
+           'register',
            'bdist',
            'bdist_dumb',
            'bdist_rpm',
index 5acca11a62b7c5105892f60276937b995316acbf..3c4c893920038aff21a6db01583738a4336b9efd 100644 (file)
@@ -100,7 +100,7 @@ class bdist_wininst (Command):
         if not self.skip_build:
             self.run_command('build')
 
-        install = self.reinitialize_command('install')
+        install = self.reinitialize_command('install', reinit_subcommands=1)
         install.root = self.bdist_dir
         install.skip_build = self.skip_build
         install.warn_dir = 0
index 258d6d4ca04a9cf6accf2efa65024d7053040ff5..6c007c6987b542bdaa7857b2a3568c08d5e3afc2 100644 (file)
@@ -86,25 +86,11 @@ class build_py (Command):
         # Two options control which modules will be installed: 'packages'
         # and 'py_modules'.  The former lets us work with whole packages, not
         # specifying individual modules at all; the latter is for
-        # specifying modules one-at-a-time.  Currently they are mutually
-        # exclusive: you can define one or the other (or neither), but not
-        # both.  It remains to be seen how limiting this is.
-
-        # Dispose of the two "unusual" cases first: no pure Python modules
-        # at all (no problem, just return silently), and over-specified
-        # 'packages' and 'py_modules' options.
-
-        if not self.py_modules and not self.packages:
-            return
-        if self.py_modules and self.packages:
-            raise DistutilsOptionError, \
-                  "build_py: supplying both 'packages' and 'py_modules' " + \
-                  "options is not allowed"
-
-        # Now we're down to two cases: 'py_modules' only and 'packages' only.
+        # specifying modules one-at-a-time.
+
         if self.py_modules:
             self.build_modules()
-        else:
+        if self.packages:
             self.build_packages()
 
         self.byte_compile(self.get_outputs(include_bytecode=0))
@@ -276,10 +262,10 @@ class build_py (Command):
         (package, module, module_file), just like 'find_modules()' and
         'find_package_modules()' do."""
 
+        modules = []
         if self.py_modules:
-            modules = self.find_modules()
-        else:
-            modules = []
+            modules.extend(self.find_modules())
+        if self.packages:
             for package in self.packages:
                 package_dir = self.get_package_dir(package)
                 m = self.find_package_modules(package, package_dir)
index f61ad37d03c81c04fd6d5e69cdd0f59e4ee860d6..8de9cd3f6d9c8cb441295217f8aee9e0372075f9 100644 (file)
@@ -15,7 +15,7 @@ from distutils.util import convert_path
 from distutils import log
 
 # check if Python is called on the first line with this expression
-first_line_re = re.compile(r'^#!.*python[0-9.]*(\s+.*)?$')
+first_line_re = re.compile('^#!.*python[0-9.]*([ \t].*)?$')
 
 class build_scripts (Command):
 
@@ -96,7 +96,7 @@ class build_scripts (Command):
                                    (os.path.normpath(sys.executable),
                                     post_interp))
                     else:
-                        outf.write("#!%s%s" %
+                        outf.write("#!%s%s\n" %
                                    (os.path.join(
                             sysconfig.get_config_var("BINDIR"),
                             "python" + sysconfig.get_config_var("EXE")),
index 29b76cbfd97ebc710ea9805929a78e57f6180826..8e347ce6dc397c3c5a4ece84fbd14b2a7659b5ba 100644 (file)
@@ -15,15 +15,13 @@ from distutils.errors import *
 
 class register(Command):
 
-    description = "register the distribution with the repository"
+    description = ("register the distribution with the Python package index")
 
     DEFAULT_REPOSITORY = 'http://www.python.org/pypi'
 
     user_options = [
         ('repository=', 'r',
          "url of repository [default: %s]"%DEFAULT_REPOSITORY),
-        ('verify', None,
-         'verify the package metadata for correctness'),
         ('list-classifiers', None,
          'list the valid Trove classifiers'),
         ('show-response', None,
@@ -33,7 +31,6 @@ class register(Command):
 
     def initialize_options(self):
         self.repository = None
-        self.verify = 0
         self.show_response = 0
         self.list_classifiers = 0
 
@@ -43,7 +40,7 @@ class register(Command):
 
     def run(self):
         self.check_metadata()
-        if self.verify:
+        if self.dry_run:
             self.verify_metadata()
         elif self.list_classifiers:
             self.classifiers()
index 18af388c3c8e8d602b3ea804a0397001f987fe52..94b8b86b6d708294479953fed62743914cfb193f 100644 (file)
@@ -40,6 +40,10 @@ cygwin in no-cygwin mode).
 #     this is windows standard and there are normally not the necessary symbols
 #     in the dlls.
 #   *** only the version of June 2000 shows these problems
+# * cygwin gcc 3.2/ld 2.13.90 works
+#   (ld supports -shared)
+# * mingw gcc 3.2/ld 2.13 works
+#   (ld supports -shared)
 
 # This module should be kept compatible with Python 1.5.2.
 
@@ -83,7 +87,7 @@ class CygwinCCompiler (UnixCCompiler):
                           self.ld_version,
                           self.dllwrap_version) )
 
-        # ld_version >= "2.10.90" should also be able to use
+        # ld_version >= "2.10.90" and < "2.13" should also be able to use
         # gcc -mdll instead of dllwrap
         # Older dllwraps had own version numbers, newer ones use the
         # same as the rest of binutils ( also ld )
@@ -93,13 +97,20 @@ class CygwinCCompiler (UnixCCompiler):
         else:
             self.linker_dll = "dllwrap"
 
+        # ld_version >= "2.13" support -shared so use it instead of
+        # -mdll -static
+        if self.ld_version >= "2.13":
+            shared_option = "-shared"
+        else:
+            shared_option = "-mdll -static"
+
         # Hard-code GCC because that's what this is all about.
         # XXX optimization, warnings etc. should be customizable.
         self.set_executables(compiler='gcc -mcygwin -O -Wall',
                              compiler_so='gcc -mcygwin -mdll -O -Wall',
                              linker_exe='gcc -mcygwin',
-                             linker_so=('%s -mcygwin -mdll -static' %
-                                        self.linker_dll))
+                             linker_so=('%s -mcygwin %s' %
+                                        (self.linker_dll, shared_option)))
 
         # cygwin and mingw32 need different sets of libraries
         if self.gcc_version == "2.91.57":
@@ -268,6 +279,13 @@ class Mingw32CCompiler (CygwinCCompiler):
 
         CygwinCCompiler.__init__ (self, verbose, dry_run, force)
 
+        # ld_version >= "2.13" support -shared so use it instead of
+        # -mdll -static
+        if self.ld_version >= "2.13":
+            shared_option = "-shared"
+        else:
+            shared_option = "-mdll -static"
+
         # A real mingw32 doesn't need to specify a different entry point,
         # but cygwin 2.91.57 in no-cygwin-mode needs it.
         if self.gcc_version <= "2.91.57":
@@ -278,8 +296,9 @@ class Mingw32CCompiler (CygwinCCompiler):
         self.set_executables(compiler='gcc -mno-cygwin -O -Wall',
                              compiler_so='gcc -mno-cygwin -mdll -O -Wall',
                              linker_exe='gcc -mno-cygwin',
-                             linker_so='%s -mno-cygwin -mdll -static %s'
-                                        % (self.linker_dll, entry_point))
+                             linker_so='%s -mno-cygwin %s %s'
+                                        % (self.linker_dll, shared_option,
+                                           entry_point))
         # Maybe we should also append -mthreads, but then the finished
         # dlls need another dll (mingwm10.dll see Mingw32 docs)
         # (-mthreads: Support thread-safe exception handling on `Mingw32')
@@ -363,7 +382,7 @@ def get_versions():
         out = os.popen(gcc_exe + ' -dumpversion','r')
         out_string = out.read()
         out.close()
-        result = re.search('(\d+\.\d+\.\d+)',out_string)
+        result = re.search('(\d+\.\d+(\.\d+)*)',out_string)
         if result:
             gcc_version = StrictVersion(result.group(1))
         else:
@@ -375,7 +394,7 @@ def get_versions():
         out = os.popen(ld_exe + ' -v','r')
         out_string = out.read()
         out.close()
-        result = re.search('(\d+\.\d+\.\d+)',out_string)
+        result = re.search('(\d+\.\d+(\.\d+)*)',out_string)
         if result:
             ld_version = StrictVersion(result.group(1))
         else:
@@ -387,7 +406,7 @@ def get_versions():
         out = os.popen(dllwrap_exe + ' --version','r')
         out_string = out.read()
         out.close()
-        result = re.search(' (\d+\.\d+\.\d+)',out_string)
+        result = re.search(' (\d+\.\d+(\.\d+)*)',out_string)
         if result:
             dllwrap_version = StrictVersion(result.group(1))
         else:
index 08e2a4f7d877454903ff7892ed4058611a39e4bc..d313e7d1161073193eb6ce38c4786ae892eed962 100644 (file)
@@ -205,6 +205,15 @@ class Distribution:
                     for (opt, val) in cmd_options.items():
                         opt_dict[opt] = ("setup script", val)
 
+            if attrs.has_key('licence'):
+                attrs['license'] = attrs['licence']
+                del attrs['licence']
+                msg = "'licence' distribution option is deprecated; use 'license'"
+                if warnings is not None:
+                    warnings.warn(msg)
+                else:
+                    sys.stderr.write(msg + "\n")
+
             # Now work on the rest of the attributes.  Any attribute that's
             # not already defined is invalid!
             for (key,val) in attrs.items():
@@ -966,7 +975,7 @@ class DistributionMetadata:
                          "maintainer", "maintainer_email", "url",
                          "license", "description", "long_description",
                          "keywords", "platforms", "fullname", "contact",
-                         "contact_email", "licence", "classifiers",
+                         "contact_email", "license", "classifiers",
                          "download_url")
 
     def __init__ (self):
index 0442033d66d895512a009db50eb6053208db08ce..01420da9af0210a65f4b75d27ef9067806099c45 100644 (file)
@@ -53,9 +53,9 @@ def set_threshold(level):
     _global_log.threshold = level
 
 def set_verbosity(v):
-    if v == 0:
+    if v <= 0:
         set_threshold(WARN)
-    if v == 1:
+    elif v == 1:
         set_threshold(INFO)
-    if v == 2:
+    elif v >= 2:
         set_threshold(DEBUG)
index e07a6d5a0ca77942ce1814ce9c7e003936d36333..5f3d8de87232c5a3c75b0776fe2aebcd4751a19c 100644 (file)
@@ -1,7 +1,8 @@
 """distutils.msvccompiler
 
 Contains MSVCCompiler, an implementation of the abstract CCompiler class
-for the Microsoft Visual Studio."""
+for the Microsoft Visual Studio.
+"""
 
 # Written by Perry Stoll
 # hacked by Robin Becker and Thomas Heller to do a better job of
@@ -12,7 +13,6 @@ for the Microsoft Visual Studio."""
 __revision__ = "$Id$"
 
 import sys, os, string
-from types import *
 from distutils.errors import \
      DistutilsExecError, DistutilsPlatformError, \
      CompileError, LibError, LinkError
@@ -45,129 +45,128 @@ except ImportError:
         RegError = win32api.error
 
     except ImportError:
+        log.info("Warning: Can't read registry to find the "
+                 "necessary compiler setting\n"
+                 "Make sure that Python modules _winreg, "
+                 "win32api or win32con are installed.")
         pass
 
 if _can_read_reg:
-    HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT
-    HKEY_LOCAL_MACHINE = hkey_mod.HKEY_LOCAL_MACHINE
-    HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER
-    HKEY_USERS = hkey_mod.HKEY_USERS
+    HKEYS = (hkey_mod.HKEY_USERS,
+             hkey_mod.HKEY_CURRENT_USER,
+             hkey_mod.HKEY_LOCAL_MACHINE,
+             hkey_mod.HKEY_CLASSES_ROOT)
 
+def read_keys(base, key):
+    """Return list of registry keys."""
 
-
-def get_devstudio_versions ():
-    """Get list of devstudio versions from the Windows registry.  Return a
-       list of strings containing version numbers; the list will be
-       empty if we were unable to access the registry (eg. couldn't import
-       a registry-access module) or the appropriate registry keys weren't
-       found."""
-
-    if not _can_read_reg:
-        return []
-
-    K = 'Software\\Microsoft\\Devstudio'
+    try:
+        handle = RegOpenKeyEx(base, key)
+    except RegError:
+        return None
     L = []
-    for base in (HKEY_CLASSES_ROOT,
-                 HKEY_LOCAL_MACHINE,
-                 HKEY_CURRENT_USER,
-                 HKEY_USERS):
+    i = 0
+    while 1:
         try:
-            k = RegOpenKeyEx(base,K)
-            i = 0
-            while 1:
-                try:
-                    p = RegEnumKey(k,i)
-                    if p[0] in '123456789' and p not in L:
-                        L.append(p)
-                except RegError:
-                    break
-                i = i + 1
+            k = RegEnumKey(handle, i)
         except RegError:
-            pass
-    L.sort()
-    L.reverse()
+            break
+        L.append(k)
+        i = i + 1
     return L
 
-# get_devstudio_versions ()
-
-
-def get_msvc_paths (path, version='6.0', platform='x86'):
-    """Get a list of devstudio directories (include, lib or path).  Return
-       a list of strings; will be empty list if unable to access the
-       registry or appropriate registry keys not found."""
-
-    if not _can_read_reg:
-        return []
+def read_values(base, key):
+    """Return dict of registry keys and values.
 
-    L = []
-    if path=='lib':
-        path= 'Library'
-    path = string.upper(path + ' Dirs')
-    K = ('Software\\Microsoft\\Devstudio\\%s\\' +
-         'Build System\\Components\\Platforms\\Win32 (%s)\\Directories') % \
-        (version,platform)
-    for base in (HKEY_CLASSES_ROOT,
-                 HKEY_LOCAL_MACHINE,
-                 HKEY_CURRENT_USER,
-                 HKEY_USERS):
+    All names are converted to lowercase.
+    """
+    try:
+        handle = RegOpenKeyEx(base, key)
+    except RegError:
+        return None
+    d = {}
+    i = 0
+    while 1:
         try:
-            k = RegOpenKeyEx(base,K)
-            i = 0
-            while 1:
-                try:
-                    (p,v,t) = RegEnumValue(k,i)
-                    if string.upper(p) == path:
-                        V = string.split(v,';')
-                        for v in V:
-                            if hasattr(v, "encode"):
-                                try:
-                                    v = v.encode("mbcs")
-                                except UnicodeError:
-                                    pass
-                            if v == '' or v in L: continue
-                            L.append(v)
-                        break
-                    i = i + 1
-                except RegError:
-                    break
+            name, value, type = RegEnumValue(handle, i)
         except RegError:
+            break
+        name = name.lower()
+        d[convert_mbcs(name)] = convert_mbcs(value)
+        i = i + 1
+    return d
+
+def convert_mbcs(s):
+    enc = getattr(s, "encode", None)
+    if enc is not None:
+        try:
+            s = enc("mbcs")
+        except UnicodeError:
             pass
-    return L
-
-# get_msvc_paths()
-
-
-def find_exe (exe, version_number):
-    """Try to find an MSVC executable program 'exe' (from version
-       'version_number' of MSVC) in several places: first, one of the MSVC
-       program search paths from the registry; next, the directories in the
-       PATH environment variable.  If any of those work, return an absolute
-       path that is known to exist.  If none of them work, just return the
-       original program name, 'exe'."""
-
-    for p in get_msvc_paths ('path', version_number):
-        fn = os.path.join (os.path.abspath(p), exe)
-        if os.path.isfile(fn):
-            return fn
-
-    # didn't find it; try existing path
-    for p in string.split (os.environ['Path'],';'):
-        fn = os.path.join(os.path.abspath(p),exe)
-        if os.path.isfile(fn):
-            return fn
-
-    return exe                          # last desperate hope
-
-
-def set_path_env_var (name, version_number):
-    """Set environment variable 'name' to an MSVC path type value obtained
-       from 'get_msvc_paths()'.  This is equivalent to a SET command prior
-       to execution of spawned commands."""
-
-    p = get_msvc_paths (name, version_number)
-    if p:
-        os.environ[name] = string.join (p,';')
+    return s
+
+class MacroExpander:
+
+    def __init__(self, version):
+        self.macros = {}
+        self.load_macros(version)
+
+    def set_macro(self, macro, path, key):
+        for base in HKEYS:
+            d = read_values(base, path)
+            if d:
+                self.macros["$(%s)" % macro] = d[key]
+                break
+              
+    def load_macros(self, version):
+        vsbase = r"Software\Microsoft\VisualStudio\%0.1f" % version
+        self.set_macro("VCInstallDir", vsbase + r"\Setup\VC", "productdir")
+        self.set_macro("VSInstallDir", vsbase + r"\Setup\VS", "productdir")
+        net = r"Software\Microsoft\.NETFramework"
+        self.set_macro("FrameworkDir", net, "installroot")
+        if version > 7.0:
+            self.set_macro("FrameworkSDKDir", net, "sdkinstallrootv1.1")
+        else:
+            self.set_macro("FrameworkSDKDir", net, "sdkinstallroot")
 
+        p = r"Software\Microsoft\NET Framework Setup\Product"
+        for base in HKEYS:
+            try:
+                h = RegOpenKeyEx(base, p)
+            except RegError:
+                continue
+            key = RegEnumKey(h, 0)
+            d = read_values(base, r"%s\%s" % (p, key))
+            self.macros["$(FrameworkVersion)"] = d["version"]
+
+    def sub(self, s):
+        for k, v in self.macros.items():
+            s = string.replace(s, k, v)
+        return s
+
+def get_build_version():
+    """Return the version of MSVC that was used to build Python.
+
+    For Python 2.3 and up, the version number is included in
+    sys.version.  For earlier versions, assume the compiler is MSVC 6.
+    """
+
+    prefix = "MSC v."
+    i = string.find(sys.version, prefix)
+    if i == -1:
+        return 6
+    i = i + len(prefix)
+    s, rest = sys.version[i:].split(" ", 1)
+    majorVersion = int(s[:-2]) - 6
+    minorVersion = int(s[2:3]) / 10.0
+    # I don't think paths are affected by minor version in version 6
+    if majorVersion == 6:
+        minorVersion = 0
+    if majorVersion >= 6:
+        return majorVersion + minorVersion
+    # else we don't know what version of the compiler this is
+    return None
+    
 
 class MSVCCompiler (CCompiler) :
     """Concrete class that implements an interface to Microsoft Visual C++,
@@ -199,39 +198,37 @@ class MSVCCompiler (CCompiler) :
     static_lib_format = shared_lib_format = '%s%s'
     exe_extension = '.exe'
 
-
-    def __init__ (self,
-                  verbose=0,
-                  dry_run=0,
-                  force=0):
-
+    def __init__ (self, verbose=0, dry_run=0, force=0):
         CCompiler.__init__ (self, verbose, dry_run, force)
-        versions = get_devstudio_versions ()
-
-        if versions:
-            version = versions[0]  # highest version
-
-            self.cc   = find_exe("cl.exe", version)
-            self.linker = find_exe("link.exe", version)
-            self.lib  = find_exe("lib.exe", version)
-            self.rc   = find_exe("rc.exe", version)     # resource compiler
-            self.mc   = find_exe("mc.exe", version)     # message compiler
-            set_path_env_var ('lib', version)
-            set_path_env_var ('include', version)
-            path=get_msvc_paths('path', version)
-            try:
-                for p in string.split(os.environ['path'],';'):
-                    path.append(p)
-            except KeyError:
-                pass
-            os.environ['path'] = string.join(path,';')
+        self.__version = get_build_version()
+        if self.__version >= 7:
+            self.__root = r"Software\Microsoft\VisualStudio"
+            self.__macros = MacroExpander(self.__version)
         else:
-            # devstudio not found in the registry
-            self.cc = "cl.exe"
-            self.linker = "link.exe"
-            self.lib = "lib.exe"
-            self.rc = "rc.exe"
-            self.mc = "mc.exe"
+            self.__root = r"Software\Microsoft\Devstudio"
+        self.__paths = self.get_msvc_paths("path")
+
+        if len (self.__paths) == 0:
+            raise DistutilsPlatformError, \
+                  ("Python was built with version %s of Visual Studio, "
+                   "and extensions need to be built with the same "
+                   "version of the compiler, but it isn't installed." % self.__version)
+
+        self.cc = self.find_exe("cl.exe")
+        self.linker = self.find_exe("link.exe")
+        self.lib = self.find_exe("lib.exe")
+        self.rc = self.find_exe("rc.exe")   # resource compiler
+        self.mc = self.find_exe("mc.exe")   # message compiler
+        self.set_path_env_var('lib')
+        self.set_path_env_var('include')
+
+        # extend the MSVC path with the current path
+        try:
+            for p in string.split(os.environ['path'], ';'):
+                self.__paths.append(p)
+        except KeyError:
+            pass
+        os.environ['path'] = string.join(self.__paths, ';')
 
         self.preprocess_options = None
         self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GX' ,
@@ -500,4 +497,69 @@ class MSVCCompiler (CCompiler) :
 
     # find_library_file ()
 
-# class MSVCCompiler
+    # Helper methods for using the MSVC registry settings
+
+    def find_exe(self, exe):
+        """Return path to an MSVC executable program.
+
+        Tries to find the program in several places: first, one of the
+        MSVC program search paths from the registry; next, the directories
+        in the PATH environment variable.  If any of those work, return an
+        absolute path that is known to exist.  If none of them work, just
+        return the original program name, 'exe'.
+        """
+
+        for p in self.__paths:
+            fn = os.path.join(os.path.abspath(p), exe)
+            if os.path.isfile(fn):
+                return fn
+
+        # didn't find it; try existing path
+        for p in string.split(os.environ['Path'],';'):
+            fn = os.path.join(os.path.abspath(p),exe)
+            if os.path.isfile(fn):
+                return fn
+
+        return exe
+    
+    def get_msvc_paths(self, path, platform='x86'):
+        """Get a list of devstudio directories (include, lib or path).
+
+        Return a list of strings.  The list will be empty if unable to
+        access the registry or appropriate registry keys not found.
+        """
+
+        if not _can_read_reg:
+            return []
+
+        path = path + " dirs"
+        if self.__version >= 7:
+            key = (r"%s\%0.1f\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories"
+                   % (self.__root, self.__version))
+        else:
+            key = (r"%s\6.0\Build System\Components\Platforms"
+                   r"\Win32 (%s)\Directories" % (self.__root, platform))
+
+        for base in HKEYS:
+            d = read_values(base, key)
+            if d:
+                if self.__version >= 7:
+                    return string.split(self.__macros.sub(d[path]), ";")
+                else:
+                    return string.split(d[path], ";")
+        return []
+
+    def set_path_env_var(self, name):
+        """Set environment variable 'name' to an MSVC path type value.
+
+        This is equivalent to a SET command prior to execution of spawned
+        commands.
+        """
+
+        if name == "lib":
+            p = self.get_msvc_paths("library")
+        else:
+            p = self.get_msvc_paths(name)
+        if p:
+            os.environ[name] = string.join(p, ';')
+
index 2a6b1beeea410b898bcae3dd5b52965b1913aa81..11ecb9f6aec35dd8bfb80d5fb0aad74e04a73129 100644 (file)
@@ -77,6 +77,8 @@ class UnixCCompiler(CCompiler):
     shared_lib_extension = ".so"
     dylib_lib_extension = ".dylib"
     static_lib_format = shared_lib_format = dylib_lib_format = "lib%s%s"
+    if sys.platform == "cygwin":
+        exe_extension = ".exe"
 
     def preprocess(self, source,
                    output_file=None, macros=None, include_dirs=None,
@@ -201,8 +203,10 @@ class UnixCCompiler(CCompiler):
         if sys.platform[:6] == "darwin":
             # MacOSX's linker doesn't understand the -R flag at all
             return "-L" + dir
+        elif sys.platform[:5] == "hp-ux":
+            return "+s -L" + dir
         elif compiler[:3] == "gcc" or compiler[:3] == "g++":
-            return "-Wl,-R" + dir
+          return "-Wl,-R" + dir
         else:
             return "-R" + dir