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
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))
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