Example #1
0
 def _get_static_function(self, used_names, function, collect_dict):
     """
     Create arguments and functioncall for arguments rank > 0 in fortran.
     Format : a is numpy array
     func(a) ==> static_func(a.DIM , a.DATA)
     where a.DATA = buffer holding data
           a.DIM = size of array
     """
     additional_body = []
     if self._target_language == 'fortran':
         static_args = []
         for a in function.arguments:
             if isinstance(a, Variable) and a.rank > 0:
                 # Add shape arguments for static function
                 for i in range(collect_dict[a].rank):
                     var = Variable(dtype=NativeInteger(),
                                    name=self.get_new_name(
                                        used_names, a.name + "_dim"))
                     body = FunctionCall(numpy_get_dim,
                                         [collect_dict[a], i])
                     if a.is_optional:
                         body = IfTernaryOperator(
                             VariableAddress(collect_dict[a]), body,
                             LiteralInteger(0))
                     body = Assign(var, body)
                     additional_body.append(body)
                     static_args.append(var)
             static_args.append(a)
         static_function = as_static_function_call(function,
                                                   self._module_name,
                                                   name=function.name)
     else:
         static_function = function
         static_args = function.arguments
     return static_function, static_args, additional_body
Example #2
0
    def _print_Module(self, expr):
        self._global_names = set(f.name.name for f in expr.funcs)
        self._module_name = expr.name
        sep = self._print(SeparatorComment(40))
        if self._target_language == 'fortran':
            static_funcs = [
                as_static_function_call(f, expr.name, name=f.name)
                for f in expr.funcs
            ]
        else:
            static_funcs = expr.funcs
        function_signatures = '\n'.join(
            '{};'.format(self.function_signature(f)) for f in static_funcs)

        interfaces = expr.interfaces
        interface_funcs = [f.name for i in interfaces for f in i.functions]
        funcs = interfaces + [
            f for f in expr.funcs if f.name not in interface_funcs
        ]

        function_defs = '\n\n'.join(self._print(f) for f in funcs)
        cast_functions = '\n\n'.join(
            CCodePrinter._print_FunctionDef(self, f)
            for f in self._cast_functions_dict.values())
        method_def_func = ',\n'.join(('{{\n'
                                     '"{name}",\n'
                                     '(PyCFunction){wrapper_name},\n'
                                     'METH_VARARGS | METH_KEYWORDS,\n'
                                     '{doc_string}\n'
                                     '}}').format(
                                            name = f.name,
                                            wrapper_name = self._function_wrapper_names[f.name],
                                            doc_string = self._print(LiteralString('\n'.join(f.doc_string.comments))) \
                                                        if f.doc_string else '""')
                                     for f in funcs)

        method_def_name = self.get_new_name(self._global_names,
                                            '{}_methods'.format(expr.name))
        method_def = ('static PyMethodDef {method_def_name}[] = {{\n'
                      '{method_def_func},\n'
                      '{{ NULL, NULL, 0, NULL}}\n'
                      '}};'.format(method_def_name=method_def_name,
                                   method_def_func=method_def_func))

        module_def_name = self.get_new_name(self._global_names,
                                            '{}_module'.format(expr.name))
        module_def = (
            'static struct PyModuleDef {module_def_name} = {{\n'
            'PyModuleDef_HEAD_INIT,\n'
            '/* name of module */\n'
            '\"{mod_name}\",\n'
            '/* module documentation, may be NULL */\n'
            'NULL,\n'  #TODO: Add documentation
            '/* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */\n'
            '-1,\n'
            '{method_def_name}\n'
            '}};'.format(module_def_name=module_def_name,
                         mod_name=expr.name,
                         method_def_name=method_def_name))

        init_func = ('PyMODINIT_FUNC PyInit_{mod_name}(void)\n{{\n'
                     'PyObject *m;\n\n'
                     'import_array();\n\n'
                     'm = PyModule_Create(&{module_def_name});\n'
                     'if (m == NULL) return NULL;\n\n'
                     'return m;\n}}'.format(mod_name=expr.name,
                                            module_def_name=module_def_name))

        # Print imports last to be sure that all additional_imports have been collected
        imports = [Import(s) for s in self._additional_imports]
        imports += [Import('Python')]
        imports += [Import('numpy/arrayobject')]
        imports = '\n'.join(self._print(i) for i in imports)

        numpy_max_acceptable_version = [1, 19]
        numpy_current_version = [
            int(v) for v in np.version.version.split('.')[:2]
        ]
        numpy_api_macro = '#define NPY_NO_DEPRECATED_API NPY_{}_{}_API_VERSION'.format(
            min(numpy_max_acceptable_version[0], numpy_current_version[0]),
            min(numpy_max_acceptable_version[1], numpy_current_version[1]))

        return ('#define PY_SSIZE_T_CLEAN\n'
                '{numpy_api_macro}\n'
                '{imports}\n\n'
                '{function_signatures}\n\n'
                '{sep}\n\n'
                '{cast_functions}\n\n'
                '{sep}\n\n'
                '{function_defs}\n\n'
                '{method_def}\n\n'
                '{sep}\n\n'
                '{module_def}\n\n'
                '{sep}\n\n'
                '{init_func}\n'.format(numpy_api_macro=numpy_api_macro,
                                       imports=imports,
                                       function_signatures=function_signatures,
                                       sep=sep,
                                       cast_functions=cast_functions,
                                       function_defs=function_defs,
                                       method_def=method_def,
                                       module_def=module_def,
                                       init_func=init_func))
