Exemplo n.º 1
0
    def _print_Program(self, expr):

        name = 'prog_{0}'.format(self._print(expr.name))
        name = name.replace('.', '_')

        imports = list(expr.imports)
        imports += [Import('stdlib.h')]
        imports = '\n'.join(self._print(i) for i in imports)
        body = '\n'.join(self._print(i) for i in expr.body)
        decs = '\n'.join(self._print(i) for i in expr.declarations)

        sep = self._print(SeparatorComment(40))

        funcs = ''
        for i in expr.funcs:
            funcs = ('{funcs}\n'
                     '{sep}\n'
                     '{f}\n'
                     '{sep}\n').format(funcs=funcs, sep=sep, f=self._print(i))

        if funcs:
            funcs = 'contains\n{0}'.format(funcs)

        return ('{imports}\n'
                '{funcs}\n'
                'int main(){{\n'
                '{decs}\n'
                '{body}\n'
                'return 0;\n'
                '}}').format(imports=imports,
                             decs=decs,
                             body=body,
                             funcs=funcs)
Exemplo n.º 2
0
    def _print_FunctionDef(self, expr):

        if len(expr.results) > 1:
            self._additional_args.append(expr.results)
        body = self._print(expr.body)
        decs = [
            Declare(i.dtype, i)
            if isinstance(i, Variable) else FuncAddressDeclare(i)
            for i in expr.local_vars
        ]
        if len(expr.results) <= 1:
            decs += [
                Declare(i.dtype, i)
                if isinstance(i, Variable) else FuncAddressDeclare(i)
                for i in expr.results
            ]
        decs += [Declare(i.dtype, i) for i in self._additional_declare]
        decs = '\n'.join(self._print(i) for i in decs)
        self._additional_declare.clear()

        sep = self._print(SeparatorComment(40))
        if self._additional_args:
            self._additional_args.pop()
        imports = ''.join(self._print(i) for i in expr.imports)

        return ('{sep}\n'
                '{signature}\n{{\n'
                '{imports}\n'
                '{decs}\n\n'
                '{body}\n'
                '}}\n{sep}'.format(sep=sep,
                                   signature=self.function_signature(expr),
                                   imports=imports,
                                   decs=decs,
                                   body=body))
