517 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			517 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 
								 | 
							
								# Added Fortran compiler support to config. Currently useful only for
							 | 
						||
| 
								 | 
							
								# try_compile call. try_run works but is untested for most of Fortran
							 | 
						||
| 
								 | 
							
								# compilers (they must define linker_exe first).
							 | 
						||
| 
								 | 
							
								# Pearu Peterson
							 | 
						||
| 
								 | 
							
								import os
							 | 
						||
| 
								 | 
							
								import signal
							 | 
						||
| 
								 | 
							
								import subprocess
							 | 
						||
| 
								 | 
							
								import sys
							 | 
						||
| 
								 | 
							
								import textwrap
							 | 
						||
| 
								 | 
							
								import warnings
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								from distutils.command.config import config as old_config
							 | 
						||
| 
								 | 
							
								from distutils.command.config import LANG_EXT
							 | 
						||
| 
								 | 
							
								from distutils import log
							 | 
						||
| 
								 | 
							
								from distutils.file_util import copy_file
							 | 
						||
| 
								 | 
							
								from distutils.ccompiler import CompileError, LinkError
							 | 
						||
| 
								 | 
							
								import distutils
							 | 
						||
| 
								 | 
							
								from numpy.distutils.exec_command import filepath_from_subprocess_output
							 | 
						||
| 
								 | 
							
								from numpy.distutils.mingw32ccompiler import generate_manifest
							 | 
						||
| 
								 | 
							
								from numpy.distutils.command.autodist import (check_gcc_function_attribute,
							 | 
						||
| 
								 | 
							
								                                              check_gcc_function_attribute_with_intrinsics,
							 | 
						||
| 
								 | 
							
								                                              check_gcc_variable_attribute,
							 | 
						||
| 
								 | 
							
								                                              check_gcc_version_at_least,
							 | 
						||
| 
								 | 
							
								                                              check_inline,
							 | 
						||
| 
								 | 
							
								                                              check_restrict,
							 | 
						||
| 
								 | 
							
								                                              check_compiler_gcc)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								LANG_EXT['f77'] = '.f'
							 | 
						||
| 
								 | 
							
								LANG_EXT['f90'] = '.f90'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class config(old_config):
							 | 
						||
| 
								 | 
							
								    old_config.user_options += [
							 | 
						||
| 
								 | 
							
								        ('fcompiler=', None, "specify the Fortran compiler type"),
							 | 
						||
| 
								 | 
							
								        ]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def initialize_options(self):
							 | 
						||
| 
								 | 
							
								        self.fcompiler = None
							 | 
						||
| 
								 | 
							
								        old_config.initialize_options(self)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _check_compiler (self):
							 | 
						||
| 
								 | 
							
								        old_config._check_compiler(self)
							 | 
						||
| 
								 | 
							
								        from numpy.distutils.fcompiler import FCompiler, new_fcompiler
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if sys.platform == 'win32' and (self.compiler.compiler_type in
							 | 
						||
| 
								 | 
							
								                                        ('msvc', 'intelw', 'intelemw')):
							 | 
						||
| 
								 | 
							
								            # XXX: hack to circumvent a python 2.6 bug with msvc9compiler:
							 | 
						||
| 
								 | 
							
								            # initialize call query_vcvarsall, which throws an OSError, and
							 | 
						||
| 
								 | 
							
								            # causes an error along the way without much information. We try to
							 | 
						||
| 
								 | 
							
								            # catch it here, hoping it is early enough, and print a helpful
							 | 
						||
| 
								 | 
							
								            # message instead of Error: None.
							 | 
						||
| 
								 | 
							
								            if not self.compiler.initialized:
							 | 
						||
| 
								 | 
							
								                try:
							 | 
						||
| 
								 | 
							
								                    self.compiler.initialize()
							 | 
						||
| 
								 | 
							
								                except OSError as e:
							 | 
						||
| 
								 | 
							
								                    msg = textwrap.dedent("""\
							 | 
						||
| 
								 | 
							
								                        Could not initialize compiler instance: do you have Visual Studio
							 | 
						||
| 
								 | 
							
								                        installed?  If you are trying to build with MinGW, please use "python setup.py
							 | 
						||
| 
								 | 
							
								                        build -c mingw32" instead.  If you have Visual Studio installed, check it is
							 | 
						||
| 
								 | 
							
								                        correctly installed, and the right version (VS 2015 as of this writing).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                        Original exception was: %s, and the Compiler class was %s
							 | 
						||
| 
								 | 
							
								                        ============================================================================""") \
							 | 
						||
