Repository: numpy/numpy

Issue:
Support for the NVIDIA HPC SDK fortran compiler
<!-- Please describe the issue in detail here, and fill in the fields below -->
PGI Compilers & Tools are now packaged in the NVIDIA HPC SDK (https://www.pgroup.com/index.htm).
This implies a few changes for the detection of the fortran compiler.
Our particular use case uses f2py to wrap fortran code.

**nv**fortran is the executable for compiling fortran code, **pg**fortran is still available as an alias for nvfortran.
The compiler detection process parses the output of the `--version` flag.
Here are the outputs of the `--version` flag for pgfortran 20.04 (previous packaging), pgfortran 20.07 (new packaing alias) and nvfortran 20.07 (new packagin):

```shell
$ pgfortran --version

pgfortran 20.4-0 linuxpower target on Linuxpower
PGI Compilers and Tools
Copyright (c) 2020, NVIDIA CORPORATION.  All rights reserved.
```
```shell
$ pgfortran --version

pgfortran (aka nvfortran) 20.7-0 linuxpower target on Linuxpower
PGI Compilers and Tools
Copyright (c) 2020, NVIDIA CORPORATION.  All rights reserved.
```
```shell
$ nvfortran --version

nvfortran 20.7-0 linuxpower target on Linuxpower
NVIDIA Compilers and Tools
Copyright (c) 2020, NVIDIA CORPORATION.  All rights reserved.
```

Notice :
- the `(aka nvfortran)` part (2nd output) breaks the version detection if the pgfortran executable is used.
- **nv**fortran (3rd output) is not matched during version detection if the nvfortran executable is used.
<!-- Remove these sections for a feature request -->


### Reproducing code example:
```fortran
! file: helloworld.f90

module m_hello_world
contains
subroutine sayhello()
  implicit none
  print *, 'Hello, World!'
end subroutine sayhello

end module m_hello_world
```
### Compiled with:
In this exemple the nvfortran executable is used
```shell
$ F77=nvfortran F90=nvfortran CC=gcc CPATH= f2py --verbose -c --fcompiler=pg helloworld.f90 -m helloworld
```

<!-- A short code example that reproduces the problem/missing feature. It should be
self-contained, i.e., possible to run as-is via 'python myproblem.py' -->


### Error message:
This is the error message with the nvfortran executable.
```
customize PGroupFCompiler
find_executable('nvfortran')
Found executable ***/nvhpc/20.07/Linux_ppc64le/20.7/compilers/bin/nvfortran
Traceback (most recent call last):
  File "***/python_venv/reproducer_venv/bin/f2py", line 11, in <module>
    load_entry_point('numpy==1.19.2', 'console_scripts', 'f2py')()
  File "***/python_venv/reproducer_venv/lib/python3.7/site-packages/numpy-1.19.2-py3.7-linux-ppc64le.egg/numpy/f2py/f2py2e.py", line 692, in main
    run_compile()
  File "***/python_venv/reproducer_venv/lib/python3.7/site-packages/numpy-1.19.2-py3.7-linux-ppc64le.egg/numpy/f2py/f2py2e.py", line 659, in run_compile
    setup(ext_modules=[ext])
  File "***/python_venv/reproducer_venv/lib/python3.7/site-packages/numpy-1.19.2-py3.7-linux-ppc64le.egg/numpy/distutils/core.py", line 169, in setup
    return old_setup(**new_attr)
  File "***/anaconda3/2019.03/lib/python3.7/distutils/core.py", line 148, in setup
    dist.run_commands()
  File "***/anaconda3/2019.03/lib/python3.7/distutils/dist.py", line 966, in run_commands
    self.run_command(cmd)
  File "***/anaconda3/2019.03/lib/python3.7/distutils/dist.py", line 985, in run_command
    cmd_obj.run()
  File "***/python_venv/reproducer_venv/lib/python3.7/site-packages/numpy-1.19.2-py3.7-linux-ppc64le.egg/numpy/distutils/command/build.py", line 40, in run
    old_build.run(self)
  File "***/anaconda3/2019.03/lib/python3.7/distutils/command/build.py", line 135, in run
    self.run_command(cmd_name)
  File "***/anaconda3/2019.03/lib/python3.7/distutils/cmd.py", line 313, in run_command
    self.distribution.run_command(command)
  File "***/anaconda3/2019.03/lib/python3.7/distutils/dist.py", line 985, in run_command
    cmd_obj.run()
  File "***/python_venv/reproducer_venv/lib/python3.7/site-packages/numpy-1.19.2-py3.7-linux-ppc64le.egg/numpy/distutils/command/build_ext.py", line 238, in run
    if fcompiler and fcompiler.get_version():
  File "***/python_venv/reproducer_venv/lib/python3.7/site-packages/numpy-1.19.2-py3.7-linux-ppc64le.egg/numpy/distutils/fcompiler/__init__.py", line 428, in get_version
    raise CompilerNotFound()
numpy.distutils.fcompiler.CompilerNotFound
```
With the pgfortran executable the Traceback is identical.


### Workarround
This modification allows to match "**nv**fortran"  in the output of the `--version` flag.
```diff
diff --git a/numpy/distutils/fcompiler/pg.py b/numpy/distutils/fcompiler/pg.py
index 72442c4fe..306f7ef34 100644
--- a/numpy/distutils/fcompiler/pg.py
+++ b/numpy/distutils/fcompiler/pg.py
@@ -12,7 +12,7 @@ class PGroupFCompiler(FCompiler):

     compiler_type = 'pg'
     description = 'Portland Group Fortran Compiler'
-    version_pattern = r'\s*pg(f77|f90|hpf|fortran) (?P<version>[\d.-]+).*'
+    version_pattern = r'\s*(pg|nv)(f77|f90|hpf|fortran) (?P<version>[\d.-]+).*'

     if platform == 'darwin':
         executables = {
```

Handling the  `(aka nvfortran)` part for the pgfortran executable seems trickier.

<!-- If you are reporting a segfault please include a GDB traceback, which you
can generate by following
https://github.com/numpy/numpy/blob/master/doc/source/dev/development_environment.rst#debugging -->

<!-- Full error message, if any (starting from line Traceback: ...) -->

### Numpy/Python version information:
```shell
$ python --version
Python 3.7.3
```
```shell
$ pip show numpy
Name: numpy
Version: 1.19.2
Summary: NumPy is the fundamental package for array computing with Python.
Home-page: https://www.numpy.org
Author: Travis E. Oliphant et al.
Author-email: None
License: BSD
Location: ***/python_venv/reproducer_venv/lib/python3.7/site-packages/numpy-1.19.2-py3.7-linux-ppc64le.egg
Requires:
Required-by: f90wrap
```

<!-- Output from 'import sys, numpy; print(numpy.__version__, sys.version)' -->




Discussion:
Could you make a PR with this modification?

Resolving patch:
diff --git a/numpy/distutils/fcompiler/__init__.py b/numpy/distutils/fcompiler/__init__.py
--- a/numpy/distutils/fcompiler/__init__.py
+++ b/numpy/distutils/fcompiler/__init__.py
@@ -745,7 +745,7 @@ def wrap_unlinkable_objects(self, objects, output_dir, extra_dll_dir):
     ('win32', ('gnu', 'intelv', 'absoft', 'compaqv', 'intelev', 'gnu95', 'g95',
                'intelvem', 'intelem', 'flang')),
     ('cygwin.*', ('gnu', 'intelv', 'absoft', 'compaqv', 'intelev', 'gnu95', 'g95')),
-    ('linux.*', ('gnu95', 'intel', 'lahey', 'pg', 'absoft', 'nag', 'vast', 'compaq',
+    ('linux.*', ('gnu95', 'intel', 'lahey', 'pg', 'nv', 'absoft', 'nag', 'vast', 'compaq',
                  'intele', 'intelem', 'gnu', 'g95', 'pathf95', 'nagfor')),
     ('darwin.*', ('gnu95', 'nag', 'absoft', 'ibm', 'intel', 'gnu', 'g95', 'pg')),
     ('sunos.*', ('sun', 'gnu', 'gnu95', 'g95')),
diff --git a/numpy/distutils/fcompiler/nv.py b/numpy/distutils/fcompiler/nv.py
new file mode 100644
--- /dev/null
+++ b/numpy/distutils/fcompiler/nv.py
@@ -0,0 +1,55 @@
+import sys
+
+from numpy.distutils.fcompiler import FCompiler
+
+compilers = ['NVHPCFCompiler']
+
+class NVHPCFCompiler(FCompiler):
+    """ NVIDIA High Performance Computing (HPC) SDK Fortran Compiler
+   
+    https://developer.nvidia.com/hpc-sdk
+   
+    Since august 2020 the NVIDIA HPC SDK includes the compilers formerly known as The Portland Group compilers,
+    https://www.pgroup.com/index.htm.
+    See also `numpy.distutils.fcompiler.pg`.
+    """
+
+    compiler_type = 'nv'
+    description = 'NVIDIA HPC SDK'
+    version_pattern = r'\s*(nvfortran|(pg(f77|f90|fortran)) \(aka nvfortran\)) (?P<version>[\d.-]+).*'
+
+    executables = {
+        'version_cmd': ["<F90>", "-V"],
+        'compiler_f77': ["nvfortran"],
+        'compiler_fix': ["nvfortran", "-Mfixed"],
+        'compiler_f90': ["nvfortran"],
+        'linker_so': ["<F90>"],
+        'archiver': ["ar", "-cr"],
+        'ranlib': ["ranlib"]
+    }
+    pic_flags = ['-fpic']
+
+    module_dir_switch = '-module '
+    module_include_switch = '-I'
+
+    def get_flags(self):
+        opt = ['-Minform=inform', '-Mnosecond_underscore']
+        return self.pic_flags + opt
+
+    def get_flags_opt(self):
+        return ['-fast']
+
+    def get_flags_debug(self):
+        return ['-g']
+
+    def get_flags_linker_so(self):
+        return ["-shared", '-fpic']
+
+    def runtime_library_dir_option(self, dir):
+        return '-R%s' % dir
+
+if __name__ == '__main__':
+    from distutils import log
+    log.set_verbosity(2)
+    from numpy.distutils import customized_fcompiler
+    print(customized_fcompiler(compiler='nv').get_version())


Test patch:
diff --git a/numpy/tests/test_public_api.py b/numpy/tests/test_public_api.py
--- a/numpy/tests/test_public_api.py
+++ b/numpy/tests/test_public_api.py
@@ -246,6 +246,7 @@ def test_NPY_NO_EXPORT():
     "distutils.fcompiler.none",
     "distutils.fcompiler.pathf95",
     "distutils.fcompiler.pg",
+    "distutils.fcompiler.nv",
     "distutils.fcompiler.sun",
     "distutils.fcompiler.vast",
     "distutils.from_template",