"""OpenMP wrapper using a libgomp dynamically loaded library."""

from ctypes.util import find_library
from subprocess import check_output, CalledProcessError
from numpy.distutils.misc_util import msvc_runtime_major
import ctypes
import os
import sys

try:
    # there may be an environ modification when loading config
    from pythran.config import compiler
except ImportError:
    def compiler():
        return os.environ.get('CXX', 'c++')
cxx = compiler()


class OpenMP(object):

    """
    Internal representation of the OpenMP module.

    Custom class is used to dynamically add omp runtime function
    to this library when function is called.
    """

    def __init__(self):
        ver = msvc_runtime_major()
        if ver is None:
            self.init_not_msvc()
        else:
            self.init_msvc(ver)

    def init_msvc(self, ver):
        vcomp_path = find_library('vcomp%d.dll' % ver)
        if not vcomp_path:
            raise ImportError("I can't find a shared library for vcomp.")
        else:
            # Load the library (shouldn't fail with an absolute path right?)
            self.libomp = ctypes.CDLL(vcomp_path)
            self.version = 20

    def init_not_msvc(self):
        """ Find OpenMP library and try to load if using ctype interface. """
        # find_library() does not search automatically LD_LIBRARY_PATH
        paths = os.environ.get('LD_LIBRARY_PATH', '').split(':')
        for gomp in ('libgomp.so', 'libgomp.dylib'):
            if cxx is None:
                continue
            cmd = [cxx, '-print-file-name=' + gomp]
            # the subprocess can fail in various ways
            # in that case just give up that path
            try:
                path = os.path.dirname(check_output(cmd).strip())
                if path:
                    paths.append(path)
            except (OSError, CalledProcessError):
                pass

        # Try to load find libgomp shared library using loader search dirs
        libgomp_path = find_library("gomp")

        # Try to use custom paths if lookup failed
        for path in paths:
            if libgomp_path:
                break
            path = path.strip()
            if os.path.isdir(path):
                libgomp_path = find_library(os.path.join(str(path), "libgomp"))

        if not libgomp_path:
            raise ImportError("I can't find a shared library for libgomp,"
                              " you may need to install it or adjust the "
                              "LD_LIBRARY_PATH environment variable.")
        else:
            # Load the library (shouldn't fail with an absolute path right?)
            self.libomp = ctypes.CDLL(libgomp_path)
            self.version = 45

    def __getattr__(self, name):
        """
        Get correct function name from libgomp ready to be use.

        __getattr__ is call only `name != libomp` as libomp is a real
        attribute.
        """
        if name == 'VERSION':
            return self.version
        return getattr(self.libomp, 'omp_' + name)

# see http://mail.python.org/pipermail/python-ideas/2012-May/014969.html
sys.modules[__name__] = OpenMP()


@@ -190,16 +190,22 @@
  import 
+(%0A    
 msvc_run
@@ -214,16 +214,44 @@
 me_major
+, get_shared_lib_extension%0A)
 %0Aimport 
@@ -1212,16 +1212,963 @@
 n = 20%0A%0A
+    def get_libomp_names(self):%0A        %22%22%22Return list of OpenMP libraries to try, based on platform and%0A        compiler detected.%22%22%22%0A        if cxx is None:%0A            # Can't tell what compiler we're using, guessing we need libgomp%0A            names %5B'libgomp'%5D%0A        else:%0A            cmd = %5Bcxx, '--version'%5D%0A            try:%0A                version_str = os.path.dirname(check_output(cmd).decode().strip())%0A            except (OSError, CalledProcessError):%0A                version_str = ''%0A%0A            if 'clang' in version_str:%0A                names = %5B'libomp', 'libiomp5', 'libgomp'%5D%0A            elif version_str.startswith('Intel'):%0A                names = %5B'libiomp5'%5D%0A            else:%0A                # Too many GCC flavors and version strings, make this the default%0A                # rather than try to detect if it's GCC%0A                names = %5B'libgomp'%5D%0A%0A        return %5Bname + get_shared_lib_extension() for name in names%5D%0A%0A
     def 
@@ -2402,16 +2402,17 @@
 it(':')%0A
+%0A
         
@@ -2419,46 +2419,45 @@
 for 
-gomp in ('libgomp.so', '
+libomp_name in self.get_
 lib
-g
 omp
-.dylib'
+_names(
 ):%0A 
@@ -2473,33 +2473,186 @@
   if cxx is None
-:
+ or sys.platform == 'win32':%0A                # Note: Clang supports -print-file-name, but not yet for%0A                # clang-cl as of v12.0.0 (April '21)
 %0A               
@@ -2661,16 +2661,17 @@
 ontinue%0A
+%0A
         
@@ -2708,20 +2708,27 @@
 ame=' + 
-gomp
+libomp_name
 %5D%0A      
@@ -2774,30 +2774,16 @@
 ous ways
-%0A            #
  in that
@@ -2804,18 +2804,8 @@
 e up
- that path
 %0A   
@@ -2875,16 +2875,25 @@
 ut(cmd).
+decode().
 strip())

Improve OpenMP detection for different platforms and compilers