Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/numba/pycc/platform.py: 0%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

118 statements  

1import setuptools 

2from setuptools.command.build_ext import build_ext 

3from setuptools.dist import Distribution 

4import numpy as np 

5 

6import functools 

7import os 

8import subprocess 

9import sys 

10from tempfile import mkdtemp 

11from contextlib import contextmanager 

12from pathlib import Path 

13 

14# Wire in distutils components from setuptools 

15CCompiler = setuptools.distutils.ccompiler.CCompiler 

16new_compiler = setuptools.distutils.ccompiler.new_compiler 

17customize_compiler = setuptools.distutils.sysconfig.customize_compiler 

18log = setuptools.distutils.log 

19 

20 

21_configs = { 

22 # DLL suffix, Python C extension suffix 

23 'win': ('.dll', '.pyd'), 

24 'default': ('.so', '.so'), 

25} 

26 

27 

28def get_configs(arg): 

29 return _configs.get(sys.platform[:3], _configs['default'])[arg] 

30 

31 

32find_shared_ending = functools.partial(get_configs, 0) 

33find_pyext_ending = functools.partial(get_configs, 1) 

34 

35@contextmanager 

36def _gentmpfile(suffix): 

37 # windows locks the tempfile so use a tempdir + file, see 

38 # https://github.com/numba/numba/issues/3304 

39 try: 

40 tmpdir = mkdtemp() 

41 ntf = open(os.path.join(tmpdir, "temp%s" % suffix), 'wt') 

42 yield ntf 

43 finally: 

44 try: 

45 ntf.close() 

46 os.remove(ntf) 

47 except: 

48 pass 

49 else: 

50 os.rmdir(tmpdir) 

51 

52 

53@functools.lru_cache(maxsize=1) 

54def external_compiler_works(): 

55 """ 

56 Returns True if the "external compiler" bound in numpy.distutil is present 

57 and working, False otherwise. 

58 """ 

59 compiler = new_compiler() 

60 customize_compiler(compiler) 

61 for suffix in ['.c', '.cxx']: 

62 try: 

63 with _gentmpfile(suffix) as ntf: 

64 simple_c = "int main(void) { return 0; }" 

65 ntf.write(simple_c) 

66 ntf.flush() 

67 ntf.close() 

68 # *output_dir* is set to avoid the compiler putting temp files 

69 # in the current directory. 

70 compiler.compile([ntf.name], output_dir=Path(ntf.name).anchor) 

71 except Exception: # likely CompileError or file system issue 

72 return False 

73 return True 

74 

75 

76class _DummyExtension(object): 

77 libraries = [] 

78 

79 

80class Toolchain(object): 

81 

82 def __init__(self): 

83 if not external_compiler_works(): 

84 self._raise_external_compiler_error() 

85 

86 self._verbose = False 

87 self._compiler = new_compiler() 

88 customize_compiler(self._compiler) 

89 self._build_ext = build_ext(Distribution()) 

90 self._build_ext.finalize_options() 

91 self._py_lib_dirs = self._build_ext.library_dirs 

92 self._py_include_dirs = self._build_ext.include_dirs 

93 np_compile_args = {'include_dirs': [np.get_include(),],} 

94 if sys.platform == 'win32': 

95 np_compile_args['libraries'] = [] 

96 else: 

97 np_compile_args['libraries'] = ['m',] 

98 self._math_info = np_compile_args 

99 

100 @property 

101 def verbose(self): 

102 return self._verbose 

103 

104 @verbose.setter 

105 def verbose(self, value): 

106 self._verbose = value 

107 # DEBUG will let Numpy spew many messages, so stick to INFO 

108 # to print commands executed by distutils 

109 log.set_threshold(log.INFO if value else log.WARN) 

110 

111 def _raise_external_compiler_error(self): 

112 basemsg = ("Attempted to compile AOT function without the " 

113 "compiler used by `numpy.distutils` present.") 

114 conda_msg = "If using conda try:\n\n#> conda install %s" 