Exemplo n.º 3
0
    def _print_Interface(self, expr):

        # Collecting all functions
        funcs = expr.functions
        # Save all used names
        used_names = set(n.name for n in funcs)

        # Find a name for the wrapper function
        wrapper_name = self._get_wrapper_name(used_names, expr)
        self._global_names.add(wrapper_name)

        # Collect local variables
        python_func_args = self.get_new_PyObject("args", used_names)
        python_func_kwargs = self.get_new_PyObject("kwargs", used_names)
        python_func_selfarg = self.get_new_PyObject("self", used_names)

        # Collect wrapper arguments and results
        wrapper_args = [
            python_func_selfarg, python_func_args, python_func_kwargs
        ]
        wrapper_results = [self.get_new_PyObject("result", used_names)]

        # Collect parser arguments
        wrapper_vars = {}

        # Collect argument names for PyArgParse
        arg_names = [a.name for a in funcs[0].arguments]
        keyword_list_name = self.get_new_name(used_names, 'kwlist')
        keyword_list = PyArgKeywords(keyword_list_name, arg_names)
        wrapper_body = [keyword_list]

        wrapper_body_translations = []
        body_tmp = []

        # To store the mini function responsible of collecting value and calling interfaces functions and return the builded value
        funcs_def = []
        default_value = {
        }  # dict to collect all initialisation needed in the wrapper
        check_var = Variable(dtype=NativeInteger(),
                             name=self.get_new_name(used_names, "check"))
        wrapper_vars[check_var.name] = check_var
        types_dict = OrderedDict(
            (a, set()) for a in funcs[0].arguments
        )  #dict to collect each variable possible type and the corresponding flags
        # collect parse arg
        parse_args = [
            Variable(dtype=PyccelPyArrayObject(),
                     is_pointer=True,
                     rank=a.rank,
                     order=a.order,
                     name=self.get_new_name(used_names, a.name +
                                            "_tmp")) if a.rank > 0 else
            Variable(dtype=PyccelPyObject(),
                     name=self.get_new_name(used_names, a.name + "_tmp"),
                     is_pointer=True) for a in funcs[0].arguments
        ]
        # Managing the body of wrapper
        for func in funcs:
            mini_wrapper_func_body = []
            res_args = []
            mini_wrapper_func_vars = {a.name: a for a in func.arguments}
            flags = 0
            collect_vars = {}

            # Loop for all args in every functions and create the corresponding condition and body
            for p_arg, f_arg in zip(parse_args, func.arguments):
                collect_vars[f_arg] = p_arg
                body, tmp_variable = self._body_management(
                    used_names, f_arg, p_arg, None)
                if tmp_variable:
                    mini_wrapper_func_vars[tmp_variable.name] = tmp_variable

                # get check type function
                check = self._get_check_type_statement(f_arg, p_arg)
                # If the variable cannot be collected from PyArgParse directly
                wrapper_vars[p_arg.name] = p_arg

                # Save the body
                wrapper_body_translations.extend(body)

                # Write default values
                if isinstance(f_arg, ValuedVariable):
                    wrapper_body.append(
                        self.get_default_assign(parse_args[-1], f_arg))

                flag_value = flags_registry[(f_arg.dtype, f_arg.precision)]
                flags = (flags << 4) + flag_value  # shift by 4 to the left
                types_dict[f_arg].add(
                    (f_arg, check,
                     flag_value))  # collect variable type for each arguments
                mini_wrapper_func_body += body

            # create the corresponding function call
            static_function, static_args, additional_body = self._get_static_function(
                used_names, func, collect_vars)
            mini_wrapper_func_body.extend(additional_body)

            for var in static_args:
                mini_wrapper_func_vars[var.name] = var

            if len(func.results) == 0:
                func_call = FunctionCall(static_function, static_args)
            else:
                results = func.results if len(
                    func.results) > 1 else func.results[0]
                func_call = Assign(results,
                                   FunctionCall(static_function, static_args))

            mini_wrapper_func_body.append(func_call)

            # Loop for all res in every functions and create the corresponding body and cast
            for r in func.results:
                collect_var, cast_func = self.get_PyBuildValue(used_names, r)
                mini_wrapper_func_vars[collect_var.name] = collect_var
                if cast_func is not None:
                    mini_wrapper_func_vars[r.name] = r
                    mini_wrapper_func_body.append(
                        AliasAssign(collect_var, cast_func))
                res_args.append(
                    VariableAddress(collect_var) if collect_var.
                    is_pointer else collect_var)

            # Building PybuildValue and freeing the allocated variable after.
            mini_wrapper_func_body.append(
                AliasAssign(wrapper_results[0], PyBuildValueNode(res_args)))
            mini_wrapper_func_body += [
                FunctionCall(Py_DECREF, [i])
                for i in self._to_free_PyObject_list
            ]
            mini_wrapper_func_body.append(Return(wrapper_results))
            self._to_free_PyObject_list.clear()
            # Building Mini wrapper function
            mini_wrapper_func_name = self.get_new_name(
                used_names.union(self._global_names),
                func.name.name + '_mini_wrapper')
            self._global_names.add(mini_wrapper_func_name)

            mini_wrapper_func_def = FunctionDef(
                name=mini_wrapper_func_name,
                arguments=parse_args,
                results=wrapper_results,
                body=mini_wrapper_func_body,
                local_vars=mini_wrapper_func_vars.values())
            funcs_def.append(mini_wrapper_func_def)

            # append check condition to the functioncall
            body_tmp.append((PyccelEq(check_var, LiteralInteger(flags)), [
                AliasAssign(wrapper_results[0],
                            FunctionCall(mini_wrapper_func_def, parse_args))
            ]))

        # Errors / Types management
        # Creating check_type function
        check_func_def = self._create_wrapper_check(check_var, parse_args,
                                                    types_dict, used_names,
                                                    funcs[0].name.name)
        funcs_def.append(check_func_def)

        # Create the wrapper body with collected informations
        body_tmp = [((PyccelNot(check_var), [Return([Nil()])]))] + body_tmp
        body_tmp.append((LiteralTrue(), [
            PyErr_SetString('PyExc_TypeError',
                            '"Arguments combinations don\'t exist"'),
            Return([Nil()])
        ]))
        wrapper_body_translations = [If(*body_tmp)]

        # Parsing Arguments
        parse_node = PyArg_ParseTupleNode(python_func_args, python_func_kwargs,
                                          funcs[0].arguments, parse_args,
                                          keyword_list, True)
        wrapper_body += list(default_value.values())
        wrapper_body.append(If((PyccelNot(parse_node), [Return([Nil()])])))

        #finishing the wrapper body
        wrapper_body.append(
            Assign(check_var, FunctionCall(check_func_def, parse_args)))
        wrapper_body.extend(wrapper_body_translations)
        wrapper_body.append(Return(wrapper_results))  # Return

        # Create FunctionDef
        funcs_def.append(
            FunctionDef(name=wrapper_name,
                        arguments=wrapper_args,
                        results=wrapper_results,
                        body=wrapper_body,
                        local_vars=wrapper_vars.values()))

        sep = self._print(SeparatorComment(40))

        return sep + '\n'.join(
            CCodePrinter._print_FunctionDef(self, f) for f in funcs_def)
Exemplo n.º 4
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))
Exemplo n.º 5
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