Chris@87
|
1 # Added Fortran compiler support to config. Currently useful only for
|
Chris@87
|
2 # try_compile call. try_run works but is untested for most of Fortran
|
Chris@87
|
3 # compilers (they must define linker_exe first).
|
Chris@87
|
4 # Pearu Peterson
|
Chris@87
|
5 from __future__ import division, absolute_import, print_function
|
Chris@87
|
6
|
Chris@87
|
7 import os, signal
|
Chris@87
|
8 import warnings
|
Chris@87
|
9 import sys
|
Chris@87
|
10
|
Chris@87
|
11 from distutils.command.config import config as old_config
|
Chris@87
|
12 from distutils.command.config import LANG_EXT
|
Chris@87
|
13 from distutils import log
|
Chris@87
|
14 from distutils.file_util import copy_file
|
Chris@87
|
15 from distutils.ccompiler import CompileError, LinkError
|
Chris@87
|
16 import distutils
|
Chris@87
|
17 from numpy.distutils.exec_command import exec_command
|
Chris@87
|
18 from numpy.distutils.mingw32ccompiler import generate_manifest
|
Chris@87
|
19 from numpy.distutils.command.autodist import check_inline, check_compiler_gcc4
|
Chris@87
|
20 from numpy.distutils.compat import get_exception
|
Chris@87
|
21
|
Chris@87
|
22 LANG_EXT['f77'] = '.f'
|
Chris@87
|
23 LANG_EXT['f90'] = '.f90'
|
Chris@87
|
24
|
Chris@87
|
25 class config(old_config):
|
Chris@87
|
26 old_config.user_options += [
|
Chris@87
|
27 ('fcompiler=', None, "specify the Fortran compiler type"),
|
Chris@87
|
28 ]
|
Chris@87
|
29
|
Chris@87
|
30 def initialize_options(self):
|
Chris@87
|
31 self.fcompiler = None
|
Chris@87
|
32 old_config.initialize_options(self)
|
Chris@87
|
33
|
Chris@87
|
34 def try_run(self, body, headers=None, include_dirs=None,
|
Chris@87
|
35 libraries=None, library_dirs=None, lang="c"):
|
Chris@87
|
36 warnings.warn("\n+++++++++++++++++++++++++++++++++++++++++++++++++\n" \
|
Chris@87
|
37 "Usage of try_run is deprecated: please do not \n" \
|
Chris@87
|
38 "use it anymore, and avoid configuration checks \n" \
|
Chris@87
|
39 "involving running executable on the target machine.\n" \
|
Chris@87
|
40 "+++++++++++++++++++++++++++++++++++++++++++++++++\n",
|
Chris@87
|
41 DeprecationWarning)
|
Chris@87
|
42 return old_config.try_run(self, body, headers, include_dirs, libraries,
|
Chris@87
|
43 library_dirs, lang)
|
Chris@87
|
44
|
Chris@87
|
45 def _check_compiler (self):
|
Chris@87
|
46 old_config._check_compiler(self)
|
Chris@87
|
47 from numpy.distutils.fcompiler import FCompiler, new_fcompiler
|
Chris@87
|
48
|
Chris@87
|
49 if sys.platform == 'win32' and self.compiler.compiler_type == 'msvc':
|
Chris@87
|
50 # XXX: hack to circumvent a python 2.6 bug with msvc9compiler:
|
Chris@87
|
51 # initialize call query_vcvarsall, which throws an IOError, and
|
Chris@87
|
52 # causes an error along the way without much information. We try to
|
Chris@87
|
53 # catch it here, hoping it is early enough, and print an helpful
|
Chris@87
|
54 # message instead of Error: None.
|
Chris@87
|
55 if not self.compiler.initialized:
|
Chris@87
|
56 try:
|
Chris@87
|
57 self.compiler.initialize()
|
Chris@87
|
58 except IOError:
|
Chris@87
|
59 e = get_exception()
|
Chris@87
|
60 msg = """\
|
Chris@87
|
61 Could not initialize compiler instance: do you have Visual Studio
|
Chris@87
|
62 installed? If you are trying to build with MinGW, please use "python setup.py
|
Chris@87
|
63 build -c mingw32" instead. If you have Visual Studio installed, check it is
|
Chris@87
|
64 correctly installed, and the right version (VS 2008 for python 2.6, 2.7 and 3.2,
|
Chris@87
|
65 VS 2010 for >= 3.3).
|
Chris@87
|
66
|
Chris@87
|
67 Original exception was: %s, and the Compiler class was %s
|
Chris@87
|
68 ============================================================================""" \
|
Chris@87
|
69 % (e, self.compiler.__class__.__name__)
|
Chris@87
|
70 print ("""\
|
Chris@87
|
71 ============================================================================""")
|
Chris@87
|
72 raise distutils.errors.DistutilsPlatformError(msg)
|
Chris@87
|
73
|
Chris@87
|
74 # After MSVC is initialized, add an explicit /MANIFEST to linker
|
Chris@87
|
75 # flags. See issues gh-4245 and gh-4101 for details. Also
|
Chris@87
|
76 # relevant are issues 4431 and 16296 on the Python bug tracker.
|
Chris@87
|
77 from distutils import msvc9compiler
|
Chris@87
|
78 if msvc9compiler.get_build_version() >= 10:
|
Chris@87
|
79 for ldflags in [self.compiler.ldflags_shared,
|
Chris@87
|
80 self.compiler.ldflags_shared_debug]:
|
Chris@87
|
81 if '/MANIFEST' not in ldflags:
|
Chris@87
|
82 ldflags.append('/MANIFEST')
|
Chris@87
|
83
|
Chris@87
|
84 if not isinstance(self.fcompiler, FCompiler):
|
Chris@87
|
85 self.fcompiler = new_fcompiler(compiler=self.fcompiler,
|
Chris@87
|
86 dry_run=self.dry_run, force=1,
|
Chris@87
|
87 c_compiler=self.compiler)
|
Chris@87
|
88 if self.fcompiler is not None:
|
Chris@87
|
89 self.fcompiler.customize(self.distribution)
|
Chris@87
|
90 if self.fcompiler.get_version():
|
Chris@87
|
91 self.fcompiler.customize_cmd(self)
|
Chris@87
|
92 self.fcompiler.show_customization()
|
Chris@87
|
93
|
Chris@87
|
94 def _wrap_method(self, mth, lang, args):
|
Chris@87
|
95 from distutils.ccompiler import CompileError
|
Chris@87
|
96 from distutils.errors import DistutilsExecError
|
Chris@87
|
97 save_compiler = self.compiler
|
Chris@87
|
98 if lang in ['f77', 'f90']:
|
Chris@87
|
99 self.compiler = self.fcompiler
|
Chris@87
|
100 try:
|
Chris@87
|
101 ret = mth(*((self,)+args))
|
Chris@87
|
102 except (DistutilsExecError, CompileError):
|
Chris@87
|
103 msg = str(get_exception())
|
Chris@87
|
104 self.compiler = save_compiler
|
Chris@87
|
105 raise CompileError
|
Chris@87
|
106 self.compiler = save_compiler
|
Chris@87
|
107 return ret
|
Chris@87
|
108
|
Chris@87
|
109 def _compile (self, body, headers, include_dirs, lang):
|
Chris@87
|
110 return self._wrap_method(old_config._compile, lang,
|
Chris@87
|
111 (body, headers, include_dirs, lang))
|
Chris@87
|
112
|
Chris@87
|
113 def _link (self, body,
|
Chris@87
|
114 headers, include_dirs,
|
Chris@87
|
115 libraries, library_dirs, lang):
|
Chris@87
|
116 if self.compiler.compiler_type=='msvc':
|
Chris@87
|
117 libraries = (libraries or [])[:]
|
Chris@87
|
118 library_dirs = (library_dirs or [])[:]
|
Chris@87
|
119 if lang in ['f77', 'f90']:
|
Chris@87
|
120 lang = 'c' # always use system linker when using MSVC compiler
|
Chris@87
|
121 if self.fcompiler:
|
Chris@87
|
122 for d in self.fcompiler.library_dirs or []:
|
Chris@87
|
123 # correct path when compiling in Cygwin but with
|
Chris@87
|
124 # normal Win Python
|
Chris@87
|
125 if d.startswith('/usr/lib'):
|
Chris@87
|
126 s, o = exec_command(['cygpath', '-w', d],
|
Chris@87
|
127 use_tee=False)
|
Chris@87
|
128 if not s: d = o
|
Chris@87
|
129 library_dirs.append(d)
|
Chris@87
|
130 for libname in self.fcompiler.libraries or []:
|
Chris@87
|
131 if libname not in libraries:
|
Chris@87
|
132 libraries.append(libname)
|
Chris@87
|
133 for libname in libraries:
|
Chris@87
|
134 if libname.startswith('msvc'): continue
|
Chris@87
|
135 fileexists = False
|
Chris@87
|
136 for libdir in library_dirs or []:
|
Chris@87
|
137 libfile = os.path.join(libdir, '%s.lib' % (libname))
|
Chris@87
|
138 if os.path.isfile(libfile):
|
Chris@87
|
139 fileexists = True
|
Chris@87
|
140 break
|
Chris@87
|
141 if fileexists: continue
|
Chris@87
|
142 # make g77-compiled static libs available to MSVC
|
Chris@87
|
143 fileexists = False
|
Chris@87
|
144 for libdir in library_dirs:
|
Chris@87
|
145 libfile = os.path.join(libdir, 'lib%s.a' % (libname))
|
Chris@87
|
146 if os.path.isfile(libfile):
|
Chris@87
|
147 # copy libname.a file to name.lib so that MSVC linker
|
Chris@87
|
148 # can find it
|
Chris@87
|
149 libfile2 = os.path.join(libdir, '%s.lib' % (libname))
|
Chris@87
|
150 copy_file(libfile, libfile2)
|
Chris@87
|
151 self.temp_files.append(libfile2)
|
Chris@87
|
152 fileexists = True
|
Chris@87
|
153 break
|
Chris@87
|
154 if fileexists: continue
|
Chris@87
|
155 log.warn('could not find library %r in directories %s' \
|
Chris@87
|
156 % (libname, library_dirs))
|
Chris@87
|
157 elif self.compiler.compiler_type == 'mingw32':
|
Chris@87
|
158 generate_manifest(self)
|
Chris@87
|
159 return self._wrap_method(old_config._link, lang,
|
Chris@87
|
160 (body, headers, include_dirs,
|
Chris@87
|
161 libraries, library_dirs, lang))
|
Chris@87
|
162
|
Chris@87
|
163 def check_header(self, header, include_dirs=None, library_dirs=None, lang='c'):
|
Chris@87
|
164 self._check_compiler()
|
Chris@87
|
165 return self.try_compile(
|
Chris@87
|
166 "/* we need a dummy line to make distutils happy */",
|
Chris@87
|
167 [header], include_dirs)
|
Chris@87
|
168
|
Chris@87
|
169 def check_decl(self, symbol,
|
Chris@87
|
170 headers=None, include_dirs=None):
|
Chris@87
|
171 self._check_compiler()
|
Chris@87
|
172 body = """
|
Chris@87
|
173 int main()
|
Chris@87
|
174 {
|
Chris@87
|
175 #ifndef %s
|
Chris@87
|
176 (void) %s;
|
Chris@87
|
177 #endif
|
Chris@87
|
178 ;
|
Chris@87
|
179 return 0;
|
Chris@87
|
180 }""" % (symbol, symbol)
|
Chris@87
|
181
|
Chris@87
|
182 return self.try_compile(body, headers, include_dirs)
|
Chris@87
|
183
|
Chris@87
|
184 def check_macro_true(self, symbol,
|
Chris@87
|
185 headers=None, include_dirs=None):
|
Chris@87
|
186 self._check_compiler()
|
Chris@87
|
187 body = """
|
Chris@87
|
188 int main()
|
Chris@87
|
189 {
|
Chris@87
|
190 #if %s
|
Chris@87
|
191 #else
|
Chris@87
|
192 #error false or undefined macro
|
Chris@87
|
193 #endif
|
Chris@87
|
194 ;
|
Chris@87
|
195 return 0;
|
Chris@87
|
196 }""" % (symbol,)
|
Chris@87
|
197
|
Chris@87
|
198 return self.try_compile(body, headers, include_dirs)
|
Chris@87
|
199
|
Chris@87
|
200 def check_type(self, type_name, headers=None, include_dirs=None,
|
Chris@87
|
201 library_dirs=None):
|
Chris@87
|
202 """Check type availability. Return True if the type can be compiled,
|
Chris@87
|
203 False otherwise"""
|
Chris@87
|
204 self._check_compiler()
|
Chris@87
|
205
|
Chris@87
|
206 # First check the type can be compiled
|
Chris@87
|
207 body = r"""
|
Chris@87
|
208 int main() {
|
Chris@87
|
209 if ((%(name)s *) 0)
|
Chris@87
|
210 return 0;
|
Chris@87
|
211 if (sizeof (%(name)s))
|
Chris@87
|
212 return 0;
|
Chris@87
|
213 }
|
Chris@87
|
214 """ % {'name': type_name}
|
Chris@87
|
215
|
Chris@87
|
216 st = False
|
Chris@87
|
217 try:
|
Chris@87
|
218 try:
|
Chris@87
|
219 self._compile(body % {'type': type_name},
|
Chris@87
|
220 headers, include_dirs, 'c')
|
Chris@87
|
221 st = True
|
Chris@87
|
222 except distutils.errors.CompileError:
|
Chris@87
|
223 st = False
|
Chris@87
|
224 finally:
|
Chris@87
|
225 self._clean()
|
Chris@87
|
226
|
Chris@87
|
227 return st
|
Chris@87
|
228
|
Chris@87
|
229 def check_type_size(self, type_name, headers=None, include_dirs=None, library_dirs=None, expected=None):
|
Chris@87
|
230 """Check size of a given type."""
|
Chris@87
|
231 self._check_compiler()
|
Chris@87
|
232
|
Chris@87
|
233 # First check the type can be compiled
|
Chris@87
|
234 body = r"""
|
Chris@87
|
235 typedef %(type)s npy_check_sizeof_type;
|
Chris@87
|
236 int main ()
|
Chris@87
|
237 {
|
Chris@87
|
238 static int test_array [1 - 2 * !(((long) (sizeof (npy_check_sizeof_type))) >= 0)];
|
Chris@87
|
239 test_array [0] = 0
|
Chris@87
|
240
|
Chris@87
|
241 ;
|
Chris@87
|
242 return 0;
|
Chris@87
|
243 }
|
Chris@87
|
244 """
|
Chris@87
|
245 self._compile(body % {'type': type_name},
|
Chris@87
|
246 headers, include_dirs, 'c')
|
Chris@87
|
247 self._clean()
|
Chris@87
|
248
|
Chris@87
|
249 if expected:
|
Chris@87
|
250 body = r"""
|
Chris@87
|
251 typedef %(type)s npy_check_sizeof_type;
|
Chris@87
|
252 int main ()
|
Chris@87
|
253 {
|
Chris@87
|
254 static int test_array [1 - 2 * !(((long) (sizeof (npy_check_sizeof_type))) == %(size)s)];
|
Chris@87
|
255 test_array [0] = 0
|
Chris@87
|
256
|
Chris@87
|
257 ;
|
Chris@87
|
258 return 0;
|
Chris@87
|
259 }
|
Chris@87
|
260 """
|
Chris@87
|
261 for size in expected:
|
Chris@87
|
262 try:
|
Chris@87
|
263 self._compile(body % {'type': type_name, 'size': size},
|
Chris@87
|
264 headers, include_dirs, 'c')
|
Chris@87
|
265 self._clean()
|
Chris@87
|
266 return size
|
Chris@87
|
267 except CompileError:
|
Chris@87
|
268 pass
|
Chris@87
|
269
|
Chris@87
|
270 # this fails to *compile* if size > sizeof(type)
|
Chris@87
|
271 body = r"""
|
Chris@87
|
272 typedef %(type)s npy_check_sizeof_type;
|
Chris@87
|
273 int main ()
|
Chris@87
|
274 {
|
Chris@87
|
275 static int test_array [1 - 2 * !(((long) (sizeof (npy_check_sizeof_type))) <= %(size)s)];
|
Chris@87
|
276 test_array [0] = 0
|
Chris@87
|
277
|
Chris@87
|
278 ;
|
Chris@87
|
279 return 0;
|
Chris@87
|
280 }
|
Chris@87
|
281 """
|
Chris@87
|
282
|
Chris@87
|
283 # The principle is simple: we first find low and high bounds of size
|
Chris@87
|
284 # for the type, where low/high are looked up on a log scale. Then, we
|
Chris@87
|
285 # do a binary search to find the exact size between low and high
|
Chris@87
|
286 low = 0
|
Chris@87
|
287 mid = 0
|
Chris@87
|
288 while True:
|
Chris@87
|
289 try:
|
Chris@87
|
290 self._compile(body % {'type': type_name, 'size': mid},
|
Chris@87
|
291 headers, include_dirs, 'c')
|
Chris@87
|
292 self._clean()
|
Chris@87
|
293 break
|
Chris@87
|
294 except CompileError:
|
Chris@87
|
295 #log.info("failure to test for bound %d" % mid)
|
Chris@87
|
296 low = mid + 1
|
Chris@87
|
297 mid = 2 * mid + 1
|
Chris@87
|
298
|
Chris@87
|
299 high = mid
|
Chris@87
|
300 # Binary search:
|
Chris@87
|
301 while low != high:
|
Chris@87
|
302 mid = (high - low) // 2 + low
|
Chris@87
|
303 try:
|
Chris@87
|
304 self._compile(body % {'type': type_name, 'size': mid},
|
Chris@87
|
305 headers, include_dirs, 'c')
|
Chris@87
|
306 self._clean()
|
Chris@87
|
307 high = mid
|
Chris@87
|
308 except CompileError:
|
Chris@87
|
309 low = mid + 1
|
Chris@87
|
310 return low
|
Chris@87
|
311
|
Chris@87
|
312 def check_func(self, func,
|
Chris@87
|
313 headers=None, include_dirs=None,
|
Chris@87
|
314 libraries=None, library_dirs=None,
|
Chris@87
|
315 decl=False, call=False, call_args=None):
|
Chris@87
|
316 # clean up distutils's config a bit: add void to main(), and
|
Chris@87
|
317 # return a value.
|
Chris@87
|
318 self._check_compiler()
|
Chris@87
|
319 body = []
|
Chris@87
|
320 if decl:
|
Chris@87
|
321 if type(decl) == str:
|
Chris@87
|
322 body.append(decl)
|
Chris@87
|
323 else:
|
Chris@87
|
324 body.append("int %s (void);" % func)
|
Chris@87
|
325 # Handle MSVC intrinsics: force MS compiler to make a function call.
|
Chris@87
|
326 # Useful to test for some functions when built with optimization on, to
|
Chris@87
|
327 # avoid build error because the intrinsic and our 'fake' test
|
Chris@87
|
328 # declaration do not match.
|
Chris@87
|
329 body.append("#ifdef _MSC_VER")
|
Chris@87
|
330 body.append("#pragma function(%s)" % func)
|
Chris@87
|
331 body.append("#endif")
|
Chris@87
|
332 body.append("int main (void) {")
|
Chris@87
|
333 if call:
|
Chris@87
|
334 if call_args is None:
|
Chris@87
|
335 call_args = ''
|
Chris@87
|
336 body.append(" %s(%s);" % (func, call_args))
|
Chris@87
|
337 else:
|
Chris@87
|
338 body.append(" %s;" % func)
|
Chris@87
|
339 body.append(" return 0;")
|
Chris@87
|
340 body.append("}")
|
Chris@87
|
341 body = '\n'.join(body) + "\n"
|
Chris@87
|
342
|
Chris@87
|
343 return self.try_link(body, headers, include_dirs,
|
Chris@87
|
344 libraries, library_dirs)
|
Chris@87
|
345
|
Chris@87
|
346 def check_funcs_once(self, funcs,
|
Chris@87
|
347 headers=None, include_dirs=None,
|
Chris@87
|
348 libraries=None, library_dirs=None,
|
Chris@87
|
349 decl=False, call=False, call_args=None):
|
Chris@87
|
350 """Check a list of functions at once.
|
Chris@87
|
351
|
Chris@87
|
352 This is useful to speed up things, since all the functions in the funcs
|
Chris@87
|
353 list will be put in one compilation unit.
|
Chris@87
|
354
|
Chris@87
|
355 Arguments
|
Chris@87
|
356 ---------
|
Chris@87
|
357 funcs : seq
|
Chris@87
|
358 list of functions to test
|
Chris@87
|
359 include_dirs : seq
|
Chris@87
|
360 list of header paths
|
Chris@87
|
361 libraries : seq
|
Chris@87
|
362 list of libraries to link the code snippet to
|
Chris@87
|
363 libraru_dirs : seq
|
Chris@87
|
364 list of library paths
|
Chris@87
|
365 decl : dict
|
Chris@87
|
366 for every (key, value), the declaration in the value will be
|
Chris@87
|
367 used for function in key. If a function is not in the
|
Chris@87
|
368 dictionay, no declaration will be used.
|
Chris@87
|
369 call : dict
|
Chris@87
|
370 for every item (f, value), if the value is True, a call will be
|
Chris@87
|
371 done to the function f.
|
Chris@87
|
372 """
|
Chris@87
|
373 self._check_compiler()
|
Chris@87
|
374 body = []
|
Chris@87
|
375 if decl:
|
Chris@87
|
376 for f, v in decl.items():
|
Chris@87
|
377 if v:
|
Chris@87
|
378 body.append("int %s (void);" % f)
|
Chris@87
|
379
|
Chris@87
|
380 # Handle MS intrinsics. See check_func for more info.
|
Chris@87
|
381 body.append("#ifdef _MSC_VER")
|
Chris@87
|
382 for func in funcs:
|
Chris@87
|
383 body.append("#pragma function(%s)" % func)
|
Chris@87
|
384 body.append("#endif")
|
Chris@87
|
385
|
Chris@87
|
386 body.append("int main (void) {")
|
Chris@87
|
387 if call:
|
Chris@87
|
388 for f in funcs:
|
Chris@87
|
389 if f in call and call[f]:
|
Chris@87
|
390 if not (call_args and f in call_args and call_args[f]):
|
Chris@87
|
391 args = ''
|
Chris@87
|
392 else:
|
Chris@87
|
393 args = call_args[f]
|
Chris@87
|
394 body.append(" %s(%s);" % (f, args))
|
Chris@87
|
395 else:
|
Chris@87
|
396 body.append(" %s;" % f)
|
Chris@87
|
397 else:
|
Chris@87
|
398 for f in funcs:
|
Chris@87
|
399 body.append(" %s;" % f)
|
Chris@87
|
400 body.append(" return 0;")
|
Chris@87
|
401 body.append("}")
|
Chris@87
|
402 body = '\n'.join(body) + "\n"
|
Chris@87
|
403
|
Chris@87
|
404 return self.try_link(body, headers, include_dirs,
|
Chris@87
|
405 libraries, library_dirs)
|
Chris@87
|
406
|
Chris@87
|
407 def check_inline(self):
|
Chris@87
|
408 """Return the inline keyword recognized by the compiler, empty string
|
Chris@87
|
409 otherwise."""
|
Chris@87
|
410 return check_inline(self)
|
Chris@87
|
411
|
Chris@87
|
412 def check_compiler_gcc4(self):
|
Chris@87
|
413 """Return True if the C compiler is gcc >= 4."""
|
Chris@87
|
414 return check_compiler_gcc4(self)
|
Chris@87
|
415
|
Chris@87
|
416 def get_output(self, body, headers=None, include_dirs=None,
|
Chris@87
|
417 libraries=None, library_dirs=None,
|
Chris@87
|
418 lang="c", use_tee=None):
|
Chris@87
|
419 """Try to compile, link to an executable, and run a program
|
Chris@87
|
420 built from 'body' and 'headers'. Returns the exit status code
|
Chris@87
|
421 of the program and its output.
|
Chris@87
|
422 """
|
Chris@87
|
423 warnings.warn("\n+++++++++++++++++++++++++++++++++++++++++++++++++\n" \
|
Chris@87
|
424 "Usage of get_output is deprecated: please do not \n" \
|
Chris@87
|
425 "use it anymore, and avoid configuration checks \n" \
|
Chris@87
|
426 "involving running executable on the target machine.\n" \
|
Chris@87
|
427 "+++++++++++++++++++++++++++++++++++++++++++++++++\n",
|
Chris@87
|
428 DeprecationWarning)
|
Chris@87
|
429 from distutils.ccompiler import CompileError, LinkError
|
Chris@87
|
430 self._check_compiler()
|
Chris@87
|
431 exitcode, output = 255, ''
|
Chris@87
|
432 try:
|
Chris@87
|
433 grabber = GrabStdout()
|
Chris@87
|
434 try:
|
Chris@87
|
435 src, obj, exe = self._link(body, headers, include_dirs,
|
Chris@87
|
436 libraries, library_dirs, lang)
|
Chris@87
|
437 grabber.restore()
|
Chris@87
|
438 except:
|
Chris@87
|
439 output = grabber.data
|
Chris@87
|
440 grabber.restore()
|
Chris@87
|
441 raise
|
Chris@87
|
442 exe = os.path.join('.', exe)
|
Chris@87
|
443 exitstatus, output = exec_command(exe, execute_in='.',
|
Chris@87
|
444 use_tee=use_tee)
|
Chris@87
|
445 if hasattr(os, 'WEXITSTATUS'):
|
Chris@87
|
446 exitcode = os.WEXITSTATUS(exitstatus)
|
Chris@87
|
447 if os.WIFSIGNALED(exitstatus):
|
Chris@87
|
448 sig = os.WTERMSIG(exitstatus)
|
Chris@87
|
449 log.error('subprocess exited with signal %d' % (sig,))
|
Chris@87
|
450 if sig == signal.SIGINT:
|
Chris@87
|
451 # control-C
|
Chris@87
|
452 raise KeyboardInterrupt
|
Chris@87
|
453 else:
|
Chris@87
|
454 exitcode = exitstatus
|
Chris@87
|
455 log.info("success!")
|
Chris@87
|
456 except (CompileError, LinkError):
|
Chris@87
|
457 log.info("failure.")
|
Chris@87
|
458 self._clean()
|
Chris@87
|
459 return exitcode, output
|
Chris@87
|
460
|
Chris@87
|
461 class GrabStdout(object):
|
Chris@87
|
462
|
Chris@87
|
463 def __init__(self):
|
Chris@87
|
464 self.sys_stdout = sys.stdout
|
Chris@87
|
465 self.data = ''
|
Chris@87
|
466 sys.stdout = self
|
Chris@87
|
467
|
Chris@87
|
468 def write (self, data):
|
Chris@87
|
469 self.sys_stdout.write(data)
|
Chris@87
|
470 self.data += data
|
Chris@87
|
471
|
Chris@87
|
472 def flush (self):
|
Chris@87
|
473 self.sys_stdout.flush()
|
Chris@87
|
474
|
Chris@87
|
475 def restore(self):
|
Chris@87
|
476 sys.stdout = self.sys_stdout
|