115 plt = sys.platform 

116 if plt.startswith('linux'): 

117 if sys.maxsize <= 2 ** 32: 

118 compilers = ['gcc_linux-32', 'gxx_linux-32'] 

119 else: 

120 compilers = ['gcc_linux-64', 'gxx_linux-64'] 

121 msg = "%s %s" % (basemsg, conda_msg % ' '.join(compilers)) 

122 elif plt.startswith('darwin'): 

123 compilers = ['clang_osx-64', 'clangxx_osx-64'] 

124 msg = "%s %s" % (basemsg, conda_msg % ' '.join(compilers)) 

125 elif plt.startswith('win32'): 

126 winmsg = "Cannot find suitable msvc." 

127 msg = "%s %s" % (basemsg, winmsg) 

128 else: 

129 msg = "Unknown platform %s" % plt 

130 raise RuntimeError(msg) 

131 

132 def compile_objects(self, sources, output_dir, 

133 include_dirs=(), depends=(), macros=(), 

134 extra_cflags=None): 

135 """ 

136 Compile the given source files into a separate object file each, 

137 all beneath the *output_dir*. A list of paths to object files 

138 is returned. 

139 

140 *macros* has the same format as in distutils: a list of 1- or 2-tuples. 

141 If a 1-tuple (name,), the given name is considered undefined by 

142 the C preprocessor. 

143 If a 2-tuple (name, value), the given name is expanded into the 

144 given value by the C preprocessor. 

145 """ 

146 objects = self._compiler.compile(sources, 

147 output_dir=output_dir, 

148 include_dirs=include_dirs, 

149 depends=depends, 

150 macros=macros or [], 

151 extra_preargs=extra_cflags) 

152 return objects 

153 

154 def link_shared(self, output, objects, libraries=(), 

155 library_dirs=(), export_symbols=(), 

156 extra_ldflags=None): 

157 """ 

158 Create a shared library *output* linking the given *objects* 

159 and *libraries* (all strings). 

160 """ 

161 output_dir, output_filename = os.path.split(output) 

162 self._compiler.link(CCompiler.SHARED_OBJECT, objects, 

163 output_filename, output_dir, 

164 libraries, library_dirs, 

165 export_symbols=export_symbols, 

166 extra_preargs=extra_ldflags) 

167 

168 def get_python_libraries(self): 

169 """ 

170 Get the library arguments necessary to link with Python. 

171 """ 

172 libs = self._build_ext.get_libraries(_DummyExtension()) 

173 if sys.platform == 'win32': 

174 # Under Windows, need to link explicitly against the CRT, 

175 # as the MSVC compiler would implicitly do. 

176 # (XXX msvcrtd in pydebug mode?) 

177 libs = libs + ['msvcrt'] 

178 return libs + self._math_info['libraries'] 

179 

180 def get_python_library_dirs(self): 

181 """ 

182 Get the library directories necessary to link with Python. 

183 """ 

184 return list(self._py_lib_dirs) 

185 

186 def get_python_include_dirs(self): 

187 """ 

188 Get the include directories necessary to compile against the Python 

189 and Numpy C APIs. 

190 """ 

191 return list(self._py_include_dirs) + self._math_info['include_dirs'] 

192 

193 def get_ext_filename(self, ext_name): 

194 """ 

195 Given a C extension's module name, return its intended filename. 

196 """ 

197 return self._build_ext.get_ext_filename(ext_name) 

198 

199 

200def _quote_arg(arg): 

201 """ 

202 Quote the argument for safe use in a shell command line. 

203 """ 

204 # If there is a quote in the string, assume relevants parts of the 

205 # string are already quoted (e.g. '-I"C:\\Program Files\\..."') 

206 if '"' not in arg and ' ' in arg: 

207 return '"%s"' % arg 

208 return arg 

209 

210 

211def _is_sequence(arg): 

212 if isinstance(arg, (str, bytes)): 

213 return False 

214 try: 

215 len(arg) 

216 return True 

217 except Exception: 

218 return False