Source code for pyccel.codegen.utilities

# coding: utf-8

"""
This file contains some useful functions to compile the generated fortran code
"""

import os
import subprocess

from pyccel.parser.errors import Errors
from pyccel.parser import Parser
from pyccel.codegen import Codegen

# TODO use constructor and a dict to map flags w.r.t the compiler
_avail_compilers = ['gfortran', 'mpif90', 'pgfortran', 'ifort']

# TODO add opt flags, etc... look at f2py interface in numpy
[docs]def construct_flags(compiler, fflags=None, debug=False, accelerator=None, include=[], libdir=[]): """ Constructs compiling flags for a given compiler. fflags: str Fortran compiler flags. Default is `-O3` compiler: str used compiler for the target language. accelerator: str name of the selected accelerator. One among ('openmp', 'openacc') debug: bool add some useful prints that may help for debugging. include: list list of include directories paths libdir: list list of lib directories paths """ if not(compiler in _avail_compilers): raise ValueError("Only {0} are available.".format(_avail_compilers)) if not fflags: fflags = '-O3' # make sure there are spaces flags = " {} ".format(fflags) if compiler == "gfortran": if debug: flags += " -fbounds-check " if compiler == "mpif90": if debug: flags += " -fbounds-check " if not (accelerator is None): if accelerator == "openmp": flags += " -fopenmp " elif accelerator == "openacc": flags += " -ta=multicore -Minfo=accel " else: raise ValueError("Only openmp and openacc are available") if isinstance(include, str): include = [include] if len(include) > 0: flags += ' '.join(' -I{0}'.format(i) for i in include) if isinstance(libdir, str): libdir = [libdir] if len(libdir) > 0: flags += ' '.join(' -L{0}'.format(i) for i in libdir) return flags
[docs]def compile_fortran(filename, compiler, flags, binary=None, verbose=False, modules=[], is_module=False, libs=[], output=''): """ Compiles the generated file. verbose: bool talk more """ if binary is None: if not is_module: binary = os.path.splitext(os.path.basename(filename))[0] mod_file = '' else: binary = "{folder}{binary}.o".format(folder=output, binary=os.path.splitext(os.path.basename(filename))[0]) mod_file = "{folder}".format(folder=output) o_code = '-o' j_code = '' if is_module: flags += ' -c ' if (len(output)>0): j_code = '-J' m_code = ' '.join('{}.o '.format(m) for m in modules) if isinstance(libs, str): libs = libs.split(',') if len(libs) == 1: libs = libs[0].split(' ') if len(libs) > 0: libs = ' '.join(' -l{0}'.format(i) for i in libs) else: libs = '' cmd = '{0} {1} {2} {3} {4} {5} {6} {7} {8}'.format( \ compiler, flags, m_code, filename, o_code, binary, libs, j_code, mod_file) if verbose: print(cmd) output = subprocess.check_output(cmd, shell=True) if verbose: print(output) # TODO shall we uncomment this? # # write and save a log file in .pyccel/'filename'.log # # ... # def mkdir_p(dir): # # type: (unicode) -> None # if os.path.isdir(dir): # return # os.makedirs(dir) # # if True: # tmp_dir = '.pyccel' # mkdir_p(tmp_dir) # logfile = '{0}.log'.format(binary) # logfile = os.path.join(tmp_dir, logfile) # f = open(logfile, 'w') # f.write(output) # f.close() return output, cmd
# ... # ...
[docs]def execute_pyccel(filename, compiler=None, fflags=None, debug=False, verbose=False, accelerator=None, include=[], libdir=[], modules=[], libs=[], binary=None, output=''): """Executes the full process: - parsing the python code - annotating the python code - converting from python to fortran - compiling the fortran code. """ pyccel = Parser(filename,output_folder=output.replace('/','.')) ast = pyccel.parse() settings = {} ast = pyccel.annotate(**settings) name = os.path.basename(filename) name = os.path.splitext(name)[0] codegen = Codegen(ast, name) code = codegen.doprint() fname = codegen.export(output+name) # reset Errors singleton errors = Errors() errors.reset() # ... constructs the compiler flags if compiler is None: compiler='gfortran' flags = construct_flags(compiler, fflags=fflags, debug=debug, accelerator=accelerator, include=include, libdir=libdir) # ... # ... compile fortran code output, cmd = compile_fortran(fname, compiler, flags, binary=binary, verbose=verbose, modules=modules, is_module=codegen.is_module, output=output, libs=libs) # ... return output, cmd
if __name__ == '__main__': import sys try: filename = sys.argv[1] except: raise ValueError('Expecting an argument for filename') execute_pyccel(filename)