def load_dependency(self, module_name, dependencies, recursive, greedy, ismapping = False): """Loads the module with the specified name if it isn't already loaded.""" key = module_name.lower() if key not in self.modules: if key == "fortpy": #Manually specify the correct path to the fortpy.f90 that shipped with #the distribution from fortpy.utility import get_fortpy_templates_dir from os import path fpy_path = path.join(get_fortpy_templates_dir(), "fortpy.f90") self.parse(fpy_path, False, False) return fkey = key + ".f90" if fkey in self._pathfiles: self.parse(self._pathfiles[fkey], dependencies, recursive) elif greedy: #The default naming doesn't match for this module #we will load all modules until we find the right #one self._load_greedy(key, dependencies, recursive) elif key in self.mappings and self.mappings[key] in self._pathfiles: #See if they have a mapping specified to a code file for this module name. if self.verbose: msg.info("MAPPING: using {} as the file".format(self.mappings[key]) + " name for module {}".format(key)) self.parse(self._pathfiles[self.mappings[key]], dependencies, recursive) elif key not in ["mkl_vsl_type", "mkl_vsl", "iso_c_binding"]: #The parsing can't continue without the necessary dependency modules. msg.err(("could not find module {}. Enable greedy search or" " add a module filename mapping.".format(key))) if self.austere: exit(1)
def template_version(self, filename): """Returns the version number of the latest fortpy.f90 file.""" if filename not in self._templatev: from os import path from fortpy.utility import get_fortpy_templates_dir tempath = path.join(get_fortpy_templates_dir(), filename) self._templatev[filename] = self.get_fortpy_version(tempath) return self._templatev[filename]
def template_version(compiler, filename): """Returns the version number of the specified file.""" global _templatev if filename not in _templatev: from os import path from fortpy.utility import get_fortpy_templates_dir tempath = path.join(get_fortpy_templates_dir(), filename) _templatev[filename] = get_fortpy_version(compiler, tempath, attribute="codeversion") return _templatev[filename]
def generate(parser, coderoot, stagedir, compiler=None, debug=False, profile=False, strict=False, docompile=True): """Generates the f90 module file for all members referenced in the parser's modules list. """ import fortpy from fortpy.utility import get_fortpy_templates_dir from fortpy.testing.elements import AutoClasser members = _find_members(parser, coderoot) folder = "filename" classers = [AutoClasser(m, folder, m.name, [], coderoot, True) for m in members] from os import path templates = get_fortpy_templates_dir() statpath = path.join(templates, "fpy_auxiliary.f90") with open(statpath) as f: static = f.read() from fortpy.printing.formatting import present_params xnames, modcode, routines, modules = _generate_single(classers) from fortpy.code import order_module_dependencies modules = order_module_dependencies(modules, parser) from os import mkdir, path if docompile: auxdir = path.join(stagedir, "fortpy.aux") if not path.isdir(auxdir): mkdir(auxdir) else: auxdir = coderoot if docompile and not _should_recompile(auxdir, parser, modules, compiler): msg.okay("The current version of fpy_auxiliary.f90 is up-to-date.") from fortpy.testing.compilers import replace target = replace(auxdir + ".[c]", compiler) return (0, True, target) static = static.replace("__auxsave__", present_params(xnames, 21)) static = static.replace("__aux_uses__", '\n'.join(modcode)) static = static.replace("__version__", fortpy.__version__) static = static.replace("__fxauxsave__", '\n'.join(routines)) xnames, modcode, routines, dmods = _generate_single(classers, False) static = static.replace("__auxread__", present_params(xnames, 21)) static = static.replace("__fxauxread__", '\n'.join(routines)) fortpath = path.join(auxdir, "fpy_auxiliary.f90") with open(fortpath, 'w') as f: f.write(static) if docompile: _prepare_dir(parser, modules, auxdir) return _compile(auxdir, compiler, debug, profile)
def set_fortpy_templates(obj, fortpy_templates=None): """Sets the directory path for the fortpy templates. If no directory is specified, use the default one that shipped with the package. """ #If they didn't specify a custom templates directory, use the default #one that shipped with the package. from os import path if fortpy_templates is not None: obj.fortpy_templates = path.abspath(path.expanduser(fortpy_templates)) else: from fortpy.utility import get_fortpy_templates_dir obj.fortpy_templates = get_fortpy_templates_dir()
def load_dependency(self, module_name, dependencies, recursive, greedy, ismapping=False): """Loads the module with the specified name if it isn't already loaded.""" key = module_name.lower() if key not in self.modules: if key == "fortpy": #Manually specify the correct path to the fortpy.f90 that shipped with #the distribution from fortpy.utility import get_fortpy_templates_dir from os import path fpy_path = path.join(get_fortpy_templates_dir(), "fortpy.f90") self.parse(fpy_path, False, False) return fkey = key + ".f90" if fkey in self._pathfiles: self.parse(self._pathfiles[fkey], dependencies, recursive) elif greedy: #The default naming doesn't match for this module #we will load all modules until we find the right #one self._load_greedy(key, dependencies, recursive) elif key in self.mappings and self.mappings[key] in self._pathfiles: #See if they have a mapping specified to a code file for this module name. if self.verbose: msg.info("MAPPING: using {} as the file".format( self.mappings[key]) + " name for module {}".format(key)) self.parse(self._pathfiles[self.mappings[key]], dependencies, recursive) elif key not in ["mkl_vsl_type", "mkl_vsl", "iso_c_binding"]: #The parsing can't continue without the necessary dependency modules. msg.err(("could not find module {}. Enable greedy search or" " add a module filename mapping.".format(key))) if self.austere: exit(1)
"__fpy_read__": fpy_read, "__fpy_read_f__": fpy_read, "__fpy_read_p__": fpy_read, "__pysave__": pysave } """Dict indicating which python function generates the fortran subroutines for the given interface field. """ from os import path import sys sys.path.insert(0, path.expanduser("~/codes/fortpy-dist/")) import fortpy from fortpy.utility import get_fortpy_templates_dir templates = get_fortpy_templates_dir() statpath = path.join(templates, "static.f90") with open(statpath) as f: static = f.read() for iface, idict in list(interfaces.items()): if iface in generators: static = fpy_interface(generators[iface], static, iface, idict) else: raise ValueError("No generator for field {}".format(iface)) static = static.replace("__version__", fortpy.__version__) fortpath = path.join(templates, "fortpy.f90") with open(fortpath, 'w') as f: f.write(static)
def compile(folder, compiler=None, identifier=None, debug=False, profile=False, quiet=False, moptions=None, inclfortpy=True, vupdates=None, strict=False, inclfpyaux=False): """Runs the makefile in the specified folder to compile the 'all' rule. :arg vupdates: a list of module names for which the output .mod and .o files should have version information attached. """ if inclfortpy: #Before we can compile the library, we need to make sure that we have a fortpy #.mod and .o compiled with the *same* compiler version specified. from fortpy.utility import get_fortpy_templates_dir _ensure_fileversion(compiler, "fortpy", get_fortpy_templates_dir(), folder) options = "" if debug: options += " DEBUG=true" if profile: options += " GPROF=true" if strict: options += " STRICT=true" if moptions is not None: for opt in moptions: options += " {}".format(opt) if identifier is not None: codestr = "cd {}; make -f 'Makefile.{}' F90='{}' FAM='{}'" + options command = codestr.format(folder, identifier, executor(compiler), family(compiler)) else: codestr = "cd {}; make F90='{}' FAM='{}'" + options command = codestr.format(folder, executor(compiler), family(compiler)) #If we are running in quiet mode, we don't want the compile information #to post to stdout; only errors should be redirected. This means we need #to wrap the execution in a subprocess and redirect the std* to PIPE from os import waitpid, path from subprocess import Popen, PIPE pcompile = Popen(command, shell=True, executable="/bin/bash", stdout=PIPE, stderr=PIPE) waitpid(pcompile.pid, 0) if not quiet: output = [x.decode('utf8') for x in pcompile.stdout.readlines()] msg.std(''.join(output)) #else: #We don't need to get these lines since we are purposefully redirecting them. error = [x.decode('utf8') for x in pcompile.stderr.readlines()] code = len(error) if code != 0: msg.err(''.join(error)) #It turns out that the compiler still returns a code of zero, even if the compile #failed because the actual compiler didn't fail; it did its job properly. We need to #check for the existence of errors in the 'compile.log' file. lcount = 0 errors = [] log = path.join(folder, "compile.log") with open(log) as f: for line in f: lcount += 1 if lcount > 21 and lcount < 32: errors.append(line) elif lcount > 21: break if len(errors) > 0: #There are 21 lines in the compile.log file when everything runs correctly #Overwrite code with a bad exit value since we have some other problems. code = 1 #We want to write the first couple of errors to the console and give them the #option to still execute if the compile only generated warnings. msg.warn("compile generated some errors or warnings:") msg.blank() msg.info(''.join(errors)) if vupdates is not None: for modname in vupdates: _vupdate_compiled_module(compiler, modname, folder, rename=False) return (code, len(errors)==0)
def compile(folder, compiler=None, identifier=None, debug=False, profile=False, quiet=False, moptions=None, inclfortpy=True, vupdates=None, strict=False, inclfpyaux=False): """Runs the makefile in the specified folder to compile the 'all' rule. :arg vupdates: a list of module names for which the output .mod and .o files should have version information attached. """ if inclfortpy: #Before we can compile the library, we need to make sure that we have a fortpy #.mod and .o compiled with the *same* compiler version specified. from fortpy.utility import get_fortpy_templates_dir _ensure_fileversion(compiler, "fortpy", get_fortpy_templates_dir(), folder) options = "" if debug: options += " DEBUG=true" if profile: options += " GPROF=true" if strict: options += " STRICT=true" if moptions is not None: for opt in moptions: options += " {}".format(opt) if identifier is not None: codestr = "cd {}; make -f 'Makefile.{}' F90='{}' FAM='{}'" + options command = codestr.format(folder, identifier, executor(compiler), family(compiler)) else: codestr = "cd {}; make F90='{}' FAM='{}'" + options command = codestr.format(folder, executor(compiler), family(compiler)) #If we are running in quiet mode, we don't want the compile information #to post to stdout; only errors should be redirected. This means we need #to wrap the execution in a subprocess and redirect the std* to PIPE from os import waitpid, path from subprocess import Popen, PIPE pcompile = Popen(command, shell=True, executable="/bin/bash", stdout=PIPE, stderr=PIPE, close_fds=True) waitpid(pcompile.pid, 0) if not quiet: output = [x.decode('utf8') for x in pcompile.stdout.readlines()] msg.std(''.join(output)) #else: #We don't need to get these lines since we are purposefully redirecting them. error = [x.decode('utf8') for x in pcompile.stderr.readlines()] code = len(error) if code != 0: msg.err(''.join(error)) pcompile.stdout.close() pcompile.stderr.close() #It turns out that the compiler still returns a code of zero, even if the compile #failed because the actual compiler didn't fail; it did its job properly. We need to #check for the existence of errors in the 'compile.log' file. lcount = 0 errors = [] log = path.join( folder, "compile.{}.log".format( identifier if identifier is not None else "default")) with open(log) as f: for line in f: lcount += 1 if lcount > 21 and lcount < 32: errors.append(line) elif lcount > 21: break if len(errors) > 0: #There are 21 lines in the compile.log file when everything runs correctly #Overwrite code with a bad exit value since we have some other problems. code = 1 #We want to write the first couple of errors to the console and give them the #option to still execute if the compile only generated warnings. msg.warn("compile generated some errors or warnings:") msg.blank() msg.info(''.join(errors)) if vupdates is not None: for modname in vupdates: _vupdate_compiled_module(compiler, modname, folder, rename=False) return (code, len(errors) == 0)