Repository: numpy/numpy

Issue:
numpy 1.13.0 doesn't build with Intel compilers
I'm running into the problem below when trying to build `numpy` 1.13.0 with Intel compilers; building earlier numpy versions (1.12.1, 1.11.1, 1.10.4, ...) with this approach works fine.

```
$ python setup.py build --compiler=intel --fcompiler=intelem
building library "npymath" sources
Found executable /path/to/icc
Could not locate executable ecc
Traceback (most recent call last):
  File "setup.py", line 392, in <module>
    setup_package()
  File "setup.py", line 384, in setup_package
    setup(**metadata)
  File "/tmp/vsc40023/easybuild_build/numpy/1.13.0/intel-2017a-Python-2.7.13/numpy-1.13.0/numpy/distutils/core.py", line 169, in setup
    return old_setup(**new_attr)
  File "/user/home/gent/vsc400/vsc40023/eb_phanpyscratch/CO7/haswell-ib/software/Python/2.7.13-intel-2017a/lib/python2.7/distutils/core.py", line 151, in setup
    dist.run_commands()
  File "/user/home/gent/vsc400/vsc40023/eb_phanpyscratch/CO7/haswell-ib/software/Python/2.7.13-intel-2017a/lib/python2.7/distutils/dist.py", line 953, in run_commands
    self.run_command(cmd)
  File "/user/home/gent/vsc400/vsc40023/eb_phanpyscratch/CO7/haswell-ib/software/Python/2.7.13-intel-2017a/lib/python2.7/distutils/dist.py", line 972, in run_command
    cmd_obj.run()
  File "/tmp/vsc40023/easybuild_build/numpy/1.13.0/intel-2017a-Python-2.7.13/numpy-1.13.0/numpy/distutils/command/build.py", line 47, in run
    old_build.run(self)
  File "/user/home/gent/vsc400/vsc40023/eb_phanpyscratch/CO7/haswell-ib/software/Python/2.7.13-intel-2017a/lib/python2.7/distutils/command/build.py", line 127, in run
    self.run_command(cmd_name)
  File "/user/home/gent/vsc400/vsc40023/eb_phanpyscratch/CO7/haswell-ib/software/Python/2.7.13-intel-2017a/lib/python2.7/distutils/cmd.py", line 326, in run_command
    self.distribution.run_command(command)
  File "/user/home/gent/vsc400/vsc40023/eb_phanpyscratch/CO7/haswell-ib/software/Python/2.7.13-intel-2017a/lib/python2.7/distutils/dist.py", line 972, in run_command
    cmd_obj.run()
  File "/tmp/vsc40023/easybuild_build/numpy/1.13.0/intel-2017a-Python-2.7.13/numpy-1.13.0/numpy/distutils/command/build_src.py", line 148, in run
    self.build_sources()
  File "/tmp/vsc40023/easybuild_build/numpy/1.13.0/intel-2017a-Python-2.7.13/numpy-1.13.0/numpy/distutils/command/build_src.py", line 159, in build_sources
    self.build_library_sources(*libname_info)
  File "/tmp/vsc40023/easybuild_build/numpy/1.13.0/intel-2017a-Python-2.7.13/numpy-1.13.0/numpy/distutils/command/build_src.py", line 294, in build_library_sources
    sources = self.generate_sources(sources, (lib_name, build_info))
  File "/tmp/vsc40023/easybuild_build/numpy/1.13.0/intel-2017a-Python-2.7.13/numpy-1.13.0/numpy/distutils/command/build_src.py", line 377, in generate_sources
    source = func(extension, build_dir)
  File "numpy/core/setup.py", line 672, in get_mathlib_info
    st = config_cmd.try_link('int main(void) { return 0;}')
  File "/user/home/gent/vsc400/vsc40023/eb_phanpyscratch/CO7/haswell-ib/software/Python/2.7.13-intel-2017a/lib/python2.7/distutils/command/config.py", line 248, in try_link
    self._check_compiler()
  File "/tmp/vsc40023/easybuild_build/numpy/1.13.0/intel-2017a-Python-2.7.13/numpy-1.13.0/numpy/distutils/command/config.py", line 39, in _check_compiler
    old_config._check_compiler(self)
  File "/user/home/gent/vsc400/vsc40023/eb_phanpyscratch/CO7/haswell-ib/software/Python/2.7.13-intel-2017a/lib/python2.7/distutils/command/config.py", line 102, in _check_compiler
    dry_run=self.dry_run, force=1)
  File "/tmp/vsc40023/easybuild_build/numpy/1.13.0/intel-2017a-Python-2.7.13/numpy-1.13.0/numpy/distutils/ccompiler.py", line 713, in new_compiler
    compiler = klass(None, dry_run, force)
  File "/tmp/vsc40023/easybuild_build/numpy/1.13.0/intel-2017a-Python-2.7.13/numpy-1.13.0/numpy/distutils/intelccompiler.py", line 21, in __init__
    v = self.get_version()
  File "/tmp/vsc40023/easybuild_build/numpy/1.13.0/intel-2017a-Python-2.7.13/numpy-1.13.0/numpy/distutils/ccompiler.py", line 582, in CCompiler_get_version
    self.find_executables()
AttributeError: IntelCCompiler instance has no attribute 'find_executables'
```

The `Could not locate executable ecc` seems to be a hint, since this message doesn't occur with older numpy versions where building like this does work:

```
...
building library "npymath" sources
Found executable /path/to/icc
customize IntelEM64TFCompiler
Found executable /path/to/ifort
customize IntelEM64TFCompiler using config
C compiler: icc -fPIC -fp-model strict -O3 -fomit-frame-pointer -openmp
...
```

