We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Compiler not found: /tmp/tmp bug


```
$ pip install numba
Collecting numba
  Downloading numba-0.53.1-cp39-cp39-manylinux2014_x86_64.whl (3.4 MB)
     |████████████████████████████████| 3.4 MB 1.2 MB/s 
Collecting numpy>=1.15
  Downloading numpy-1.21.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl (15.7 MB)
     |████████████████████████████████| 15.7 MB 1.1 MB/s 
Requirement already satisfied: setuptools in /usr/lib/python3/dist-packages (from numba) (52.0.0)
Collecting llvmlite<0.37,>=0.36.0rc1
  Downloading llvmlite-0.36.0-cp39-cp39-manylinux2010_x86_64.whl (25.3 MB)
     |████████████████████████████████| 25.3 MB 829 kB/s 
Installing collected packages: numpy, llvmlite, numba
  WARNING: The scripts f2py, f2py3 and f2py3.9 are installed in '/home/olaf/.local/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed llvmlite-0.36.0 numba-0.53.1 numpy-1.21.0

$ ./t.py 
          
$ ./t.py 

$ chmod 000 /tmp/tmp

$ ./t.py            
Traceback (most recent call last):
  File "/home/olaf/./t.py", line 5, in <module>
    cc = CC('interpolation')
  File "/home/olaf/.local/lib/python3.9/site-packages/numba/pycc/cc.py", line 65, in __init__
    self._toolchain = Toolchain()
  File "/home/olaf/.local/lib/python3.9/site-packages/numba/pycc/platform.py", line 78, in __init__
    self._raise_external_compiler_error()
  File "/home/olaf/.local/lib/python3.9/site-packages/numba/pycc/platform.py", line 121, in _raise_external_compiler_error
    raise RuntimeError(msg)
RuntimeError: Attempted to compile AOT function without the compiler used by `numpy.distutils` present. If using conda try:

#> conda install gcc_linux-64 gxx_linux-64

$ cat t.py 
#!/usr/bin/python3

from numba.pycc import CC

cc = CC('interpolation')

# cc.compile()

$ pip list|grep numba
numba            0.53.1
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `numba/pycc/platform.py`
Content:
```
1 from distutils.ccompiler import CCompiler, new_compiler
2 from distutils.command.build_ext import build_ext
3 from distutils.sysconfig import customize_compiler
4 from distutils import log
5 
6 import numpy.distutils.misc_util as np_misc
7 
8 import functools
9 import os
10 import subprocess
11 import sys
12 from tempfile import NamedTemporaryFile, mkdtemp, gettempdir
13 from contextlib import contextmanager
14 
15 _configs = {
16     # DLL suffix, Python C extension suffix
17     'win': ('.dll', '.pyd'),
18     'default': ('.so', '.so'),
19 }
20 
21 
22 def get_configs(arg):
23     return _configs.get(sys.platform[:3], _configs['default'])[arg]
24 
25 
26 find_shared_ending = functools.partial(get_configs, 0)
27 find_pyext_ending = functools.partial(get_configs, 1)
28 
29 @contextmanager
30 def _gentmpfile(suffix):
31     # windows locks the tempfile so use a tempdir + file, see
32     # https://github.com/numba/numba/issues/3304
33     try:
34         tmpdir = mkdtemp()
35         ntf = open(os.path.join(tmpdir, "temp%s" % suffix), 'wt')
36         yield ntf
37     finally:
38         try:
39             ntf.close()
40             os.remove(ntf)
41         except:
42             pass
43         else:
44             os.rmdir(tmpdir)
45 
46 def _check_external_compiler():
47     # see if the external compiler bound in numpy.distutil is present
48     # and working
49     compiler = new_compiler()
50     customize_compiler(compiler)
51     for suffix in ['.c', '.cxx']:
52         try:
53             with _gentmpfile(suffix) as ntf:
54                 simple_c = "int main(void) { return 0; }"
55                 ntf.write(simple_c)
56                 ntf.flush()
57                 ntf.close()
58                 # *output_dir* is set to avoid the compiler putting temp files
59                 # in the current directory.
60                 compiler.compile([ntf.name], output_dir=gettempdir())
61         except Exception: # likely CompileError or file system issue
62             return False
63     return True
64 
65 # boolean on whether the externally provided compiler is present and
66 # functioning correctly
67 _external_compiler_ok = _check_external_compiler()
68 
69 
70 class _DummyExtension(object):
71     libraries = []
72 
73 
74 class Toolchain(object):
75 
76     def __init__(self):
77         if not _external_compiler_ok:
78             self._raise_external_compiler_error()
79 
80         # Need to import it here since setuptools may monkeypatch it
81         from distutils.dist import Distribution
82         self._verbose = False
83         self._compiler = new_compiler()
84         customize_compiler(self._compiler)
85         self._build_ext = build_ext(Distribution())
86         self._build_ext.finalize_options()
87         self._py_lib_dirs = self._build_ext.library_dirs
88         self._py_include_dirs = self._build_ext.include_dirs
89         self._math_info = np_misc.get_info('npymath')
90 
91     @property
92     def verbose(self):
93         return self._verbose
94 
95     @verbose.setter
96     def verbose(self, value):
97         self._verbose = value
98         # DEBUG will let Numpy spew many messages, so stick to INFO
99         # to print commands executed by distutils
100         log.set_threshold(log.INFO if value else log.WARN)
101 
102     def _raise_external_compiler_error(self):
103         basemsg = ("Attempted to compile AOT function without the "
104                    "compiler used by `numpy.distutils` present.")
105         conda_msg = "If using conda try:\n\n#> conda install %s"
106         plt = sys.platform
107         if plt.startswith('linux'):
108             if sys.maxsize <= 2 ** 32:
109                 compilers = ['gcc_linux-32', 'gxx_linux-32']
110             else:
111                 compilers = ['gcc_linux-64', 'gxx_linux-64']
112             msg = "%s %s" % (basemsg, conda_msg % ' '.join(compilers))
113         elif plt.startswith('darwin'):
114             compilers = ['clang_osx-64', 'clangxx_osx-64']
115             msg = "%s %s" % (basemsg, conda_msg % ' '.join(compilers))
116         elif plt.startswith('win32'):
117             winmsg = "Cannot find suitable msvc."
118             msg = "%s %s" % (basemsg, winmsg)
119         else:
120             msg = "Unknown platform %s" % plt
121         raise RuntimeError(msg)
122 
123     def compile_objects(self, sources, output_dir,
124                         include_dirs=(), depends=(), macros=(),
125                         extra_cflags=None):
126         """
127         Compile the given source files into a separate object file each,
128         all beneath the *output_dir*.  A list of paths to object files
129         is returned.
130 
131         *macros* has the same format as in distutils: a list of 1- or 2-tuples.
132         If a 1-tuple (name,), the given name is considered undefined by
133         the C preprocessor.
134         If a 2-tuple (name, value), the given name is expanded into the
135         given value by the C preprocessor.
136         """
137         objects = self._compiler.compile(sources,
138                                          output_dir=output_dir,
139                                          include_dirs=include_dirs,
140                                          depends=depends,
141                                          macros=macros or [],
142                                          extra_preargs=extra_cflags)
143         return objects
144 
145     def link_shared(self, output, objects, libraries=(),
146                     library_dirs=(), export_symbols=(),
147                     extra_ldflags=None):
148         """
149         Create a shared library *output* linking the given *objects*
150         and *libraries* (all strings).
151         """
152         output_dir, output_filename = os.path.split(output)
153         self._compiler.link(CCompiler.SHARED_OBJECT, objects,
154                             output_filename, output_dir,
155                             libraries, library_dirs,
156                             export_symbols=export_symbols,
157                             extra_preargs=extra_ldflags)
158 
159     def get_python_libraries(self):
160         """
161         Get the library arguments necessary to link with Python.
162         """
163         libs = self._build_ext.get_libraries(_DummyExtension())
164         if sys.platform == 'win32':
165             # Under Windows, need to link explicitly against the CRT,
166             # as the MSVC compiler would implicitly do.
167             # (XXX msvcrtd in pydebug mode?)
168             libs = libs + ['msvcrt']
169         return libs + self._math_info['libraries']
170 
171     def get_python_library_dirs(self):
172         """
173         Get the library directories necessary to link with Python.
174         """
175         return list(self._py_lib_dirs) + self._math_info['library_dirs']
176 
177     def get_python_include_dirs(self):
178         """
179         Get the include directories necessary to compile against the Python
180         and Numpy C APIs.
181         """
182         return list(self._py_include_dirs) + self._math_info['include_dirs']
183 
184     def get_ext_filename(self, ext_name):
185         """
186         Given a C extension's module name, return its intended filename.
187         """
188         return self._build_ext.get_ext_filename(ext_name)
189 
190 
191 #
192 # Patch Numpy's exec_command() to avoid random crashes on Windows in test_pycc
193 # see https://github.com/numpy/numpy/pull/7614
194 # and https://github.com/numpy/numpy/pull/7862
195 #
196 
197 def _patch_exec_command():
198     # Patch the internal worker _exec_command()
199     import numpy.distutils.exec_command as mod
200     orig_exec_command = mod._exec_command
201     mod._exec_command = _exec_command
202 
203 
204 def _exec_command(command, use_shell=None, use_tee=None, **env):
205     """
206     Internal workhorse for exec_command().
207     Code from https://github.com/numpy/numpy/pull/7862
208     """
209     if use_shell is None:
210         use_shell = os.name == 'posix'
211     if use_tee is None:
212         use_tee = os.name == 'posix'
213 
214     executable = None
215 
216     if os.name == 'posix' and use_shell:
217         # On POSIX, subprocess always uses /bin/sh, override
218         sh = os.environ.get('SHELL', '/bin/sh')
219         if _is_sequence(command):
220             command = [sh, '-c', ' '.join(command)]
221         else:
222             command = [sh, '-c', command]
223         use_shell = False
224 
225     elif os.name == 'nt' and _is_sequence(command):
226         # On Windows, join the string for CreateProcess() ourselves as
227         # subprocess does it a bit differently
228         command = ' '.join(_quote_arg(arg) for arg in command)
229 
230     # Inherit environment by default
231     env = env or None
232     try:
233         proc = subprocess.Popen(command, shell=use_shell, env=env,
234                                 stdout=subprocess.PIPE,
235                                 stderr=subprocess.PIPE,
236                                 universal_newlines=True)
237     except OSError:
238         # Return 127, as os.spawn*() and /bin/sh do
239         return '', 127
240     text, err = proc.communicate()
241     # Only append stderr if the command failed, as otherwise
242     # the output may become garbled for parsing
243     if proc.returncode:
244         if text:
245             text += "\n"
246         text += err
247     # Another historical oddity
248     if text[-1:] == '\n':
249         text = text[:-1]
250     if use_tee:
251         print(text)
252     return proc.returncode, text
253 
254 
255 def _quote_arg(arg):
256     """
257     Quote the argument for safe use in a shell command line.
258     """
259     # If there is a quote in the string, assume relevants parts of the
260     # string are already quoted (e.g. '-I"C:\\Program Files\\..."')
261     if '"' not in arg and ' ' in arg:
262         return '"%s"' % arg
263     return arg
264 
265 
266 def _is_sequence(arg):
267     if isinstance(arg, (str, bytes)):
268         return False
269     try:
270         len(arg)
271         return True
272     except Exception:
273         return False
274
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/numba/pycc/platform.py b/numba/pycc/platform.py
--- a/numba/pycc/platform.py
+++ b/numba/pycc/platform.py
@@ -9,8 +9,9 @@
 import os
 import subprocess
 import sys