| 
								 | 
							
								                        % (e, self.compiler.__class__.__name__)
							 | 
						||
| 
								 | 
							
								                    print(textwrap.dedent("""\
							 | 
						||
| 
								 | 
							
								                        ============================================================================"""))
							 | 
						||
| 
								 | 
							
								                    raise distutils.errors.DistutilsPlatformError(msg) from e
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            # After MSVC is initialized, add an explicit /MANIFEST to linker
							 | 
						||
| 
								 | 
							
								            # flags.  See issues gh-4245 and gh-4101 for details.  Also
							 | 
						||
| 
								 | 
							
								            # relevant are issues 4431 and 16296 on the Python bug tracker.
							 | 
						||
| 
								 | 
							
								            from distutils import msvc9compiler
							 | 
						||
| 
								 | 
							
								            if msvc9compiler.get_build_version() >= 10:
							 | 
						||
| 
								 | 
							
								                for ldflags in [self.compiler.ldflags_shared,
							 | 
						||
| 
								 | 
							
								                                self.compiler.ldflags_shared_debug]:
							 | 
						||
| 
								 | 
							
								                    if '/MANIFEST' not in ldflags:
							 | 
						||
| 
								 | 
							
								                        ldflags.append('/MANIFEST')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if not isinstance(self.fcompiler, FCompiler):
							 | 
						||
| 
								 | 
							
								            self.fcompiler = new_fcompiler(compiler=self.fcompiler,
							 | 
						||
| 
								 | 
							
								                                           dry_run=self.dry_run, force=1,
							 | 
						||
| 
								 | 
							
								                                           c_compiler=self.compiler)
							 | 
						||
| 
								 | 
							
								            if self.fcompiler is not None:
							 | 
						||
| 
								 | 
							
								                self.fcompiler.customize(self.distribution)
							 | 
						||
| 
								 | 
							
								                if self.fcompiler.get_version():
							 | 
						||
| 
								 | 
							
								                    self.fcompiler.customize_cmd(self)
							 | 
						||
| 
								 | 
							
								                    self.fcompiler.show_customization()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _wrap_method(self, mth, lang, args):
							 | 
						||
| 
								 | 
							
								        from distutils.ccompiler import CompileError
							 | 
						||
| 
								 | 
							
								        from distutils.errors import DistutilsExecError
							 | 
						||
| 
								 | 
							
								        save_compiler = self.compiler
							 | 
						||
| 
								 | 
							
								        if lang in ['f77', 'f90']:
							 | 
						||
| 
								 | 
							
								            self.compiler = self.fcompiler
							 | 
						||
| 
								 | 
							
								        if self.compiler is None:
							 | 
						||
| 
								 | 
							
								            raise CompileError('%s compiler is not set' % (lang,))
							 | 
						||
| 
								 | 
							
								        try:
							 | 
						||
| 
								 | 
							
								            ret = mth(*((self,)+args))
							 | 
						||
| 
								 | 
							
								        except (DistutilsExecError, CompileError) as e:
							 | 
						||
| 
								 | 
							
								            self.compiler = save_compiler
							 | 
						||
| 
								 | 
							
								            raise CompileError from e
							 | 
						||
| 
								 | 
							
								        self.compiler = save_compiler
							 | 
						||
| 
								 | 
							
								        return ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _compile (self, body, headers, include_dirs, lang):
							 | 
						||
| 
								 | 
							
								        src, obj = self._wrap_method(old_config._compile, lang,
							 | 
						||
| 
								 | 
							
								                                     (body, headers, include_dirs, lang))
							 | 
						||
| 
								 | 
							
								        # _compile in unixcompiler.py sometimes creates .d dependency files.
							 | 
						||
| 
								 | 
							
								        # Clean them up.
							 | 
						||
| 
								 | 
							
								        self.temp_files.append(obj + '.d')
							 | 
						||
| 
								 | 
							
								        return src, obj
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _link (self, body,
							 | 
						||
| 
								 | 
							
								               headers, include_dirs,
							 | 
						||
| 
								 | 
							
								               libraries, library_dirs, lang):
							 | 
						||
