__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
-import sys, os.path, glob, re
+import math, sys, os.path, glob, string, re
-is_win32 = sys.platform == 'win32'
+is_windows = sys.platform == 'win32'
+is_win64 = is_windows and (os.environ['PROCESSOR_ARCHITECTURE'] == 'AMD64' or
+ ('PROCESSOR_ARCHITEW6432' in os.environ and
+ os.environ['PROCESSOR_ARCHITEW6432'] == 'AMD64'))
is_linux = sys.platform == 'linux2'
+is_mac = sys.platform == 'darwin'
-if is_win32:
+if is_windows:
import SCons.Tool.msvc
elif is_linux:
import SCons.Tool.gcc
+elif is_mac:
+ import SCons.Tool.gcc
import SCons.Util
import SCons.Warnings
-
-def fltcmp(a, b):
- """Compare strings as floats"""
- return cmp(float(b), float(a))
+# Exceptions for this tool
+class IntelCError(SCons.Errors.InternalError):
+ pass
+class MissingRegistryError(IntelCError): # missing registry entry
+ pass
+class MissingDirError(IntelCError): # dir not found
+ pass
+class NoRegistryModuleError(IntelCError): # can't read registry at all
+ pass
+
+def uniquify(s):
+ """Return a sequence containing only one copy of each unique element from input sequence s.
+ Does not preserve order.
+ Input sequence must be hashable (i.e. must be usable as a dictionary key)."""
+ u = {}
+ for x in s:
+ u[x] = 1
+ return u.keys()
+
+def linux_ver_normalize(vstr):
+ """Normalize a Linux compiler version number.
+ Intel changed from "80" to "9.0" in 2005, so we assume if the number
+ is greater than 60 it's an old-style number and otherwise new-style.
+ Always returns an old-style float like 80 or 90 for compatibility with Windows.
+ Shades of Y2K!"""
+ # Check for version number like 9.1.026: return 91.026
+ m = re.match(r'([0-9]+)\.([0-9]+)\.([0-9]+)', vstr)
+ if m:
+ vmaj,vmin,build = m.groups()
+ return float(vmaj) * 10 + float(vmin) + float(build) / 1000.;
+ else:
+ f = float(vstr)
+ if is_windows:
+ return f
+ else:
+ if f < 60: return f * 10.0
+ else: return f
+
+def check_abi(abi):
+ """Check for valid ABI (application binary interface) name,
+ and map into canonical one"""
+ if not abi:
+ return None
+ abi = abi.lower()
+ # valid_abis maps input name to canonical name
+ if is_windows:
+ valid_abis = {'ia32' : 'ia32',
+ 'x86' : 'ia32',
+ 'ia64' : 'ia64',
+ 'em64t' : 'em64t',
+ 'amd64' : 'em64t'}
+ if is_linux:
+ valid_abis = {'ia32' : 'ia32',
+ 'x86' : 'ia32',
+ 'x86_64' : 'x86_64',
+ 'em64t' : 'x86_64',
+ 'amd64' : 'x86_64'}
+ if is_mac:
+ valid_abis = {'ia32' : 'ia32',
+ 'x86' : 'ia32',
+ 'x86_64' : 'x86_64',
+ 'em64t' : 'x86_64'}
+ try:
+ abi = valid_abis[abi]
+ except KeyError:
+ raise SCons.Errors.UserError("Intel compiler: Invalid ABI %s, valid values are %s"% \
+ (abi, valid_abis.keys()))
+ return abi
+
+def vercmp(a, b):
+ """Compare strings as floats,
+ but Intel changed Linux naming convention at 9.0"""
+ return cmp(linux_ver_normalize(b), linux_ver_normalize(a))
+
+def get_version_from_list(v, vlist):
+ """See if we can match v (string) in vlist (list of strings)
+ Linux has to match in a fuzzy way."""
+ if is_windows:
+ # Simple case, just find it in the list
+ if v in vlist: return v
+ else: return None
+ else:
+ # Fuzzy match: normalize version number first, but still return
+ # original non-normalized form.
+ fuzz = 0.001
+ for vi in vlist:
+ if math.fabs(linux_ver_normalize(vi) - linux_ver_normalize(v)) < fuzz:
+ return vi
+ # Not found
+ return None
def get_intel_registry_value(valuename, version=None, abi=None):
"""
- Return a value from the Intel compiler registry tree. (Win32 only)
+ Return a value from the Intel compiler registry tree. (Windows only)
"""
-
# Open the key:
- K = 'Software\\Intel\\Compilers\\C++\\' + version + '\\'+abi.upper()
+ if is_win64:
+ K = 'Software\\Wow6432Node\\Intel\\Compilers\\C++\\' + version + '\\'+abi.upper()
+ else:
+ K = 'Software\\Intel\\Compilers\\C++\\' + version + '\\'+abi.upper()
try:
k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, K)
except SCons.Util.RegError:
- raise SCons.Errors.InternalError, \
- "%s was not found in the registry, for Intel compiler version %s"%(K, version)
+ raise MissingRegistryError("%s was not found in the registry, for Intel compiler version %s, abi='%s'"%(K, version,abi))
# Get the value:
try:
v = SCons.Util.RegQueryValueEx(k, valuename)[0]
return v # or v.encode('iso-8859-1', 'replace') to remove unicode?
except SCons.Util.RegError:
- raise SCons.Errors.InternalError, \
- "%s\\%s was not found in the registry."%(K, value)
+ raise MissingRegistryError("%s\\%s was not found in the registry."%(K, valuename))
def get_all_compiler_versions():
- """Returns a sorted list of strings, like "70" or "80"
+ """Returns a sorted list of strings, like "70" or "80" or "9.0"
with most recent compiler version first.
"""
versions=[]
- if is_win32:
- keyname = 'Software\\Intel\\Compilers\\C++'
- k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
- keyname)
+ if is_windows:
+ if is_win64:
+ keyname = 'Software\\WoW6432Node\\Intel\\Compilers\\C++'
+ else:
+ keyname = 'Software\\Intel\\Compilers\\C++'
+ try:
+ k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
+ keyname)
+ except WindowsError:
+ return []
i = 0
versions = []
try:
while i < 100:
subkey = SCons.Util.RegEnumKey(k, i) # raises EnvironmentError
- versions.append(subkey)
+ # Check that this refers to an existing dir.
+ # This is not 100% perfect but should catch common
+ # installation issues like when the compiler was installed
+ # and then the install directory deleted or moved (rather
+ # than uninstalling properly), so the registry values
+ # are still there.
+ ok = False
+ for try_abi in ('IA32', 'IA32e', 'IA64', 'EM64T'):
+ try:
+ d = get_intel_registry_value('ProductDir', subkey, try_abi)
+ except MissingRegistryError:
+ continue # not found in reg, keep going
+ if os.path.exists(d): ok = True
+ if ok:
+ versions.append(subkey)
+ else:
+ try:
+ # Registry points to nonexistent dir. Ignore this
+ # version.
+ value = get_intel_registry_value('ProductDir', subkey, 'IA32')
+ except MissingRegistryError, e:
+
+ # Registry key is left dangling (potentially
+ # after uninstalling).
+
+ print \
+ "scons: *** Ignoring the registry key for the Intel compiler version %s.\n" \
+ "scons: *** It seems that the compiler was uninstalled and that the registry\n" \
+ "scons: *** was not cleaned up properly.\n" % subkey
+ else:
+ print "scons: *** Ignoring "+str(value)
+
i = i + 1
except EnvironmentError:
# no more subkeys
pass
elif is_linux:
- # Typical dir here is /opt/intel_cc_80.
for d in glob.glob('/opt/intel_cc_*'):
- versions.append(re.search(r'cc_(.*)$', d).group(1))
- versions.sort(fltcmp)
- return versions
-
-def get_intel_compiler_top(version=None, abi=None):
+ # Typical dir here is /opt/intel_cc_80.
+ m = re.search(r'cc_(.*)$', d)
+ if m:
+ versions.append(m.group(1))
+ for d in glob.glob('/opt/intel/cc*/*'):
+ # Typical dir here is /opt/intel/cc/9.0 for IA32,
+ # /opt/intel/cce/9.0 for EMT64 (AMD64)
+ m = re.search(r'([0-9.]+)$', d)
+ if m:
+ versions.append(m.group(1))
+ elif is_mac:
+ for d in glob.glob('/opt/intel/cc*/*'):
+ # Typical dir here is /opt/intel/cc/9.0 for IA32,
+ # /opt/intel/cce/9.0 for EMT64 (AMD64)
+ m = re.search(r'([0-9.]+)$', d)
+ if m:
+ versions.append(m.group(1))
+ return sorted(uniquify(versions)) # remove dups
+
+def get_intel_compiler_top(version, abi):
"""
Return the main path to the top-level dir of the Intel compiler,
- using the given version or latest if None.
+ using the given version.
The compiler will be in <top>/bin/icl.exe (icc on linux),
the include dir is <top>/include, etc.
"""
- if is_win32:
+ if is_windows:
if not SCons.Util.can_read_reg:
- raise SCons.Errors.InternalError, "No Windows registry module was found"
+ raise NoRegistryModuleError("No Windows registry module was found")
top = get_intel_registry_value('ProductDir', version, abi)
-
- if not os.path.exists(os.path.join(top, "Bin", "icl.exe")):
- raise SCons.Errors.InternalError, \
- "Can't find Intel compiler in %s"%(top)
- elif is_linux:
- top = '/opt/intel_cc_%s'%version
- if not os.path.exists(os.path.join(top, "bin", "icc")):
- raise SCons.Errors.InternalError, \
- "Can't find version %s Intel compiler in %s"%(version,top)
+ # pre-11, icl was in Bin. 11 and later, it's in Bin/<abi> apparently.
+ if not os.path.exists(os.path.join(top, "Bin", "icl.exe")) \
+ and not os.path.exists(os.path.join(top, "Bin", abi, "icl.exe")):
+ raise MissingDirError("Can't find Intel compiler in %s"%(top))
+ elif is_mac or is_linux:
+ # first dir is new (>=9.0) style, second is old (8.0) style.
+ dirs=('/opt/intel/cc/%s', '/opt/intel_cc_%s')
+ if abi == 'x86_64':
+ dirs=('/opt/intel/cce/%s',) # 'e' stands for 'em64t', aka x86_64 aka amd64
+ top=None
+ for d in dirs:
+ if os.path.exists(os.path.join(d%version, "bin", "icc")):
+ top = d%version
+ break
+ if not top:
+ raise MissingDirError("Can't find version %s Intel compiler in %s (abi='%s')"%(version,top, abi))
return top
-def generate(env, version=None, abi=None, topdir=None, verbose=1):
+def generate(env, version=None, abi=None, topdir=None, verbose=0):
"""Add Builders and construction variables for Intel C/C++ compiler
to an Environment.
args:
If topdir is used, version and abi are ignored.
verbose: (int) if >0, prints compiler version used.
"""
- if not (is_linux or is_win32):
+ if not (is_mac or is_linux or is_windows):
# can't handle this platform
return
- if is_win32:
+ if is_windows:
SCons.Tool.msvc.generate(env)
elif is_linux:
SCons.Tool.gcc.generate(env)
-
+ elif is_mac:
+ SCons.Tool.gcc.generate(env)
+
# if version is unspecified, use latest
vlist = get_all_compiler_versions()
if not version:
if vlist:
version = vlist[0]
else:
- if version not in vlist:
- raise SCons.Errors.UserError, \
- "Invalid Intel compiler version %s: "%version + \
- "installed versions are %s"%(', '.join(vlist))
-
- # if abi is unspecified, use ia32 (ia64 is another possibility)
+ # User may have specified '90' but we need to get actual dirname '9.0'.
+ # get_version_from_list does that mapping.
+ v = get_version_from_list(version, vlist)
+ if not v:
+ raise SCons.Errors.UserError("Invalid Intel compiler version %s: "%version + \
+ "installed versions are %s"%(', '.join(vlist)))
+ version = v
+
+ # if abi is unspecified, use ia32
+ # alternatives are ia64 for Itanium, or amd64 or em64t or x86_64 (all synonyms here)
+ abi = check_abi(abi)
if abi is None:
- abi = "ia32" # or ia64, I believe
-
- if topdir is None:
+ if is_mac or is_linux:
+ # Check if we are on 64-bit linux, default to 64 then.
+ uname_m = os.uname()[4]
+ if uname_m == 'x86_64':
+ abi = 'x86_64'
+ else:
+ abi = 'ia32'
+ else:
+ if is_win64:
+ abi = 'em64t'
+ else:
+ abi = 'ia32'
+
+ if version and not topdir:
try:
topdir = get_intel_compiler_top(version, abi)
- except (SCons.Util.RegError, SCons.Errors.InternalError):
+ except (SCons.Util.RegError, IntelCError):
topdir = None
- if topdir:
+ if not topdir:
+ # Normally this is an error, but it might not be if the compiler is
+ # on $PATH and the user is importing their env.
+ class ICLTopDirWarning(SCons.Warnings.Warning):
+ pass
+ if (is_mac or is_linux) and not env.Detect('icc') or \
+ is_windows and not env.Detect('icl'):
+
+ SCons.Warnings.enableWarningClass(ICLTopDirWarning)
+ SCons.Warnings.warn(ICLTopDirWarning,
+ "Failed to find Intel compiler for version='%s', abi='%s'"%
+ (str(version), str(abi)))
+ else:
+ # should be cleaned up to say what this other version is
+ # since in this case we have some other Intel compiler installed
+ SCons.Warnings.enableWarningClass(ICLTopDirWarning)
+ SCons.Warnings.warn(ICLTopDirWarning,
+ "Can't find Intel compiler top dir for version='%s', abi='%s'"%
+ (str(version), str(abi)))
+ if topdir:
if verbose:
- print "Intel C compiler: using version %s, abi %s, in '%s'"%(version,abi,topdir)
+ print "Intel C compiler: using version %s (%g), abi %s, in '%s'"%\
+ (repr(version), linux_ver_normalize(version),abi,topdir)
+ if is_linux:
+ # Show the actual compiler version by running the compiler.
+ os.system('%s/bin/icc --version'%topdir)
+ if is_mac:
+ # Show the actual compiler version by running the compiler.
+ os.system('%s/bin/icc --version'%topdir)
env['INTEL_C_COMPILER_TOP'] = topdir
if is_linux:
'LIB' : 'lib',
'PATH' : 'bin',
'LD_LIBRARY_PATH' : 'lib'}
- for p in paths:
+ for p in paths.keys():
env.PrependENVPath(p, os.path.join(topdir, paths[p]))
- if is_win32:
+ if is_mac:
+ paths={'INCLUDE' : 'include',
+ 'LIB' : 'lib',
+ 'PATH' : 'bin',
+ 'LD_LIBRARY_PATH' : 'lib'}
+ for p in paths.keys():
+ env.PrependENVPath(p, os.path.join(topdir, paths[p]))
+ if is_windows:
# env key reg valname default subdir of top
paths=(('INCLUDE', 'IncludeDir', 'Include'),
('LIB' , 'LibDir', 'Lib'),
('PATH' , 'BinDir', 'Bin'))
+ # We are supposed to ignore version if topdir is set, so set
+ # it to the emptry string if it's not already set.
+ if version is None:
+ version = ''
# Each path has a registry entry, use that or default to subdir
for p in paths:
try:
path=get_intel_registry_value(p[1], version, abi)
- env.PrependENVPath(p[0], ';'.split(path))
- # print "ICL %s: %s, final=%s"%(p[0], path, str(env['ENV'][p[0]]))
- except:
+ # These paths may have $(ICInstallDir)
+ # which needs to be substituted with the topdir.
+ path=path.replace('$(ICInstallDir)', topdir + os.sep)
+ except IntelCError:
+ # Couldn't get it from registry: use default subdir of topdir
env.PrependENVPath(p[0], os.path.join(topdir, p[2]))
+ else:
+ env.PrependENVPath(p[0], path.split(os.pathsep))
+ # print "ICL %s: %s, final=%s"%(p[0], path, str(env['ENV'][p[0]]))
- if is_win32:
+ if is_windows:
env['CC'] = 'icl'
env['CXX'] = 'icl'
env['LINK'] = 'xilink'
else:
env['CC'] = 'icc'
env['CXX'] = 'icpc'
- env['LINK'] = '$CC'
-
- if is_win32:
+ # Don't reset LINK here;
+ # use smart_link which should already be here from link.py.
+ #env['LINK'] = '$CC'
+ env['AR'] = 'xiar'
+ env['LD'] = 'xild' # not used by default
+
+ # This is not the exact (detailed) compiler version,
+ # just the major version as determined above or specified
+ # by the user. It is a float like 80 or 90, in normalized form for Linux
+ # (i.e. even for Linux 9.0 compiler, still returns 90 rather than 9.0)
+ if version:
+ env['INTEL_C_COMPILER_VERSION']=linux_ver_normalize(version)
+
+ if is_windows:
# Look for license file dir
# in system environment, registry, and default location.
envlicdir = os.environ.get("INTEL_LICENSE_FILE", '')
licdir = None
for ld in [envlicdir, reglicdir]:
- if ld and os.path.exists(ld):
+ # If the string contains an '@', then assume it's a network
+ # license (port@system) and good by definition.
+ if ld and (ld.find('@') != -1 or os.path.exists(ld)):
licdir = ld
break
if not licdir:
env['ENV']['INTEL_LICENSE_FILE'] = licdir
def exists(env):
- if not (is_linux or is_win32):
+ if not (is_mac or is_linux or is_windows):
# can't handle this platform
return 0
try:
- top = get_intel_compiler_top()
- except (SCons.Util.RegError, SCons.Errors.InternalError):
- top = None
- if not top:
+ versions = get_all_compiler_versions()
+ except (SCons.Util.RegError, IntelCError):
+ versions = None
+ detected = versions is not None and len(versions) > 0
+ if not detected:
# try env.Detect, maybe that will work
- if is_win32:
+ if is_windows:
return env.Detect('icl')
elif is_linux:
return env.Detect('icc')
- return top is not None
+ elif is_mac:
+ return env.Detect('icc')
+ return detected
# end of file
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4: