X-Git-Url: http://git.tremily.us/?a=blobdiff_plain;f=src%2Fengine%2FSCons%2FTool%2FMSCommon%2Fvc.py;h=b8aae84282e3d1493d4b99c61c8b0ce622304cda;hb=6a218d30e5fa1a14835a31129881b4288db7dc1d;hp=130acf5d5803e5046d736bdf5d391a5761943bb4;hpb=66cbc7150e5d544c999c3611b181a3a5bdb4bae2;p=scons.git diff --git a/src/engine/SCons/Tool/MSCommon/vc.py b/src/engine/SCons/Tool/MSCommon/vc.py index 130acf5d..b8aae842 100644 --- a/src/engine/SCons/Tool/MSCommon/vc.py +++ b/src/engine/SCons/Tool/MSCommon/vc.py @@ -34,9 +34,11 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" __doc__ = """Module for Visual C/C++ detection and configuration. """ +import SCons.compat import os import platform +from string import digits as string_digits import SCons.Warnings @@ -44,12 +46,20 @@ import common debug = common.debug +import sdk + +get_installed_sdks = sdk.get_installed_sdks + + class VisualCException(Exception): pass class UnsupportedVersion(VisualCException): pass +class UnsupportedArch(VisualCException): + pass + class MissingConfiguration(VisualCException): pass @@ -84,6 +94,11 @@ def get_host_target(env): host_platform = env.get('HOST_ARCH') if not host_platform: host_platform = platform.machine() + # TODO(2.5): the native Python platform.machine() function returns + # '' on all Python versions before 2.6, after which it also uses + # PROCESSOR_ARCHITECTURE. + if not host_platform: + host_platform = os.environ.get('PROCESSOR_ARCHITECTURE', '') target_platform = env.get('TARGET_ARCH') if not target_platform: target_platform = host_platform @@ -91,7 +106,8 @@ def get_host_target(env): try: host = _ARCH_TO_CANONICAL[host_platform] except KeyError, e: - raise ValueError("Unrecognized host architecture %s" % host_platform) + msg = "Unrecognized host architecture %s" + raise ValueError(msg % repr(host_platform)) try: target = _ARCH_TO_CANONICAL[target_platform] @@ -100,16 +116,18 @@ def get_host_target(env): return (host, target) -_VCVER = ["10.0", "9.0", "8.0", "7.1", "7.0", "6.0"] +_VCVER = ["10.0", "9.0", "9.0Exp","8.0", "8.0Exp","7.1", "7.0", "6.0"] _VCVER_TO_PRODUCT_DIR = { '10.0': [ r'Microsoft\VisualStudio\10.0\Setup\VC\ProductDir'], '9.0': [ - r'Microsoft\VisualStudio\9.0\Setup\VC\ProductDir', + r'Microsoft\VisualStudio\9.0\Setup\VC\ProductDir'], + '9.0Exp' : [ r'Microsoft\VCExpress\9.0\Setup\VC\ProductDir'], '8.0': [ - r'Microsoft\VisualStudio\8.0\Setup\VC\ProductDir', + r'Microsoft\VisualStudio\8.0\Setup\VC\ProductDir'], + '8.0Exp': [ r'Microsoft\VCExpress\8.0\Setup\VC\ProductDir'], '7.1': [ r'Microsoft\VisualStudio\7.1\Setup\VC\ProductDir'], @@ -119,6 +137,42 @@ _VCVER_TO_PRODUCT_DIR = { r'Microsoft\VisualStudio\6.0\Setup\Microsoft Visual C++\ProductDir'] } +def msvc_version_to_maj_min(msvc_version): + t = msvc_version.split(".") + if not len(t) == 2: + raise ValueError("Unrecognized version %s" % msvc_version) + try: + maj = int(t[0]) + min = int(t[1]) + return maj, min + except ValueError, e: + raise ValueError("Unrecognized version %s" % msvc_version) + +def is_host_target_supported(host_target, msvc_version): + """Return True if the given (host, target) tuple is supported given the + msvc version. + + Parameters + ---------- + host_target: tuple + tuple of (canonalized) host-target, e.g. ("x86", "amd64") for cross + compilation from 32 bits windows to 64 bits. + msvc_version: str + msvc version (major.minor, e.g. 10.0) + + Note + ---- + This only check whether a given version *may* support the given (host, + target), not that the toolchain is actually present on the machine. + """ + # We assume that any Visual Studio version supports x86 as a target + if host_target[1] != "x86": + maj, min = msvc_version_to_maj_min(msvc_version) + if maj < 8: + return False + + return True + def find_vc_pdir(msvc_version): """Try to find the product directory for the given version. @@ -152,12 +206,20 @@ def find_vc_pdir(msvc_version): raise MissingConfiguration("registry dir %s not found on the filesystem" % comps) return None -def find_batch_file(msvc_version): +def find_batch_file(env,msvc_version): + """ + Find the location of the batch script which should set up the compiler + for any TARGET_ARCH whose compilers were installed by Visual Studio/VCExpress + """ pdir = find_vc_pdir(msvc_version) if pdir is None: raise NoVersionFound("No version of Visual Studio found") + + debug('vc.py: find_batch_file() pdir:%s'%pdir) - vernum = float(msvc_version) + # filter out e.g. "Exp" from the version name + msvc_ver_numeric = ''.join([x for x in msvc_version if x in string_digits + "."]) + vernum = float(msvc_ver_numeric) if 7 <= vernum < 8: pdir = os.path.join(pdir, os.pardir, "Common7", "Tools") batfilename = os.path.join(pdir, "vsvars32.bat") @@ -167,12 +229,33 @@ def find_batch_file(msvc_version): else: # >= 8 batfilename = os.path.join(pdir, "vcvarsall.bat") - if os.path.exists(batfilename): - return batfilename - else: + if not os.path.exists(batfilename): debug("Not found: %s" % batfilename) - return None + batfilename = None + + installed_sdks=get_installed_sdks() + (host_arch,target_arch)=get_host_target(env) + for _sdk in installed_sdks: + sdk_bat_file=_sdk.get_sdk_vc_script(host_arch,target_arch) + sdk_bat_file_path=os.path.join(pdir,sdk_bat_file) + debug('vc.py:find_batch_file() sdk_bat_file_path:%s'%sdk_bat_file_path) + if os.path.exists(sdk_bat_file_path): + return (batfilename,sdk_bat_file_path) + else: + debug("vc.py:find_batch_file() not found:%s"%sdk_bat_file_path) + else: + return (batfilename,None) + +__INSTALLED_VCS_RUN = None + +def cached_get_installed_vcs(): + global __INSTALLED_VCS_RUN + if __INSTALLED_VCS_RUN is None: + ret = get_installed_vcs() + __INSTALLED_VCS_RUN = ret + + return __INSTALLED_VCS_RUN def get_installed_vcs(): installed_versions = [] @@ -188,6 +271,10 @@ def get_installed_vcs(): debug('did not find VC %s: caught exception %s' % (ver, str(e))) return installed_versions +def reset_installed_vcs(): + """Make it try again to find VC. This is just for the tests.""" + __INSTALLED_VCS_RUN = None + def script_env(script, args=None): stdout = common.get_output(script, args) # Stupid batch files do not set return code: we take a look at the @@ -203,6 +290,8 @@ def get_default_version(env): msvc_version = env.get('MSVC_VERSION') msvs_version = env.get('MSVS_VERSION') + + debug('get_default_version(): msvc_version:%s msvs_version:%s'%(msvc_version,msvs_version)) if msvs_version and not msvc_version: SCons.Warnings.warn( @@ -219,7 +308,7 @@ def get_default_version(env): % (msvc_version, msvs_version)) return msvs_version if not msvc_version: - installed_vcs = get_installed_vcs() + installed_vcs = cached_get_installed_vcs() debug('installed_vcs:%s' % installed_vcs) if not installed_vcs: msg = 'No installed VCs' @@ -239,7 +328,7 @@ def msvc_setup_env_once(env): if not has_run: msvc_setup_env(env) - env["MSVC_SETUP_RUN"] = False + env["MSVC_SETUP_RUN"] = True def msvc_setup_env(env): debug('msvc_setup_env()') @@ -250,8 +339,6 @@ def msvc_setup_env(env): "compilers most likely not set correctly" SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg) return None - - host_platform, target_platform = get_host_target(env) debug('msvc_setup_env: using specified MSVC version %s\n' % repr(version)) # XXX: we set-up both MSVS version for backward @@ -261,49 +348,62 @@ def msvc_setup_env(env): env['MSVS'] = {} try: - script = find_batch_file(version) + (vc_script,sdk_script) = find_batch_file(env,version) + debug('vc.py:msvc_setup_env() vc_script:%s sdk_script:%s'%(vc_script,sdk_script)) except VisualCException, e: msg = str(e) debug('Caught exception while looking for batch file (%s)' % msg) - warn_msg = "VC version %s not installed - C/C++ compilers most " \ - "likely not set correctly" % version - warn_msg += " \n Install versions are: %s" % get_installed_vcs() + warn_msg = "VC version %s not installed. " + \ + "C/C++ compilers are most likely not set correctly.\n" + \ + " Installed versions are: %s" + warn_msg = warn_msg % (version, cached_get_installed_vcs()) SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg) return None - + + debug('vc.py:msvc_setup_env() vc_script:%s sdk_script:%s'%(vc_script,sdk_script)) use_script = env.get('MSVC_USE_SCRIPT', True) if SCons.Util.is_String(use_script): debug('use_script 1 %s\n' % repr(use_script)) d = script_env(use_script) elif use_script: + host_platform, target_platform = get_host_target(env) host_target = (host_platform, target_platform) + if not is_host_target_supported(host_target, version): + warn_msg = "host, target = %s not supported for MSVC version %s" % \ + (host_target, version) + SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg) arg = _HOST_TARGET_ARCH_TO_BAT_ARCH[host_target] - debug('use_script 2 %s, args:%s\n' % (repr(script), arg)) - try: - d = script_env(script, args=arg) - except BatchFileExecutionError, e: - msg = "MSVC error while executing %s with args %s (error was %s)" % \ - (script, arg, str(e)) - raise SCons.Errors.UserError(msg) + debug('use_script 2 %s, args:%s\n' % (repr(vc_script), arg)) + if vc_script: + try: + d = script_env(vc_script, args=arg) + except BatchFileExecutionError, e: + debug('use_script 3: failed running VC script %s: %s: Error:%s'%(repr(vc_script),arg,e)) + vc_script=None + if not vc_script and sdk_script: + debug('use_script 4: trying sdk script: %s'%(sdk_script)) + try: + d = script_env(sdk_script,args=[]) + except BatchFileExecutionError,e: + debug('use_script 5: failed running SDK script %s: Error:%s'%(repr(sdk_script),e)) + return None + elif not vc_script and not sdk_script: + debug('use_script 6: Neither VC script nor SDK script found') + return None + else: - debug('msvc.get_default_env()\n') - d = msvc.get_default_env() + debug('MSVC_USE_SCRIPT set to False') + warn_msg = "MSVC_USE_SCRIPT set to False, assuming environment " \ + "set correctly." + SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg) + return None for k, v in d.items(): + debug('vc.py:msvc_setup_env() env:%s -> %s'%(k,v)) env.PrependENVPath(k, v, delete_existing=True) -def msvc_setup_env_once(env): - try: - has_run = env["MSVC_SETUP_RUN"] - except KeyError: - has_run = False - - if not has_run: - msvc_setup_env(env) - env["MSVC_SETUP_RUN"] = True - def msvc_exists(version=None): - vcs = get_installed_vcs() + vcs = cached_get_installed_vcs() if version is None: return len(vcs) > 0 return version in vcs