| 
								 | 
							
								        if self.compiler.compiler_type=='msvc':
							 | 
						||
| 
								 | 
							
								            libraries = (libraries or [])[:]
							 | 
						||
| 
								 | 
							
								            library_dirs = (library_dirs or [])[:]
							 | 
						||
| 
								 | 
							
								            if lang in ['f77', 'f90']:
							 | 
						||
| 
								 | 
							
								                lang = 'c' # always use system linker when using MSVC compiler
							 | 
						||
| 
								 | 
							
								                if self.fcompiler:
							 | 
						||
| 
								 | 
							
								                    for d in self.fcompiler.library_dirs or []:
							 | 
						||
| 
								 | 
							
								                        # correct path when compiling in Cygwin but with
							 | 
						||
| 
								 | 
							
								                        # normal Win Python
							 | 
						||
| 
								 | 
							
								                        if d.startswith('/usr/lib'):
							 | 
						||
| 
								 | 
							
								                            try:
							 | 
						||
| 
								 | 
							
								                                d = subprocess.check_output(['cygpath',
							 | 
						||
| 
								 | 
							
								                                                             '-w', d])
							 | 
						||
| 
								 | 
							
								                            except (OSError, subprocess.CalledProcessError):
							 | 
						||
| 
								 | 
							
								                                pass
							 | 
						||
| 
								 | 
							
								                            else:
							 | 
						||
| 
								 | 
							
								                                d = filepath_from_subprocess_output(d)
							 | 
						||
| 
								 | 
							
								                        library_dirs.append(d)
							 | 
						||
| 
								 | 
							
								                    for libname in self.fcompiler.libraries or []:
							 | 
						||
| 
								 | 
							
								                        if libname not in libraries:
							 | 
						||
| 
								 | 
							
								                            libraries.append(libname)
							 | 
						||
| 
								 | 
							
								            for libname in libraries:
							 | 
						||
| 
								 | 
							
								                if libname.startswith('msvc'): continue
							 | 
						||
| 
								 | 
							
								                fileexists = False
							 | 
						||
| 
								 | 
							
								                for libdir in library_dirs or []:
							 | 
						||
| 
								 | 
							
								                    libfile = os.path.join(libdir, '%s.lib' % (libname))
							 | 
						||
| 
								 | 
							
								                    if os.path.isfile(libfile):
							 | 
						||
| 
								 | 
							
								                        fileexists = True
							 | 
						||
| 
								 | 
							
								                        break
							 | 
						||
| 
								 | 
							
								                if fileexists: continue
							 | 
						||
| 
								 | 
							
								                # make g77-compiled static libs available to MSVC
							 | 
						||
| 
								 | 
							
								                fileexists = False
							 | 
						||
| 
								 | 
							
								                for libdir in library_dirs:
							 | 
						||
| 
								 | 
							
								                    libfile = os.path.join(libdir, 'lib%s.a' % (libname))
							 | 
						||
| 
								 | 
							
								                    if os.path.isfile(libfile):
							 | 
						||
| 
								 | 
							
								                        # copy libname.a file to name.lib so that MSVC linker
							 | 
						||
| 
								 | 
							
								                        # can find it
							 | 
						||
| 
								 | 
							
								                        libfile2 = os.path.join(libdir, '%s.lib' % (libname))
							 | 
						||
| 
								 | 
							
								                        copy_file(libfile, libfile2)
							 | 
						||
| 
								 | 
							
								                        self.temp_files.append(libfile2)
							 | 
						||
| 
								 | 
							
								                        fileexists = True
							 | 
						||
| 
								 | 
							
								                        break
							 | 
						||
| 
								 | 
							
								                if fileexists: continue
							 | 
						||
| 
								 | 
							
								                log.warn('could not find library %r in directories %s' \
							 | 
						||
| 
								 | 
							
								                         % (libname, library_dirs))
							 | 
						||
| 
								 | 
							
								        elif self.compiler.compiler_type == 'mingw32':
							 | 
						||
| 
								 | 
							
								            generate_manifest(self)
							 | 
						||
| 
								 | 
							
								        return self._wrap_method(old_config._link, lang,
							 | 
						||
| 
								 | 
							
								                                 (body, headers, include_dirs,
							 | 
						||
| 
								 | 
							
								                                  libraries, library_dirs, lang))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def check_header(self, header, include_dirs=None, library_dirs=None, lang='c'):
							 | 
						||
| 
								 | 
							
								        self._check_compiler()
							 | 
						||
| 
								 | 
							
								        return self.try_compile(
							 | 
						||
| 
								 | 
							
								                "/* we need a dummy line to make distutils happy */",
							 | 
						||
| 
								 | 
							
								                [header], include_dirs)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def check_decl(self, symbol,
							 | 
						||
| 
								 | 
							
								                   headers=None, include_dirs=None):
							 | 
						||
| 
								 | 
							
								        self._check_compiler()
							 | 
						||
| 
								 | 
							
								        body = textwrap.dedent("""
							 | 
						||
| 
								 | 
							
								            int main(void)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								            #ifndef %s
							 | 
						||
| 
								 | 
							
								                (void) %s;
							 | 
						||
| 
								 | 
							
								            #endif
							 | 
						||
| 
								 | 
							
								                ;
							 | 
						||
| 
								 | 
							
								                return 0;
							 | 
						||
| 
								 | 
							
								            }""") % (symbol, symbol)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return self.try_compile(body, headers, include_dirs)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def check_macro_true(self, symbol,
							 | 
						||
| 
								 | 
							
								                         headers=None, include_dirs=None):
							 | 
						||
| 
								 | 
							
								        self._check_compiler()
							 | 
						||
| 
								 | 
							
								        body = textwrap.dedent("""
							 | 
						||
| 
								 | 
							
								            int main(void)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								            #if %s
							 | 
						||
| 
								 | 
							
								            #else
							 | 
						||
| 
								 | 
							
								            #error false or undefined macro
							 | 
						||
| 
								 | 
							
								            #endif
							 | 
						||
| 
								 | 
							
								                ;
							 | 
						||
| 
								 | 
							
								                return 0;
							 | 
						||
| 
								 | 
							
								            }""") % (symbol,)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return self.try_compile(body, headers, include_dirs)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def check_type(self, type_name, headers=None, include_dirs=None,
							 | 
						||
| 
								 | 
							
								            library_dirs=None):
							 | 
						||
| 
								 | 
							
								        """Check type availability. Return True if the type can be compiled,
							 | 
						||
| 
								 | 
							
								        False otherwise"""
							 | 
						||
| 
								 | 
							
								        self._check_compiler()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # First check the type can be compiled
							 | 
						||
| 
								 | 
							
								        body = textwrap.dedent(r"""
							 | 
						||
| 
								 | 
							
								            int main(void) {
							 | 
						||
| 
								 | 
							
								              if ((%(name)s *) 0)
							 | 
						||
| 
								 | 
							
								                return 0;
							 | 
						||
| 
								 | 
							
								              if (sizeof (%(name)s))
							 | 
						||
| 
								 | 
							
								                return 0;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            """) % {'name': type_name}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        st = False
							 | 
						||
| 
								 | 
							
								        try:
							 | 
						||
| 
								 | 
							
								            try:
							 | 
						||
| 
								 | 
							
								                self._compile(body % {'type': type_name},
							 | 
						||
| 
								 | 
							
								                        headers, include_dirs, 'c')
							 | 
						||
| 
								 | 
							
								                st = True
							 | 
						||
| 
								 | 
							
								            except distutils.errors.CompileError:
							 | 
						||
| 
								 | 
							
								                st = False
							 | 
						||
| 
								 | 
							
								        finally:
							 | 
						||
| 
								 | 
							
								            self._clean()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return st
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def check_type_size(self, type_name, headers=None, include_dirs=None, library_dirs=None, expected=None):
							 | 
						||
| 
								 | 
							
								        """Check size of a given type."""
							 | 
						||
| 
								 | 
							
								        self._check_compiler()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # First check the type can be compiled
							 | 
						||
| 
								 | 
							
								        body = textwrap.dedent(r"""
							 | 
						||
| 
								 | 
							
								            typedef %(type)s npy_check_sizeof_type;
							 | 
						||
| 
								 | 
							
								            int main (void)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                static int test_array [1 - 2 * !(((long) (sizeof (npy_check_sizeof_type))) >= 0)];
							 | 
						||
| 
								 | 
							
								                test_array [0] = 0
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                ;
							 | 
						||
| 
								 | 
							
								                return 0;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            """)
							 | 
						||