-from tempfile import NamedTemporaryFile, mkdtemp, gettempdir
+from tempfile import mkdtemp
 from contextlib import contextmanager
+from pathlib import Path
 
 _configs = {
     # DLL suffix, Python C extension suffix
@@ -57,7 +58,7 @@
                 ntf.close()
                 # *output_dir* is set to avoid the compiler putting temp files
                 # in the current directory.
-                compiler.compile([ntf.name], output_dir=gettempdir())
+                compiler.compile([ntf.name], output_dir=Path(ntf.name).anchor)
         except Exception: # likely CompileError or file system issue
             return False
     return True

{"golden_diff": "diff --git a/numba/pycc/platform.py b/numba/pycc/platform.py\n--- a/numba/pycc/platform.py\n+++ b/numba/pycc/platform.py\n@@ -9,8 +9,9 @@\n import os\n import subprocess\n import sys\n-from tempfile import NamedTemporaryFile, mkdtemp, gettempdir\n+from tempfile import mkdtemp\n from contextlib import contextmanager\n+from pathlib import Path\n \n _configs = {\n     # DLL suffix, Python C extension suffix\n@@ -57,7 +58,7 @@\n                 ntf.close()\n                 # *output_dir* is set to avoid the compiler putting temp files\n                 # in the current directory.\n-                compiler.compile([ntf.name], output_dir=gettempdir())\n+                compiler.compile([ntf.name], output_dir=Path(ntf.name).anchor)\n         except Exception: # likely CompileError or file system issue\n             return False\n     return True\n", "issue": "Compiler not found: /tmp/tmp bug\n\r\n\r\n```\r\n$ pip install numba\r\nCollecting numba\r\n  Downloading numba-0.53.1-cp39-cp39-manylinux2014_x86_64.whl (3.4 MB)\r\n     |\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 3.4 MB 1.2 MB/s \r\nCollecting numpy>=1.15\r\n  Downloading numpy-1.21.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl (15.7 MB)\r\n     |\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 15.7 MB 1.1 MB/s \r\nRequirement already satisfied: setuptools in /usr/lib/python3/dist-packages (from numba) (52.0.0)\r\nCollecting llvmlite<0.37,>=0.36.0rc1\r\n  Downloading llvmlite-0.36.0-cp39-cp39-manylinux2010_x86_64.whl (25.3 MB)\r\n     |\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 25.3 MB 829 kB/s \r\nInstalling collected packages: numpy, llvmlite, numba\r\n  WARNING: The scripts f2py, f2py3 and f2py3.9 are installed in '/home/olaf/.local/bin' which is not on PATH.\r\n  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.\r\nSuccessfully installed llvmlite-0.36.0 numba-0.53.1 numpy-1.21.0\r\n\r\n$ ./t.py \r\n          \r\n$ ./t.py \r\n\r\n$ chmod 000 /tmp/tmp\r\n\r\n$ ./t.py            \r\nTraceback (most recent call last):\r\n  File \"/home/olaf/./t.py\", line 5, in <module>\r\n    cc = CC('interpolation')\r\n  File \"/home/olaf/.local/lib/python3.9/site-packages/numba/pycc/cc.py\", line 65, in __init__\r\n    self._toolchain = Toolchain()\r\n  File \"/home/olaf/.local/lib/python3.9/site-packages/numba/pycc/platform.py\", line 78, in __init__\r\n    self._raise_external_compiler_error()\r\n  File \"/home/olaf/.local/lib/python3.9/site-packages/numba/pycc/platform.py\", line 121, in _raise_external_compiler_error\r\n    raise RuntimeError(msg)\r\nRuntimeError: Attempted to compile AOT function without the compiler used by `numpy.distutils` present. If using conda try:\r\n\r\n#> conda install gcc_linux-64 gxx_linux-64\r\n\r\n$ cat t.py \r\n#!/usr/bin/python3\r\n\r\nfrom numba.pycc import CC\r\n\r\ncc = CC('interpolation')\r\n\r\n# cc.compile()\r\n\r\n$ pip list|grep numba\r\nnumba            0.53.1\r\n```\n", "before_files": [{"content": "from distutils.ccompiler import CCompiler, new_compiler\nfrom distutils.command.build_ext import build_ext\nfrom distutils.sysconfig import customize_compiler\nfrom distutils import log\n\nimport numpy.distutils.misc_util as np_misc\n\nimport functools\nimport os\nimport subprocess\nimport sys\nfrom tempfile import NamedTemporaryFile, mkdtemp, gettempdir\nfrom contextlib import contextmanager\n\n_configs = {\n    # DLL suffix, Python C extension suffix\n    'win': ('.dll', '.pyd'),\n    'default': ('.so', '.so'),\n}\n\n\ndef get_configs(arg):\n    return _configs.get(sys.platform[:3], _configs['default'])[arg]\n\n\nfind_shared_ending = functools.partial(get_configs, 0)\nfind_pyext_ending = functools.partial(get_configs, 1)\n\n@contextmanager\ndef _gentmpfile(suffix):\n    # windows locks the tempfile so use a tempdir + file, see\n    # https://github.com/numba/numba/issues/3304\n    try:\n        tmpdir = mkdtemp()\n        ntf = open(os.path.join(tmpdir, \"temp%s\" % suffix), 'wt')\n        yield ntf\n    finally:\n        try:\n            ntf.close()\n            os.remove(ntf)\n        except:\n            pass\n        else:\n            os.rmdir(tmpdir)\n\ndef _check_external_compiler():\n    # see if the external compiler bound in numpy.distutil is present\n    # and working\n    compiler = new_compiler()\n    customize_compiler(compiler)\n    for suffix in ['.c', '.cxx']:\n        try:\n            with _gentmpfile(suffix) as ntf:\n                simple_c = \"int main(void) { return 0; }\"\n                ntf.write(simple_c)\n                ntf.flush()\n                ntf.close()\n                # *output_dir* is set to avoid the compiler putting temp files\n                # in the current directory.\n                compiler.compile([ntf.name], output_dir=gettempdir())\n        except Exception: # likely CompileError or file system issue\n            return False\n    return True\n\n# boolean on whether the externally provided compiler is present and\n# functioning correctly\n_external_compiler_ok = _check_external_compiler()\n\n\nclass _DummyExtension(object):\n    libraries = []\n\n\nclass Toolchain(object):\n\n    def __init__(self):\n        if not _external_compiler_ok:\n            self._raise_external_compiler_error()\n\n        # Need to import it here since setuptools may monkeypatch it\n        from distutils.dist import Distribution\n        self._verbose = False\n        self._compiler = new_compiler()\n        customize_compiler(self._compiler)\n        self._build_ext = build_ext(Distribution())\n        self._build_ext.finalize_options()\n        self._py_lib_dirs = self._build_ext.library_dirs\n        self._py_include_dirs = self._build_ext.include_dirs\n        self._math_info = np_misc.get_info('npymath')\n\n    @property\n    def verbose(self):\n        return self._verbose\n\n    @verbose.setter\n    def verbose(self, value):\n        self._verbose = value\n        # DEBUG will let Numpy spew many messages, so stick to INFO\n        # to print commands executed by distutils\n        log.set_threshold(log.INFO if value else log.WARN)\n\n    def _raise_external_compiler_error(self):\n        basemsg = (\"Attempted to compile AOT function without the \"\n                   \"compiler used by `numpy.distutils` present.\")\n        conda_msg = \"If using conda try:\\n\\n#> conda install %s\"\n        plt = sys.platform\n        if plt.startswith('linux'):\n            if sys.maxsize <= 2 ** 32:\n                compilers = ['gcc_linux-32', 'gxx_linux-32']\n            else:\n                compilers = ['gcc_linux-64', 'gxx_linux-64']\n            msg = \"%s %s\" % (basemsg, conda_msg % ' '.join(compilers))\n        elif plt.startswith('darwin'):\n            compilers = ['clang_osx-64', 'clangxx_osx-64']\n            msg = \"%s %s\" % (basemsg, conda_msg % ' '.join(compilers))\n        elif plt.startswith('win32'):\n            winmsg = \"Cannot find suitable msvc.\"\n            msg = \"%s %s\" % (basemsg, winmsg)\n        else:\n            msg = \"Unknown platform %s\" % plt\n        raise RuntimeError(msg)\n\n    def compile_objects(self, sources, output_dir,\n                        include_dirs=(), depends=(), macros=(),\n                        extra_cflags=None):\n        \"\"\"\n        Compile the given source files into a separate object file each,\n        all beneath the *output_dir*.  A list of paths to object files\n        is returned.\n\n        *macros* has the same format as in distutils: a list of 1- or 2-tuples.\n        If a 1-tuple (name,), the given name is considered undefined by\n        the C preprocessor.\n        If a 2-tuple (name, value), the given name is expanded into the\n        given value by the C preprocessor.\n        \"\"\"\n        objects = self._compiler.compile(sources,\n                                         output_dir=output_dir,\n                                         include_dirs=include_dirs,\n                                         depends=depends,\n                                         macros=macros or [],\n                                         extra_preargs=extra_cflags)\n        return objects\n\n    def link_shared(self, output, objects, libraries=(),\n                    library_dirs=(), export_symbols=(),\n                    extra_ldflags=None):\n        \"\"\"\n        Create a shared library *output* linking the given *objects*\n        and *libraries* (all strings).\n        \"\"\"\n        output_dir, output_filename = os.path.split(output)\n        self._compiler.link(CCompiler.SHARED_OBJECT, objects,\n                            output_filename, output_dir,\n                            libraries, library_dirs,\n                            export_symbols=export_symbols,\n                            extra_preargs=extra_ldflags)\n\n    def get_python_libraries(self):\n        \"\"\"\n        Get the library arguments necessary to link with Python.\n        \"\"\"\n        libs = self._build_ext.get_libraries(_DummyExtension())\n        if sys.platform == 'win32':\n            # Under Windows, need to link explicitly against the CRT,\n            # as the MSVC compiler would implicitly do.\n            # (XXX msvcrtd in pydebug mode?)\n            libs = libs + ['msvcrt']\n        return libs + self._math_info['libraries']\n\n    def get_python_library_dirs(self):\n        \"\"\"\n        Get the library directories necessary to link with Python.\n        \"\"\"\n        return list(self._py_lib_dirs) + self._math_info['library_dirs']\n\n    def get_python_include_dirs(self):\n        \"\"\"\n        Get the include directories necessary to compile against the Python\n        and Numpy C APIs.\n        \"\"\"\n        return list(self._py_include_dirs) + self._math_info['include_dirs']\n\n    def get_ext_filename(self, ext_name):\n        \"\"\"\n        Given a C extension's module name, return its intended filename.\n        \"\"\"\n        return self._build_ext.get_ext_filename(ext_name)\n\n\n#\n# Patch Numpy's exec_command() to avoid random crashes on Windows in test_pycc\n# see https://github.com/numpy/numpy/pull/7614\n# and https://github.com/numpy/numpy/pull/7862\n#\n\ndef _patch_exec_command():\n    # Patch the internal worker _exec_command()\n    import numpy.distutils.exec_command as mod\n    orig_exec_command = mod._exec_command\n    mod._exec_command = _exec_command\n\n\ndef _exec_command(command, use_shell=None, use_tee=None, **env):\n    \"\"\"\n    Internal workhorse for exec_command().\n    Code from https://github.com/numpy/numpy/pull/7862\n    \"\"\"\n    if use_shell is None:\n        use_shell = os.name == 'posix'\n    if use_tee is None:\n        use_tee = os.name == 'posix'\n\n    executable = None\n\n    if os.name == 'posix' and use_shell:\n        # On POSIX, subprocess always uses /bin/sh, override\n        sh = os.environ.get('SHELL', '/bin/sh')\n        if _is_sequence(command):\n            command = [sh, '-c', ' '.join(command)]\n        else:\n            command = [sh, '-c', command]\n        use_shell = False\n\n    elif os.name == 'nt' and _is_sequence(command):\n        # On Windows, join the string for CreateProcess() ourselves as\n        # subprocess does it a bit differently\n        command = ' '.join(_quote_arg(arg) for arg in command)\n\n    # Inherit environment by default\n    env = env or None\n    try:\n        proc = subprocess.Popen(command, shell=use_shell, env=env,\n                                stdout=subprocess.PIPE,\n                                stderr=subprocess.PIPE,\n                                universal_newlines=True)\n    except OSError:\n        # Return 127, as os.spawn*() and /bin/sh do\n        return '', 127\n    text, err = proc.communicate()\n    # Only append stderr if the command failed, as otherwise\n    # the output may become garbled for parsing\n    if proc.returncode:\n        if text:\n            text += \"\\n\"\n        text += err\n    # Another historical oddity\n    if text[-1:] == '\\n':\n        text = text[:-1]\n    if use_tee:\n        print(text)\n    return proc.returncode, text\n\n\ndef _quote_arg(arg):\n    \"\"\"\n    Quote the argument for safe use in a shell command line.\n    \"\"\"\n    # If there is a quote in the string, assume relevants parts of the\n    # string are already quoted (e.g. '-I\"C:\\\\Program Files\\\\...\"')\n    if '\"' not in arg and ' ' in arg:\n        return '\"%s\"' % arg\n    return arg\n\n\ndef _is_sequence(arg):\n    if isinstance(arg, (str, bytes)):\n        return False\n    try:\n        len(arg)\n        return True\n    except Exception:\n        return False\n", "path": "numba/pycc/platform.py"}], "after_files": [{"content": "from distutils.ccompiler import CCompiler, new_compiler\nfrom distutils.command.build_ext import build_ext\nfrom distutils.sysconfig import customize_compiler\nfrom distutils import log\n\nimport numpy.distutils.misc_util as np_misc\n\nimport functools\nimport os\nimport subprocess\nimport sys\nfrom tempfile import mkdtemp\nfrom contextlib import contextmanager\nfrom pathlib import Path\n\n_configs = {\n    # DLL suffix, Python C extension suffix\n    'win': ('.dll', '.pyd'),\n    'default': ('.so', '.so'),\n}\n\n\ndef get_configs(arg):\n    return _configs.get(sys.platform[:3], _configs['default'])[arg]\n\n\nfind_shared_ending = functools.partial(get_configs, 0)\nfind_pyext_ending = functools.partial(get_configs, 1)\n\n@contextmanager\ndef _gentmpfile(suffix):\n    # windows locks the tempfile so use a tempdir + file, see\n    # https://github.com/numba/numba/issues/3304\n    try:\n        tmpdir = mkdtemp()\n        ntf = open(os.path.join(tmpdir, \"temp%s\" % suffix), 'wt')\n        yield ntf\n    finally:\n        try:\n            ntf.close()\n            os.remove(ntf)\n        except:\n            pass\n        else:\n            os.rmdir(tmpdir)\n\ndef _check_external_compiler():\n    # see if the external compiler bound in numpy.distutil is present\n    # and working\n    compiler = new_compiler()\n    customize_compiler(compiler)\n    for suffix in ['.c', '.cxx']:\n        try:\n            with _gentmpfile(suffix) as ntf:\n                simple_c = \"int main(void) { return 0; }\"\n                ntf.write(simple_c)\n                ntf.flush()\n                ntf.close()\n                # *output_dir* is set to avoid the compiler putting temp files\n                # in the current directory.\n                compiler.compile([ntf.name], output_dir=Path(ntf.name).anchor)\n        except Exception: # likely CompileError or file system issue\n            return False\n    return True\n\n# boolean on whether the externally provided compiler is present and\n# functioning correctly\n_external_compiler_ok = _check_external_compiler()\n\n\nclass _DummyExtension(object):\n    libraries = []\n\n\nclass Toolchain(object):\n\n    def __init__(self):\n        if not _external_compiler_ok:\n            self._raise_external_compiler_error()\n\n        # Need to import it here since setuptools may monkeypatch it\n        from distutils.dist import Distribution\n        self._verbose = False\n        self._compiler = new_compiler()\n        customize_compiler(self._compiler)\n        self._build_ext = build_ext(Distribution())\n        self._build_ext.finalize_options()\n        self._py_lib_dirs = self._build_ext.library_dirs\n        self._py_include_dirs = self._build_ext.include_dirs\n        self._math_info = np_misc.get_info('npymath')\n\n    @property\n    def verbose(self):\n        return self._verbose\n\n    @verbose.setter\n    def verbose(self, value):\n        self._verbose = value\n        # DEBUG will let Numpy spew many messages, so stick to INFO\n        # to print commands executed by distutils\n        log.set_threshold(log.INFO if value else log.WARN)\n\n    def _raise_external_compiler_error(self):\n        basemsg = (\"Attempted to compile AOT function without the \"\n                   \"compiler used by `numpy.distutils` present.\")\n        conda_msg = \"If using conda try:\\n\\n#> conda install %s\"\n        plt = sys.platform\n        if plt.startswith('linux'):\n            if sys.maxsize <= 2 ** 32:\n                compilers = ['gcc_linux-32', 'gxx_linux-32']\n            else:\n                compilers = ['gcc_linux-64', 'gxx_linux-64']\n            msg = \"%s %s\" % (basemsg, conda_msg % ' '.join(compilers))\n        elif plt.startswith('darwin'):\n            compilers = ['clang_osx-64', 'clangxx_osx-64']\n            msg = \"%s %s\" % (basemsg, conda_msg % ' '.join(compilers))\n        elif plt.startswith('win32'):\n            winmsg = \"Cannot find suitable msvc.\"\n            msg = \"%s %s\" % (basemsg, winmsg)\n        else:\n            msg = \"Unknown platform %s\" % plt\n        raise RuntimeError(msg)\n\n    def compile_objects(self, sources, output_dir,\n                        include_dirs=(), depends=(), macros=(),\n                        extra_cflags=None):\n        \"\"\"\n        Compile the given source files into a separate object file each,\n        all beneath the *output_dir*.  A list of paths to object files\n        is returned.\n\n        *macros* has the same format as in distutils: a list of 1- or 2-tuples.\n        If a 1-tuple (name,), the given name is considered undefined by\n        the C preprocessor.\n        If a 2-tuple (name, value), the given name is expanded into the\n        given value by the C preprocessor.\n        \"\"\"\n        objects = self._compiler.compile(sources,\n                                         output_dir=output_dir,\n                                         include_dirs=include_dirs,\n                                         depends=depends,\n                                         macros=macros or [],\n                                         extra_preargs=extra_cflags)\n        return objects\n\n    def link_shared(self, output, objects, libraries=(),\n                    library_dirs=(), export_symbols=(),\n                    extra_ldflags=None):\n        \"\"\"\n        Create a shared library *output* linking the given *objects*\n        and *libraries* (all strings).\n        \"\"\"\n        output_dir, output_filename = os.path.split(output)\n        self._compiler.link(CCompiler.SHARED_OBJECT, objects,\n                            output_filename, output_dir,\n                            libraries, library_dirs,\n                            export_symbols=export_symbols,\n                            extra_preargs=extra_ldflags)\n\n    def get_python_libraries(self):\n        \"\"\"\n        Get the library arguments necessary to link with Python.\n        \"\"\"\n        libs = self._build_ext.get_libraries(_DummyExtension())\n        if sys.platform == 'win32':\n            # Under Windows, need to link explicitly against the CRT,\n            # as the MSVC compiler would implicitly do.\n            # (XXX msvcrtd in pydebug mode?)\n            libs = libs + ['msvcrt']\n        return libs + self._math_info['libraries']\n\n    def get_python_library_dirs(self):\n        \"\"\"\n        Get the library directories necessary to link with Python.\n        \"\"\"\n        return list(self._py_lib_dirs) + self._math_info['library_dirs']\n\n    def get_python_include_dirs(self):\n        \"\"\"\n        Get the include directories necessary to compile against the Python\n        and Numpy C APIs.\n        \"\"\"\n        return list(self._py_include_dirs) + self._math_info['include_dirs']\n\n    def get_ext_filename(self, ext_name):\n        \"\"\"\n        Given a C extension's module name, return its intended filename.\n        \"\"\"\n        return self._build_ext.get_ext_filename(ext_name)\n\n\n#\n# Patch Numpy's exec_command() to avoid random crashes on Windows in test_pycc\n# see https://github.com/numpy/numpy/pull/7614\n# and https://github.com/numpy/numpy/pull/7862\n#\n\ndef _patch_exec_command():\n    # Patch the internal worker _exec_command()\n    import numpy.distutils.exec_command as mod\n    orig_exec_command = mod._exec_command\n    mod._exec_command = _exec_command\n\n\ndef _exec_command(command, use_shell=None, use_tee=None, **env):\n    \"\"\"\n    Internal workhorse for exec_command().\n    Code from https://github.com/numpy/numpy/pull/7862\n    \"\"\"\n    if use_shell is None:\n        use_shell = os.name == 'posix'\n    if use_tee is None:\n        use_tee = os.name == 'posix'\n\n    executable = None\n\n    if os.name == 'posix' and use_shell:\n        # On POSIX, subprocess always uses /bin/sh, override\n        sh = os.environ.get('SHELL', '/bin/sh')\n        if _is_sequence(command):\n            command = [sh, '-c', ' '.join(command)]\n        else:\n            command = [sh, '-c', command]\n        use_shell = False\n\n    elif os.name == 'nt' and _is_sequence(command):\n        # On Windows, join the string for CreateProcess() ourselves as\n        # subprocess does it a bit differently\n        command = ' '.join(_quote_arg(arg) for arg in command)\n\n    # Inherit environment by default\n    env = env or None\n    try:\n        proc = subprocess.Popen(command, shell=use_shell, env=env,\n                                stdout=subprocess.PIPE,\n                                stderr=subprocess.PIPE,\n                                universal_newlines=True)\n    except OSError:\n        # Return 127, as os.spawn*() and /bin/sh do\n        return '', 127\n    text, err = proc.communicate()\n    # Only append stderr if the command failed, as otherwise\n    # the output may become garbled for parsing\n    if proc.returncode:\n        if text:\n            text += \"\\n\"\n        text += err\n    # Another historical oddity\n    if text[-1:] == '\\n':\n        text = text[:-1]\n    if use_tee:\n        print(text)\n    return proc.returncode, text\n\n\ndef _quote_arg(arg):\n    \"\"\"\n    Quote the argument for safe use in a shell command line.\n    \"\"\"\n    # If there is a quote in the string, assume relevants parts of the\n    # string are already quoted (e.g. '-I\"C:\\\\Program Files\\\\...\"')\n    if '\"' not in arg and ' ' in arg:\n        return '\"%s\"' % arg\n    return arg\n\n\ndef _is_sequence(arg):\n    if isinstance(arg, (str, bytes)):\n        return False\n    try:\n        len(arg)\n        return True\n    except Exception:\n        return False\n", "path": "numba/pycc/platform.py"}]}