diff options
Diffstat (limited to 'src/engine/SCons/Tool/msvc.py')
-rw-r--r-- | src/engine/SCons/Tool/msvc.py | 320 |
1 files changed, 225 insertions, 95 deletions
diff --git a/src/engine/SCons/Tool/msvc.py b/src/engine/SCons/Tool/msvc.py index 6f0c516..f936535 100644 --- a/src/engine/SCons/Tool/msvc.py +++ b/src/engine/SCons/Tool/msvc.py @@ -35,59 +35,121 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os.path import string +import types +import re import SCons.Action import SCons.Tool import SCons.Errors +import SCons.Warnings import SCons.Builder import SCons.Util import SCons.Platform.win32 +import SCons.Tool.msvs CSuffixes = ['.c', '.C'] CXXSuffixes = ['.cc', '.cpp', '.cxx', '.c++', '.C++'] -def get_devstudio_versions(): - """ - Get list of devstudio versions from the Windows registry. Return a - list of strings containing version numbers; an exception will be raised - if we were unable to access the registry (eg. couldn't import - a registry-access module) or the appropriate registry keys weren't - found. - """ - +def _parse_msvc7_overrides(version): + """ Parse any overridden defaults for MSVS directory locations in MSVS .NET. """ + + # First, we get the shell folder for this user: if not SCons.Util.can_read_reg: raise SCons.Errors.InternalError, "No Windows registry module was found" - K = 'Software\\Microsoft\\Devstudio' - L = [] - for base in (SCons.Util.HKEY_CLASSES_ROOT, - SCons.Util.HKEY_LOCAL_MACHINE, - SCons.Util.HKEY_CURRENT_USER, - SCons.Util.HKEY_USERS): + comps = "" + try: + (comps, t) = SCons.Util.RegGetValue(SCons.Util.HKEY_CURRENT_USER, + r'Software\Microsoft\Windows\CurrentVersion' +\ + r'\Explorer\Shell Folders\Local AppData') + except SCons.Util.RegError: + raise SCons.Errors.InternalError, "The Local AppData directory was not found in the registry." + + comps = comps + '\\Microsoft\\VisualStudio\\' + version + '\\VSComponents.dat' + dirs = {} + + if os.path.exists(comps): + # now we parse the directories from this file, if it exists. + # We only look for entries after: [VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories], + # since this file could contain a number of things... + f = open(comps,'r') + line = f.readline() + found = 0 + while line: + line.strip() + if found == 1: + (key, val) = line.split('=',1) + key = key.replace(' Dirs','') + dirs[key.upper()] = val + if line.find(r'[VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories]') >= 0: + found = 1 + if line == '': + found = 0 + line = f.readline() + f.close() + else: + # since the file didn't exist, we have only the defaults in + # the registry to work with. try: - k = SCons.Util.RegOpenKeyEx(base,K) + K = 'SOFTWARE\\Microsoft\\VisualStudio\\' + version + K = K + r'\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories' + k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,K) i = 0 while 1: try: - p = SCons.Util.RegEnumKey(k,i) - if p[0] in '123456789' and p not in L: - L.append(p) + (key,val,t) = SCons.Util.RegEnumValue(k,i) + key = key.replace(' Dirs','') + dirs[key.upper()] = val + i = i + 1 except SCons.Util.RegError: break - i = i + 1 except SCons.Util.RegError: - pass + # if we got here, then we didn't find the registry entries: + raise SCons.Errors.InternalError, "Unable to find MSVC paths in the registry." + return dirs + +def _get_msvc7_path(path, version, platform): + """ + Get Visual Studio directories from version 7 (MSVS .NET) + (it has a different registry structure than versions before it) + """ + # first, look for a customization of the default values in the + # registry: These are sometimes stored in the Local Settings area + # for Visual Studio, in a file, so we have to parse it. + dirs = _parse_msvc7_overrides(version) + + if dirs.has_key(path): + p = dirs[path] + else: + raise SCons.Errors.InternalError, "Unable to retrieve the %s path from MS VC++."%path + + # collect some useful information for later expansions... + paths = SCons.Tool.msvs.get_msvs_install_dirs(version) + + # expand the directory path variables that we support. If there + # is a variable we don't support, then replace that entry with + # "---Unknown Location VSInstallDir---" or something similar, to clue + # people in that we didn't find something, and so env expansion doesn't + # do weird things with the $(xxx)'s + s = re.compile('\$\(([a-zA-Z0-9_]+?)\)') + + def repl(match): + key = string.upper(match.group(1)) + if paths.has_key(key): + return paths[key] + else: + return '---Unknown Location %s---' % match.group() - if not L: - raise SCons.Errors.InternalError, "DevStudio was not found." + rv = [] + for entry in p.split(os.pathsep): + entry = s.sub(repl,entry) + rv.append(entry) - L.sort() - L.reverse() - return L + return string.join(rv,os.pathsep) def get_msvc_path (path, version, platform='x86'): """ - Get a list of devstudio directories (include, lib or path). Return + Get a list of visualstudio directories (include, lib or path). Return a string delimited by ';'. An exception will be raised if unable to access the registry or appropriate registry keys not found. """ @@ -95,16 +157,22 @@ def get_msvc_path (path, version, platform='x86'): if not SCons.Util.can_read_reg: raise SCons.Errors.InternalError, "No Windows registry module was found" - if path=='lib': - path= 'Library' + # normalize the case for comparisons (since the registry is case + # insensitive) + path = string.upper(path) + + if path=='LIB': + path= 'LIBRARY' + + if float(version) >= 7.0: + return _get_msvc7_path(path, version, platform) + path = string.upper(path + ' Dirs') K = ('Software\\Microsoft\\Devstudio\\%s\\' + 'Build System\\Components\\Platforms\\Win32 (%s)\\Directories') % \ (version,platform) - for base in (SCons.Util.HKEY_CLASSES_ROOT, - SCons.Util.HKEY_LOCAL_MACHINE, - SCons.Util.HKEY_CURRENT_USER, - SCons.Util.HKEY_USERS): + for base in (SCons.Util.HKEY_CURRENT_USER, + SCons.Util.HKEY_LOCAL_MACHINE): try: k = SCons.Util.RegOpenKeyEx(base,K) i = 0 @@ -120,77 +188,127 @@ def get_msvc_path (path, version, platform='x86'): pass # if we got here, then we didn't find the registry entries: - raise SCons.Errors.InternalError, "%s was not found in the registry."%path - -def get_msdev_dir(version): - """Returns the root directory of the MSDev installation from the - registry if it can be found, otherwise we guess.""" - if SCons.Util.can_read_reg: - K = ('Software\\Microsoft\\Devstudio\\%s\\' + - 'Products\\Microsoft Visual C++') % \ - version - for base in (SCons.Util.HKEY_LOCAL_MACHINE, - SCons.Util.HKEY_CURRENT_USER): - try: - k = SCons.Util.RegOpenKeyEx(base,K) - val, tok = SCons.Util.RegQueryValueEx(k, 'ProductDir') - return os.path.split(val)[0] - except SCons.Util.RegError: - pass - -def get_msdev_paths(version=None): + raise SCons.Errors.InternalError, "The %s path was not found in the registry."%path + +def _get_msvc6_default_paths(version): + """Return a 3-tuple of (INCLUDE, LIB, PATH) as the values of those + three environment variables that should be set in order to execute + the MSVC 6.0 tools properly, if the information wasn't available + from the registry.""" + MVSdir = None + paths = {} + exe_path = '' + lib_path = '' + include_path = '' + try: + paths = SCons.Tool.msvs.get_msvs_install_dirs(version) + MVSdir = paths['VSINSTALLDIR'] + except (SCons.Util.RegError, SCons.Errors.InternalError): + if os.environ.has_key('MSDEVDIR'): + MVSdir = os.path.normpath(os.path.join(os.environ['MSDEVDIR'],'..','..')) + else: + MVSdir = r'C:\Program Files\Microsoft Visual Studio' + if MVSdir: + if SCons.Util.can_read_reg and paths.has_key('VCINSTALLDIR'): + MVSVCdir = paths['VCINSTALLDIR'] + else: + MVSVCdir = os.path.join(MVSdir,'VC98') + + MVSCommondir = r'%s\Common' % MVSdir + include_path = r'%s\ATL\include;%s\MFC\include;%s\include' % (MVSVCdir, MVSVCdir, MVSVCdir) + lib_path = r'%s\MFC\lib;%s\lib' % (MVSVCdir, MVSVCdir) + exe_path = r'%s\MSDev98\bin;%s\bin' % (MVSCommondir, MVSVCdir) + return (include_path, lib_path, exe_path) + +def _get_msvc7_default_paths(version): + """Return a 3-tuple of (INCLUDE, LIB, PATH) as the values of those + three environment variables that should be set in order to execute + the MSVC .NET tools properly, if the information wasn't available + from the registry.""" + + MVSdir = None + paths = {} + exe_path = '' + lib_path = '' + include_path = '' + try: + paths = SCons.Tool.msvs.get_msvs_install_dirs(version) + MVSdir = paths['VSINSTALLDIR'] + except (KeyError, SCons.Util.RegError, SCons.Errors.InternalError): + if os.environ.has_key('VSCOMNTOOLS'): + MVSdir = os.path.normpath(os.path.join(os.environ['VSCOMNTOOLS'],'..','..')) + else: + # last resort -- default install location + MVSdir = r'C:\Program Files\Microsoft Visual Studio .NET' + + if not MVSdir: + if SCons.Util.can_read_reg and paths.has_key('VCINSTALLDIR'): + MVSVCdir = paths['VCINSTALLDIR'] + else: + MVSVCdir = os.path.join(MVSdir,'Vc7') + + MVSCommondir = r'%s\Common7' % MVSdir + include_path = r'%s\atlmfc\include;%s\include' % (MVSVCdir, MVSVCdir, MVSVCdir) + lib_path = r'%s\atlmfc\lib;%s\lib' % (MVSVCdir, MVSVCdir) + exe_path = r'%s\Tools\bin;%s\Tools;%s\bin' % (MVSCommondir, MVSCommondir, MVSVCdir) + return (include_path, lib_path, exe_path) + +def get_msvc_paths(version=None): """Return a 3-tuple of (INCLUDE, LIB, PATH) as the values of those three environment variables that should be set in order to execute the MSVC tools properly.""" exe_path = '' lib_path = '' include_path = '' + + if not version and not SCons.Util.can_read_reg: + version = '6.0' + try: if not version: - version = get_devstudio_versions()[0] #use highest version + version = get_visualstudio_versions()[0] #use highest version + include_path = get_msvc_path("include", version) lib_path = get_msvc_path("lib", version) - exe_path = get_msvc_path("path", version) + ";" + os.environ['PATH'] + exe_path = get_msvc_path("path", version) + except (SCons.Util.RegError, SCons.Errors.InternalError): - # Could not get the configured directories from the registry. - # However, the configured directories only appear if the user - # changes them from the default. Therefore, we'll see if - # we can get the path to the MSDev base installation from - # the registry and deduce the default directories. - MVSdir = None - if version: - MVSdir = get_msdev_dir(version) - if MVSdir: - MVSVCdir = r'%s\VC98' % MVSdir - MVSCommondir = r'%s\Common' % MVSdir - include_path = r'%s\atl\include;%s\mfc\include;%s\include' % (MVSVCdir, MVSVCdir, MVSVCdir) - lib_path = r'%s\mfc\lib;%s\lib' % (MVSVCdir, MVSVCdir) - try: - extra_path = os.pathsep + os.environ['PATH'] - except KeyError: - extra_path = '' - exe_path = (r'%s\MSDev98\Bin;%s\Bin' % (MVSCommondir, MVSVCdir)) + extra_path + # Could not get all the configured directories from the + # registry. However, some of the configured directories only + # appear if the user changes them from the default. + # Therefore, we'll see if we can get the path to the MSDev + # base installation from the registry and deduce the default + # directories. + if float(version) >= 7.0: + return _get_msvc7_default_paths(version) else: - # The DevStudio environment variables don't exist, - # so just use the variables from the source environment. - progfiles = SCons.Platform.win32.get_program_files_dir() - MVSdir = os.path.join(progfiles,r'Microsoft Visual Studio') - MVSVCdir = r'%s\VC98' % MVSdir - MVSCommondir = r'%s\Common' % MVSdir - try: - include_path = os.environ['INCLUDE'] - except KeyError: - include_path = '' - try: - lib_path = os.environ['LIB'] - except KeyError: - lib_path = '' - try: - exe_path = os.environ['PATH'] - except KeyError: - exe_path = '' + return _get_msvc6_default_paths(version) + return (include_path, lib_path, exe_path) +def get_msvc_default_paths(version = None): + """Return a 3-tuple of (INCLUDE, LIB, PATH) as the values of those + three environment variables that should be set in order to execute + the MSVC tools properly. This will only return the default + locations for the tools, not the values used by MSVS in their + directory setup area. This can help avoid problems with different + developers having different settings, and should allow the tools + to run in most cases.""" + + if not version and not SCons.Util.can_read_reg: + version = '6.0' + + try: + if not version: + version = get_visualstudio_versions()[0] #use highest version + except: + pass + + if float(version) >= 7.0: + return _get_msvc7_default_paths(version) + else: + return _get_msvc6_default_paths(version) + def validate_vars(env): """Validate the PDB, PCH, and PCHSTOP construction variables.""" if env.has_key('PCH') and env['PCH']: @@ -282,10 +400,18 @@ def generate(env): CScan.add_skey('.rc') env['BUILDERS']['RES'] = res_builder - if SCons.Util.can_read_reg: - include_path, lib_path, exe_path = get_msdev_paths() - env['ENV']['INCLUDE'] = include_path - env['ENV']['PATH'] = exe_path + version = SCons.Tool.msvs.get_default_visualstudio_version(env) + + if env.has_key('MSVS_IGNORE_IDE_PATHS') and env['MSVS_IGNORE_IDE_PATHS']: + include_path, lib_path, exe_path = get_msvc_default_paths(version) + else: + include_path, lib_path, exe_path = get_msvc_paths(version) + + # since other tools can set these, we just make sure that the + # relevant stuff from MSVS is in there somewhere. + env.PrependENVPath('INCLUDE', include_path) + env.PrependENVPath('LIB', lib_path) + env.PrependENVPath('PATH', exe_path) env['CFILESUFFIX'] = '.c' env['CXXFILESUFFIX'] = '.cc' @@ -294,4 +420,8 @@ def generate(env): env['BUILDERS']['PCH'] = pch_builder def exists(env): - return env.Detect('cl') + if not SCons.Util.can_read_reg or not SCons.Tool.msvs.get_visualstudio_versions(): + return env.Detect('cl') + else: + # there's at least one version of MSVS installed. + return True |