| 
								 | 
							
								        self._compile(body % {'type': type_name},
							 | 
						||
| 
								 | 
							
								                headers, include_dirs, 'c')
							 | 
						||
| 
								 | 
							
								        self._clean()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if expected:
							 | 
						||
| 
								 | 
							
								            body = textwrap.dedent(r"""
							 | 
						||
| 
								 | 
							
								                typedef %(type)s npy_check_sizeof_type;
							 | 
						||
| 
								 | 
							
								                int main (void)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    static int test_array [1 - 2 * !(((long) (sizeof (npy_check_sizeof_type))) == %(size)s)];
							 | 
						||
| 
								 | 
							
								                    test_array [0] = 0
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    ;
							 | 
						||
| 
								 | 
							
								                    return 0;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                """)
							 | 
						||
| 
								 | 
							
								            for size in expected:
							 | 
						||
| 
								 | 
							
								                try:
							 | 
						||
| 
								 | 
							
								                    self._compile(body % {'type': type_name, 'size': size},
							 | 
						||
| 
								 | 
							
								                            headers, include_dirs, 'c')
							 | 
						||
| 
								 | 
							
								                    self._clean()
							 | 
						||
| 
								 | 
							
								                    return size
							 | 
						||
| 
								 | 
							
								                except CompileError:
							 | 
						||
| 
								 | 
							
								                    pass
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # this fails to *compile* if size > sizeof(type)
							 | 
						||
| 
								 | 
							
								        body = textwrap.dedent(r"""
							 | 
						||
| 
								 | 
							
								            typedef %(type)s npy_check_sizeof_type;
							 | 
						||
| 
								 | 
							
								            int main (void)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                static int test_array [1 - 2 * !(((long) (sizeof (npy_check_sizeof_type))) <= %(size)s)];
							 | 
						||
| 
								 | 
							
								                test_array [0] = 0
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                ;
							 | 
						||
| 
								 | 
							
								                return 0;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            """)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # The principle is simple: we first find low and high bounds of size
							 | 
						||
| 
								 | 
							
								        # for the type, where low/high are looked up on a log scale. Then, we
							 | 
						||
| 
								 | 
							
								        # do a binary search to find the exact size between low and high
							 | 
						||
| 
								 | 
							
								        low = 0
							 | 
						||
| 
								 | 
							
								        mid = 0
							 | 
						||
| 
								 | 
							
								        while True:
							 | 
						||
| 
								 | 
							
								            try:
							 | 
						||
| 
								 | 
							
								                self._compile(body % {'type': type_name, 'size': mid},
							 | 
						||
| 
								 | 
							
								                        headers, include_dirs, 'c')
							 | 
						||
| 
								 | 
							
								                self._clean()
							 | 
						||
| 
								 | 
							
								                break
							 | 
						||
| 
								 | 
							
								            except CompileError:
							 | 
						||
| 
								 | 
							
								                #log.info("failure to test for bound %d" % mid)
							 | 
						||
| 
								 | 
							
								                low = mid + 1
							 | 
						||
| 
								 | 
							
								                mid = 2 * mid + 1
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        high = mid
							 | 
						||
| 
								 | 
							
								        # Binary search:
							 | 
						||
| 
								 | 
							
								        while low != high:
							 | 
						||
| 
								 | 
							
								            mid = (high - low) // 2 + low
							 | 
						||
| 
								 | 
							
								            try:
							 | 
						||
| 
								 | 
							
								                self._compile(body % {'type': type_name, 'size': mid},
							 | 
						||
| 
								 | 
							
								                        headers, include_dirs, 'c')
							 | 
						||
| 
								 | 
							
								                self._clean()
							 | 
						||
| 
								 | 
							
								                high = mid
							 | 
						||
| 
								 | 
							
								            except CompileError:
							 | 
						||
| 
								 | 
							
								                low = mid + 1
							 | 
						||
| 
								 | 
							
								        return low
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def check_func(self, func,
							 | 
						||
| 
								 | 
							
								                   headers=None, include_dirs=None,
							 | 
						||
| 
								 | 
							
								                   libraries=None, library_dirs=None,
							 | 
						||
| 
								 | 
							
								                   decl=False, call=False, call_args=None):
							 | 
						||
