%PDF- %PDF-
Direktori : /lib/python3/dist-packages/pythran/ |
Current File : //lib/python3/dist-packages/pythran/config.py |
try: # python3 vs. python2 from configparser import ConfigParser except ImportError: from ConfigParser import SafeConfigParser as ConfigParser import io import logging import numpy.distutils.system_info as numpy_sys import numpy import os import sys from itertools import product logger = logging.getLogger('pythran') def get_include(): # using / as separator as advised in the distutils doc return (os.path.dirname(os.path.dirname(__file__)) or '.') + '/pythran' class silent(object): ''' Silent sys.stderr at the system level ''' def __enter__(self): try: self.prevfd = os.dup(sys.stderr.fileno()) os.close(sys.stderr.fileno()) except io.UnsupportedOperation: self.prevfd = None self.prevstream = sys.stderr sys.stderr = open(os.devnull, 'r') def __exit__(self, exc_type, exc_value, traceback): sys.stderr.close() sys.stderr = self.prevstream if self.prevfd: os.dup2(self.prevfd, sys.stderr.fileno()) os.close(self.prevfd) def get_paths_cfg( sys_file='pythran.cfg', platform_file='pythran-{}.cfg'.format(sys.platform), user_file='.pythranrc' ): sys_config_dir = os.path.dirname(__file__) sys_config_path = os.path.join(sys_config_dir, sys_file) platform_config_path = os.path.join(sys_config_dir, platform_file) if not os.path.exists(platform_config_path): platform_config_path = os.path.join(sys_config_dir, "pythran-default.cfg") user_config_path = os.environ.get('PYTHRANRC', None) if not user_config_path: user_config_dir = os.environ.get('XDG_CONFIG_HOME', None) if not user_config_dir: user_config_dir = os.environ.get('HOME', None) if not user_config_dir: user_config_dir = '~' user_config_path = os.path.expanduser( os.path.join(user_config_dir, user_file)) return {"sys": sys_config_path, "platform": platform_config_path, "user": user_config_path} def init_cfg(sys_file, platform_file, user_file, config_args=None): paths = get_paths_cfg(sys_file, platform_file, user_file) sys_config_path = paths["sys"] platform_config_path = paths["platform"] user_config_path = paths["user"] cfgp = ConfigParser() for required in (sys_config_path, platform_config_path): cfgp.read([required]) cfgp.read([user_config_path]) if config_args is not None: update_cfg(cfgp, config_args) return cfgp def update_cfg(cfgp, config_args): # Override the config options with those provided on the command line # e.g. compiler.blas=pythran-openblas. for arg in config_args: try: lhs, rhs = arg.split('=', maxsplit=1) section, item = lhs.split('.') if not cfgp.has_section(section): cfgp.add_section(section) cfgp.set(section, item, rhs) except Exception: pass def lint_cfg(cfgp, **paths): if not paths: paths = get_paths_cfg() # Use configuration from sys and platform as "reference" cfgp_ref = ConfigParser() cfgp_ref.read([paths["sys"], paths["platform"]]) # Check if pythran configuration files exists for loc, path in paths.items(): exists = os.path.exists(path) msg = " ".join([ "{} file".format(loc).rjust(13), "exists:" if exists else "does not exist:", path ]) logger.info(msg) if exists else logger.warning(msg) for section in cfgp.sections(): # Check if section in the current configuration exists in the # reference configuration if cfgp_ref.has_section(section): options = set(cfgp.options(section)) options_ref = set(cfgp_ref.options(section)) # Check if the options in the section are supported by the # reference configuration if options.issubset(options_ref): logger.info( ( "pythranrc section [{}] is valid and options are " "correct" ).format(section) ) else: logger.warning( ( "pythranrc section [{}] is valid but options {} " "are incorrect!" ).format(section, options.difference(options_ref)) ) else: logger.warning("pythranrc section [{}] is invalid!" .format(section)) def make_extension(python, **extra): # load platform specific configuration then user configuration cfg = init_cfg('pythran.cfg', 'pythran-{}.cfg'.format(sys.platform), '.pythranrc', extra.get('config', None)) if 'config' in extra: extra.pop('config') def parse_define(define): index = define.find('=') if index < 0: return (define, None) else: return define[:index], define[index + 1:] extension = { "language": "c++", # forcing str conversion to handle Unicode case (the default on MS) "define_macros": [str(x) for x in cfg.get('compiler', 'defines').split()], "undef_macros": [str(x) for x in cfg.get('compiler', 'undefs').split()], "include_dirs": [str(x) for x in cfg.get('compiler', 'include_dirs').split()], "library_dirs": [str(x) for x in cfg.get('compiler', 'library_dirs').split()], "libraries": [str(x) for x in cfg.get('compiler', 'libs').split()], "extra_compile_args": [str(x) for x in cfg.get('compiler', 'cflags').split()], "extra_link_args": [str(x) for x in cfg.get('compiler', 'ldflags').split()], "extra_objects": [] } if python: extension['define_macros'].append('ENABLE_PYTHON_MODULE') extension['define_macros'].append( '__PYTHRAN__={}'.format(sys.version_info.major)) pythonic_dir = get_include() extension["include_dirs"].append(pythonic_dir) extra.pop('language', None) # forced to c++ anyway cxx = extra.pop('cxx', None) cc = extra.pop('cc', None) if cxx is None: cxx = compiler() if cxx is not None: extension['cxx'] = cxx extension['cc'] = cc or cxx # Honor CXXFLAGS (note: Pythran calls this `cflags` everywhere, however the # standard environment variable is `CXXFLAGS` not `CFLAGS`). cflags = os.environ.get('CXXFLAGS', None) if cflags is not None: extension['extra_compile_args'].extend(cflags.split()) # Honor LDFLAGS ldflags = os.environ.get('LDFLAGS', None) if ldflags is not None: extension['extra_link_args'].extend(ldflags.split()) for k, w in extra.items(): extension[k].extend(w) if cfg.getboolean('pythran', 'complex_hook'): # the patch is *not* portable extension["include_dirs"].append(pythonic_dir + '/pythonic/patch') # numpy specific if python: extension['include_dirs'].append(numpy.get_include()) # blas dependency reserved_blas_entries = 'pythran-openblas', 'none' user_blas = cfg.get('compiler', 'blas') if user_blas == 'pythran-openblas': try: import pythran_openblas as openblas # required to cope with atlas missing extern "C" extension['define_macros'].append('PYTHRAN_BLAS_OPENBLAS') extension['include_dirs'].extend(openblas.include_dirs) extension['extra_objects'].append( os.path.join(openblas.library_dir, openblas.static_library) ) except ImportError: logger.warning("Failed to find 'pythran-openblas' package. " "Please install it or change the compiler.blas " "setting. Defaulting to 'blas'") user_blas = 'blas' elif user_blas == 'none': extension['define_macros'].append('PYTHRAN_BLAS_NONE') if user_blas not in reserved_blas_entries: # Numpy can pollute stdout with checks with silent(): numpy_blas = numpy_sys.get_info(user_blas) # Potential paths of the atlas libraries. library_files = [os.path.join(dir, "lib{}.so".format(lib)) for dir, lib in product(numpy_blas["library_dirs"], numpy_blas["libraries"])] if any('atlas' in os.path.realpath(f) for f in library_files): extension['define_macros'].append('PYTHRAN_BLAS_ATLAS') else: # required to cope with atlas missing extern "C" extension['define_macros'].append('PYTHRAN_BLAS_{}' .format(user_blas.upper())) extension['libraries'].extend(numpy_blas.get('libraries', [])) extension['library_dirs'].extend( numpy_blas.get('library_dirs', [])) extension['include_dirs'].extend( numpy_blas.get('include_dirs', [])) # final macro normalization extension["define_macros"] = [ dm if isinstance(dm, tuple) else parse_define(dm) for dm in extension["define_macros"]] return extension def compiler(): """Get compiler to use for C++ to binary process. The precedence for choosing the compiler is as follows:: 1. `CXX` environment variable 2. User configuration (~/.pythranrc) Returns None if none is set or if it's set to the empty string """ cfg_cxx = str(cfg.get('compiler', 'CXX')) if not cfg_cxx: cfg_cxx = None return os.environ.get('CXX', cfg_cxx) or None # load platform specific configuration then user configuration cfg = init_cfg('pythran.cfg', 'pythran-{}.cfg'.format(sys.platform), '.pythranrc') def run(): ''' Dump on stdout the config flags required to compile pythran-generated code. ''' import argparse import distutils.ccompiler import distutils.sysconfig import pythran import numpy parser = argparse.ArgumentParser( prog='pythran-config', description='output build options for pythran-generated code', epilog="It's a megablast!" ) parser.add_argument('--compiler', action='store_true', help='print default compiler') parser.add_argument('--cflags', action='store_true', help='print compilation flags') parser.add_argument('--libs', action='store_true', help='print linker flags') parser.add_argument('--no-python', action='store_true', help='do not include Python-related flags') parser.add_argument('--verbose', '-v', action='count', default=0, help=( 'verbose mode: [-v] prints warnings if pythranrc ' 'has an invalid configuration; use ' '[-vv] for more information') ) args = parser.parse_args(sys.argv[1:]) args.python = not args.no_python output = [] extension = pythran.config.make_extension(python=args.python) if args.verbose >= 1: if args.verbose == 1: logger.setLevel(logging.WARNING) else: logger.setLevel(logging.INFO) lint_cfg(cfg) if args.compiler or args.verbose >= 2: cxx = compiler() or 'c++' logger.info('CXX = '.rjust(10) + cxx) if args.compiler: output.append(cxx) compiler_obj = distutils.ccompiler.new_compiler() distutils.sysconfig.customize_compiler(compiler_obj) if args.cflags or args.verbose >= 2: def fmt_define(define): name, value = define if value is None: return '-D' + name else: return '-D' + name + '=' + value cflags = [] cflags.extend(fmt_define(define) for define in extension['define_macros']) cflags.extend(('-I' + include) for include in extension['include_dirs']) if args.python: cflags.append('-I' + numpy.get_include()) cflags.append('-I' + distutils.sysconfig.get_python_inc()) logger.info('CXXFLAGS = '.rjust(10) + ' '.join(cflags)) if args.cflags: output.extend(cflags) if args.libs or args.verbose >= 2: ldflags = [] ldflags.extend((compiler_obj.library_dir_option(include)) for include in extension['library_dirs']) ldflags.extend((compiler_obj.library_option(include)) for include in extension['libraries']) if args.python: ldflags.append(compiler_obj.library_dir_option(distutils.sysconfig.get_config_var('LIBPL'))) ldflags.extend(distutils.sysconfig.get_config_var('LIBS').split()) ldflags.append(compiler_obj.library_option('python') + distutils.sysconfig.get_config_var('VERSION')) logger.info('LDFLAGS = '.rjust(10) + ' '.join(ldflags)) if args.libs: output.extend(ldflags) if output: print(' '.join(output)) if __name__ == '__main__': run()