Example #3
0
def create_shared_library(codegen,
                          language,
                          pyccel_dirpath,
                          compiler,
                          mpi_compiler,
                          accelerator,
                          dep_mods,
                          libs,
                          libdirs,
                          includes='',
                          flags='',
                          sharedlib_modname=None,
                          verbose=False):

    # Consistency checks
    if not codegen.is_module:
        raise TypeError('Expected Module')

    # Get module name
    module_name = codegen.name

    # Change working directory to '__pyccel__'
    base_dirpath = os.getcwd()
    os.chdir(pyccel_dirpath)

    # Name of shared library
    if sharedlib_modname is None:
        sharedlib_modname = module_name

    sharedlib_folder = ''

    if language in ['c', 'fortran']:
        extra_libs = []
        extra_libdirs = []
        if language == 'fortran':
            # Construct static interface for passing array shapes and write it to file bind_c_MOD.f90
            funcs = [f for f in codegen.routines if not f.is_private]
            sep = fcode(SeparatorComment(40), codegen.parser)
            bind_c_funcs = [
                as_static_function_call(f, module_name, name=f.name)
                for f in funcs
            ]
            bind_c_code = '\n'.join(
                [sep + fcode(f, codegen.parser) + sep for f in bind_c_funcs])
            bind_c_filename = 'bind_c_{}.f90'.format(module_name)

            with open(bind_c_filename, 'w') as f:
                f.writelines(bind_c_code)

            compile_files(bind_c_filename,
                          compiler,
                          flags,
                          binary=None,
                          verbose=verbose,
                          is_module=True,
                          output=pyccel_dirpath,
                          libs=libs,
                          libdirs=libdirs,
                          language=language)

            dep_mods = (os.path.join(pyccel_dirpath,
                                     'bind_c_{}'.format(module_name)),
                        *dep_mods)
            if compiler == 'gfortran':
                extra_libs.append('gfortran')
                extra_libdirs.append(get_gfortran_library_dir())
            elif compiler == 'ifort':
                extra_libs.append('ifcore')

        if sys.platform == 'win32':
            extra_libs.append('quadmath')

        module_old_name = codegen.expr.name
        codegen.expr.set_name(sharedlib_modname)
        wrapper_code = cwrappercode(codegen.expr, codegen.parser, language)
        if errors.has_errors():
            return

        codegen.expr.set_name(module_old_name)
        wrapper_filename_root = '{}_wrapper'.format(module_name)
        wrapper_filename = '{}.c'.format(wrapper_filename_root)

        with open(wrapper_filename, 'w') as f:
            f.writelines(wrapper_code)

        c_flags = [fortran_c_flag_equivalence[f] if f in fortran_c_flag_equivalence \
                else f for f in flags.strip().split(' ') if f != '']

        if sys.platform == "darwin" and "-fopenmp" in c_flags and "-Xpreprocessor" not in c_flags:
            idx = 0
            while idx < len(c_flags):
                if c_flags[idx] == "-fopenmp":
                    c_flags.insert(idx, "-Xpreprocessor")
                    idx += 1
                idx += 1

        setup_code = create_c_setup(sharedlib_modname, wrapper_filename,
                                    dep_mods, compiler, includes,
                                    libs + extra_libs, libdirs + extra_libdirs,
                                    c_flags)
        setup_filename = "setup_{}.py".format(module_name)

        with open(setup_filename, 'w') as f:
            f.writelines(setup_code)

        setup_filename = os.path.join(pyccel_dirpath, setup_filename)
        cmd = [sys.executable, setup_filename, "build"]

        if verbose:
            print(' '.join(cmd))
        p = subprocess.Popen(cmd,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             universal_newlines=True)
        out, err = p.communicate()
        if verbose:
            print(out)
        if p.returncode != 0:
            err_msg = "Failed to build module"
            if verbose:
                err_msg += "\n" + err
            raise RuntimeError(err_msg)
        if err:
            warnings.warn(UserWarning(err))

        sharedlib_folder += 'build/lib*/'

    # Obtain absolute path of newly created shared library

    # Set file name extension of Python extension module
    if os.name == 'nt':  # Windows
        extext = 'pyd'
    else:
        extext = 'so'
    pattern = '{}{}*.{}'.format(sharedlib_folder, sharedlib_modname, extext)
    sharedlib_filename = glob.glob(pattern)[0]
    sharedlib_filepath = os.path.abspath(sharedlib_filename)

    # Change working directory back to starting point
    os.chdir(base_dirpath)

    # Return absolute path of shared library
    return sharedlib_filepath