| 
								 | 
							
								        # clean up distutils's config a bit: add void to main(), and
							 | 
						||
| 
								 | 
							
								        # return a value.
							 | 
						||
| 
								 | 
							
								        self._check_compiler()
							 | 
						||
| 
								 | 
							
								        body = []
							 | 
						||
| 
								 | 
							
								        if decl:
							 | 
						||
| 
								 | 
							
								            if type(decl) == str:
							 | 
						||
| 
								 | 
							
								                body.append(decl)
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                body.append("int %s (void);" % func)
							 | 
						||
| 
								 | 
							
								        # Handle MSVC intrinsics: force MS compiler to make a function call.
							 | 
						||
| 
								 | 
							
								        # Useful to test for some functions when built with optimization on, to
							 | 
						||
| 
								 | 
							
								        # avoid build error because the intrinsic and our 'fake' test
							 | 
						||
| 
								 | 
							
								        # declaration do not match.
							 | 
						||
| 
								 | 
							
								        body.append("#ifdef _MSC_VER")
							 | 
						||
| 
								 | 
							
								        body.append("#pragma function(%s)" % func)
							 | 
						||
| 
								 | 
							
								        body.append("#endif")
							 | 
						||
| 
								 | 
							
								        body.append("int main (void) {")
							 | 
						||
| 
								 | 
							
								        if call:
							 | 
						||
| 
								 | 
							
								            if call_args is None:
							 | 
						||
| 
								 | 
							
								                call_args = ''
							 | 
						||
| 
								 | 
							
								            body.append("  %s(%s);" % (func, call_args))
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            body.append("  %s;" % func)
							 | 
						||
| 
								 | 
							
								        body.append("  return 0;")
							 | 
						||
| 
								 | 
							
								        body.append("}")
							 | 
						||
| 
								 | 
							
								        body = '\n'.join(body) + "\n"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return self.try_link(body, headers, include_dirs,
							 | 
						||
| 
								 | 
							
								                             libraries, library_dirs)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def check_funcs_once(self, funcs,
							 | 
						||
| 
								 | 
							
								                   headers=None, include_dirs=None,
							 | 
						||
| 
								 | 
							
								                   libraries=None, library_dirs=None,
							 | 
						||
| 
								 | 
							
								                   decl=False, call=False, call_args=None):
							 | 
						||
| 
								 | 
							
								        """Check a list of functions at once.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        This is useful to speed up things, since all the functions in the funcs
							 | 
						||
| 
								 | 
							
								        list will be put in one compilation unit.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Arguments
							 | 
						||
| 
								 | 
							
								        ---------
							 | 
						||
| 
								 | 
							
								        funcs : seq
							 | 
						||
| 
								 | 
							
								            list of functions to test
							 | 
						||
| 
								 | 
							
								        include_dirs : seq
							 | 
						||
| 
								 | 
							
								            list of header paths
							 | 
						||
| 
								 | 
							
								        libraries : seq
							 | 
						||
| 
								 | 
							
								            list of libraries to link the code snippet to
							 | 
						||
| 
								 | 
							
								        library_dirs : seq
							 | 
						||
| 
								 | 
							
								            list of library paths
							 | 
						||
| 
								 | 
							
								        decl : dict
							 | 
						||
| 
								 | 
							
								            for every (key, value), the declaration in the value will be
							 | 
						||
| 
								 | 
							
								            used for function in key. If a function is not in the
							 | 
						||
| 
								 | 
							
								            dictionary, no declaration will be used.
							 | 
						||
| 
								 | 
							
								        call : dict
							 | 
						||
| 
								 | 
							
								            for every item (f, value), if the value is True, a call will be
							 | 
						||
| 
								 | 
							
								            done to the function f.
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        self._check_compiler()
							 | 
						||
| 
								 | 
							
								        body = []
							 | 
						||
| 
								 | 
							
								        if decl:
							 | 
						||
| 
								 | 
							
								            for f, v in decl.items():
							 | 
						||
| 
								 | 
							
								                if v:
							 | 
						||
| 
								 | 
							
								                    body.append("int %s (void);" % f)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # Handle MS intrinsics. See check_func for more info.
							 | 
						||
| 
								 | 
							
								        body.append("#ifdef _MSC_VER")
							 | 
						||
| 
								 | 
							
								        for func in funcs:
							 | 
						||
| 
								 | 
							
								            body.append("#pragma function(%s)" % func)
							 | 
						||
| 
								 | 
							
								        body.append("#endif")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        body.append("int main (void) {")
							 | 
						||
| 
								 | 
							
								        if call:
							 | 
						||
| 
								 | 
							
								            for f in funcs:
							 | 
						||
| 
								 | 
							
								                if f in call and call[f]:
							 | 
						||
| 
								 | 
							
								                    if not (call_args and f in call_args and call_args[f]):
							 | 
						||
| 
								 | 
							
								                        args = ''
							 | 
						||
| 
								 | 
							
								                    else:
							 | 
						||
| 
								 | 
							
								                        args = call_args[f]
							 | 
						||
| 
								 | 
							
								                    body.append("  %s(%s);" % (f, args))
							 | 
						||
| 
								 | 
							
								                else:
							 | 
						||
| 
								 | 
							
								                    body.append("  %s;" % f)
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            for f in funcs:
							 | 
						||
| 
								 | 
							
								                body.append("  %s;" % f)
							 | 
						||
| 
								 | 
							
								        body.append("  return 0;")
							 | 
						||
| 
								 | 
							
								        body.append("}")
							 | 
						||
| 
								 | 
							
								        body = '\n'.join(body) + "\n"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return self.try_link(body, headers, include_dirs,
							 | 
						||
| 
								 | 
							
								                             libraries, library_dirs)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def check_inline(self):
							 | 
						||
| 
								 | 
							
								        """Return the inline keyword recognized by the compiler, empty string
							 | 
						||
| 
								 | 
							
								        otherwise."""
							 | 
						||
| 
								 | 
							
								        return check_inline(self)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def check_restrict(self):
							 | 
						||
| 
								 | 
							
								        """Return the restrict keyword recognized by the compiler, empty string
							 | 
						||
| 
								 | 
							
								        otherwise."""
							 | 
						||
| 
								 | 
							
								        return check_restrict(self)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def check_compiler_gcc(self):
							 | 
						||
| 
								 | 
							
								        """Return True if the C compiler is gcc"""
							 | 
						||
| 
								 | 
							
								        return check_compiler_gcc(self)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def check_gcc_function_attribute(self, attribute, name):
							 | 
						||
| 
								 | 
							
								        return check_gcc_function_attribute(self, attribute, name)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def check_gcc_function_attribute_with_intrinsics(self, attribute, name,
							 | 
						||
| 
								 | 
							
								                                                     code, include):
							 | 
						||
| 
								 | 
							
								        return check_gcc_function_attribute_with_intrinsics(self, attribute,
							 | 
						||
| 
								 | 
							
								                                                            name, code, include)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def check_gcc_variable_attribute(self, attribute):
							 | 
						||
| 
								 | 
							
								        return check_gcc_variable_attribute(self, attribute)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def check_gcc_version_at_least(self, major, minor=0, patchlevel=0):
							 | 
						||
| 
								 | 
							
								        """Return True if the GCC version is greater than or equal to the
							 | 
						||
| 
								 | 
							
								        specified version."""
							 | 
						||
| 
								 | 
							
								        return check_gcc_version_at_least(self, major, minor, patchlevel)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def get_output(self, body, headers=None, include_dirs=None,
							 | 
						||
| 
								 | 
							
								                   libraries=None, library_dirs=None,
							 | 
						||
| 
								 | 
							
								                   lang="c", use_tee=None):
							 | 
						||
| 
								 | 
							
								        """Try to compile, link to an executable, and run a program
							 | 
						||
| 
								 | 
							
								        built from 'body' and 'headers'. Returns the exit status code
							 | 
						||
| 
								 | 
							
								        of the program and its output.
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        # 2008-11-16, RemoveMe
							 | 
						||
| 
								 | 
							
								        warnings.warn("\n+++++++++++++++++++++++++++++++++++++++++++++++++\n"
							 | 
						||
| 
								 | 
							
								                      "Usage of get_output is deprecated: please do not \n"
							 | 
						||
| 
								 | 
							
								                      "use it anymore, and avoid configuration checks \n"
							 | 
						||
| 
								 | 
							
								                      "involving running executable on the target machine.\n"
							 | 
						||
| 
								 | 
							
								                      "+++++++++++++++++++++++++++++++++++++++++++++++++\n",
							 | 
						||
| 
								 | 
							
								                      DeprecationWarning, stacklevel=2)
							 | 
						||
| 
								 | 
							
								        self._check_compiler()
							 | 
						||
| 
								 | 
							
								        exitcode, output = 255, ''
							 | 
						||
| 
								 | 
							
								        try:
							 | 
						||
| 
								 | 
							
								            grabber = GrabStdout()
							 | 
						||
| 
								 | 
							
								            try:
							 | 
						||
| 
								 | 
							
								                src, obj, exe = self._link(body, headers, include_dirs,
							 | 
						||
| 
								 | 
							
								                                           libraries, library_dirs, lang)
							 | 
						||
| 
								 | 
							
								                grabber.restore()
							 | 
						||
| 
								 | 
							
								            except Exception:
							 | 
						||
| 
								 | 
							
								                output = grabber.data
							 | 
						||
| 
								 | 
							
								                grabber.restore()
							 | 
						||
| 
								 | 
							
								                raise
							 | 
						||
| 
								 | 
							
								            exe = os.path.join('.', exe)
							 | 
						||
| 
								 | 
							
								            try:
							 | 
						||
| 
								 | 
							
								                # specify cwd arg for consistency with
							 | 
						||
| 
								 | 
							
								                # historic usage pattern of exec_command()
							 | 
						||
| 
								 | 
							
								                # also, note that exe appears to be a string,
							 | 
						||
| 
								 | 
							
								                # which exec_command() handled, but we now
							 | 
						||
| 
								 | 
							
								                # use a list for check_output() -- this assumes
							 | 
						||
| 
								 | 
							
								                # that exe is always a single command
							 | 
						||
| 
								 | 
							
								                output = subprocess.check_output([exe], cwd='.')
							 | 
						||
| 
								 | 
							
								            except subprocess.CalledProcessError as exc:
							 | 
						||
| 
								 | 
							
								                exitstatus = exc.returncode
							 | 
						||
| 
								 | 
							
								                output = ''
							 | 
						||
| 
								 | 
							
								            except OSError:
							 | 
						||
| 
								 | 
							
								                # preserve the EnvironmentError exit status
							 | 
						||
| 
								 | 
							
								                # used historically in exec_command()
							 | 
						||
| 
								 | 
							
								                exitstatus = 127
							 | 
						||
| 
								 | 
							
								                output = ''
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                output = filepath_from_subprocess_output(output)
							 | 
						||
| 
								 | 
							
								            if hasattr(os, 'WEXITSTATUS'):
							 | 
						||
| 
								 | 
							
								                exitcode = os.WEXITSTATUS(exitstatus)
							 | 
						||
| 
								 | 
							
								                if os.WIFSIGNALED(exitstatus):
							 | 
						||
| 
								 | 
							
								                    sig = os.WTERMSIG(exitstatus)
							 | 
						||
| 
								 | 
							
								                    log.error('subprocess exited with signal %d' % (sig,))
							 | 
						||
| 
								 | 
							
								                    if sig == signal.SIGINT:
							 | 
						||
| 
								 | 
							
								                        # control-C
							 | 
						||
| 
								 | 
							
								                        raise KeyboardInterrupt
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                exitcode = exitstatus
							 | 
						||
| 
								 | 
							
								            log.info("success!")
							 | 
						||
| 
								 | 
							
								        except (CompileError, LinkError):
							 | 
						||
| 
								 | 
							
								            log.info("failure.")
							 | 
						||
| 
								 | 
							
								        self._clean()
							 | 
						||
| 
								 | 
							
								        return exitcode, output
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class GrabStdout:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __init__(self):
							 | 
						||
| 
								 | 
							
								        self.sys_stdout = sys.stdout
							 | 
						||
| 
								 | 
							
								        self.data = ''
							 | 
						||
| 
								 | 
							
								        sys.stdout = self
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def write (self, data):
							 | 
						||
| 
								 | 
							
								        self.sys_stdout.write(data)
							 | 
						||
| 
								 | 
							
								        self.data += data
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def flush (self):
							 | 
						||
| 
								 | 
							
								        self.sys_stdout.flush()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def restore(self):
							 | 
						||
| 
								 | 
							
								        sys.stdout = self.sys_stdout
							 |