Why is `numpy` looking for `ecc` when it found `icc`, and not continuing to go and find `ifort` like it did before?

A similar problem was reported by @Eric89GXL in #9101, but there the problem was that `icc` could not be found, that's clearly not the problem here.

Seeing this with Python 2.7.13, Intel compilers 2017.1.132, Intel MKL 2017.1.132.


Discussion:
I get the same error. Commenting out the line `self.find_executables()` works as a work-around. This method seems to be undefined for CCompiler/IntelCCompiler.
#8961 is the only change from 1.12.1 and I don't see how that would be related to this.
#8961 has added exactly the line causing this (`v = self.get_version()`).
So an alternate fix to #8961 suggested in #8941 was `-fopenmp`, which would not be version dependent. Might want to try that.
Hi everybody,
In regard to this change, in numpy 1.13.0 I've  found using f2py and intel compilers I got the following compilation error:
`mpopt = 'openmp' if v and int(v.split('.')[0]) < 15 else 'qopenmp'
AttributeError: LooseVersion instance has no attribute 'split'`
which can be solved changing the above line by:
`mpopt = 'openmp' if v and int(v.version[0]) < 15 else 'qopenmp'`

Hope this info can be useful,
ACM
Geez, version is a `LooseVersion` instance. Seems kinda useless given the lack of documentation of the class and the variations of version in the wild. That could be fixed by calling `str` on it I suppose.

So there are two problems:
* `LooseVersion` is  not a string
* missing `find_executables`, which only seems to be defined for fortran compilers
@boegel Looks like "intel" is so generic that the Itanium platform is also being searched, weird.

EDIT: I don't think the ecc message is relevant here.

Resolving patch:
diff --git a/numpy/distutils/ccompiler.py b/numpy/distutils/ccompiler.py
--- a/numpy/distutils/ccompiler.py
+++ b/numpy/distutils/ccompiler.py
@@ -80,6 +80,7 @@ def _needs_build(obj, cc_args, extra_postargs, pp_opts):
 
     return False
 
+
 def replace_method(klass, method_name, func):
     if sys.version_info[0] < 3:
         m = types.MethodType(func, None, klass)
@@ -88,6 +89,25 @@ def replace_method(klass, method_name, func):
         m = lambda self, *args, **kw: func(self, *args, **kw)
     setattr(klass, method_name, m)
 
+
+######################################################################
+## Method that subclasses may redefine. But don't call this method,
+## it i private to CCompiler class and may return unexpected
+## results if used elsewhere. So, you have been warned..
+
+def CCompiler_find_executables(self):
+    """
+    Does nothing here, but is called by the get_version method and can be
+    overridden by subclasses. In particular it is redefined in the `FCompiler`
+    class where more documentation can be found.
+
+    """
+    pass
+
+
+replace_method(CCompiler, 'find_executables', CCompiler_find_executables)
+
+
 # Using customized CCompiler.spawn.
 def CCompiler_spawn(self, cmd, display=None):
     """
diff --git a/numpy/distutils/fcompiler/intel.py b/numpy/distutils/fcompiler/intel.py
--- a/numpy/distutils/fcompiler/intel.py
+++ b/numpy/distutils/fcompiler/intel.py
@@ -57,7 +57,7 @@ def get_flags(self):
 
     def get_flags_opt(self):  # Scipy test failures with -O2
         v = self.get_version()
-        mpopt = 'openmp' if v and int(v.split('.')[0]) < 15 else 'qopenmp'
+        mpopt = 'openmp' if v and v < '15' else 'qopenmp'
         return ['-xhost -fp-model strict -O1 -{}'.format(mpopt)]
 
     def get_flags_arch(self):
@@ -123,7 +123,7 @@ def get_flags(self):
 
     def get_flags_opt(self):  # Scipy test failures with -O2
         v = self.get_version()
-        mpopt = 'openmp' if v and int(v.split('.')[0]) < 15 else 'qopenmp'
+        mpopt = 'openmp' if v and v < '15' else 'qopenmp'
         return ['-fp-model strict -O1 -{}'.format(mpopt)]
 
     def get_flags_arch(self):
diff --git a/numpy/distutils/intelccompiler.py b/numpy/distutils/intelccompiler.py
--- a/numpy/distutils/intelccompiler.py
+++ b/numpy/distutils/intelccompiler.py
@@ -19,7 +19,7 @@ def __init__(self, verbose=0, dry_run=0, force=0):
         UnixCCompiler.__init__(self, verbose, dry_run, force)
 
         v = self.get_version()
-        mpopt = 'openmp' if v and int(v.split('.')[0]) < 15 else 'qopenmp'
+        mpopt = 'openmp' if v and v < '15' else 'qopenmp'
         self.cc_exe = ('icc -fPIC -fp-model strict -O3 '
                        '-fomit-frame-pointer -{}').format(mpopt)
         compiler = self.cc_exe
@@ -59,7 +59,7 @@ def __init__(self, verbose=0, dry_run=0, force=0):
         UnixCCompiler.__init__(self, verbose, dry_run, force)
 
         v = self.get_version()
-        mpopt = 'openmp' if v and int(v.split('.')[0]) < 15 else 'qopenmp'
+        mpopt = 'openmp' if v and v < '15' else 'qopenmp'
         self.cc_exe = ('icc -m64 -fPIC -fp-model strict -O3 '
                        '-fomit-frame-pointer -{}').format(mpopt)
         compiler = self.cc_exe


Test patch: