示例#1
0
文件: tester.py 项目: feifzhou/fortpy
    def _run_compile(self, identifier, testid):
        """Compiles the executable that was created for the specified identifier,
        returns True if the compile was successful."""
        #Because we often run the tests for multiple compiler versions, we need
        #a copy of the execution directory that was setup for the testing.
        from fortpy.testing.compilers import replace, executor, family
        from fortpy.utility import copytree
        from os import path
        source = path.join(self.libraryroot(identifier), identifier)        
        target = replace(source + ".[c]", self.compiler)
        copytree(source, target)

        #Before we compile, we need to make sure we have the fortpy.o and fortpy.mod
        #files for the specific compiler.
        tversion = self.template_version("fortpy.f90")
        for sdfile in ["fortpy.o", "fortpy.mod"]:
            fdfile = replace(sdfile + ".[c]", self.compiler)
            ftarget = path.join(target, sdfile)
            dversion = self.get_fortpy_version(ftarget)
                
            if not path.isfile(ftarget) or dversion != tversion:
                from shutil import copy
                source = path.join(self.fortpy_templates, fdfile)
                sversion = self.get_fortpy_version(source)
                if not path.isfile(source) or sversion != tversion:
                    self._compile_fortpyf90(tversion)
                    
                msg.info("   COPY: {}".format(source))
                copy(source, ftarget)
                #If the file is a binary, we need to save a .v with version
                #information as well for the next time we want to copy it.
                pre, ext = path.splitext(ftarget)
                if ext in [".o", ".so", ".mod"]:
                    with open(ftarget + '.v', 'w') as f:
                        f.write("# <fortpy version=\"{}\" />".format('.'.join(map(str, tversion))))
        
        #Find the target folder that has the executables etc then run
        #make and check the exit code.
        msg.blank()
        options = ""
        if self.debug:
            options += " DEBUG=true"
        if self.profile:
            options += " GPROF=true"

        codestr = "cd {}; make -f 'Makefile.{}' F90='{}' FAM='{}'" + options
        #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
        from subprocess import Popen, PIPE
        command = codestr.format(target, testid, executor(self.compiler), family(self.compiler))
        pcompile = Popen(command, shell=True, executable="/bin/bash", stdout=PIPE, stderr=PIPE)
        waitpid(pcompile.pid, 0)
        
        if not self.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 = 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(target, "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 the executable exists, we could still prompt them to run it (in case the
            #additional lines were just warnings).
            exe = path.join(target, "{}.x".format(testid))
            if path.isfile(exe):
                choice = input("\nWould you still like to run the executable? ").lower()
                code = 0 if "y" in choice else code
                if "n" in choice:
                    msg.err("Unit testing terminated by user.")
                    exit(0)
            else:
                msg.err("Could not compile executable {}.x".format(testid))
                exit(-1)

        return code == 0, target
示例#2
0
文件: tester.py 项目: feifzhou/fortpy
    def _compile_fortpyf90(self, tversion):
        """Compiles a fortpy.mod and fortpy.o for the current compiler.
        """
        msg.info("Compiling fortpy.mod and fortpy.f90 for {}".format(self.compiler))
        from os import waitpid, path
        from subprocess import Popen, PIPE
        from fortpy.testing.compilers import executor, replace
        command = "cd {0}; {1} fortpy.f90; {1} -c fortpy.f90".format(self.fortpy_templates, executor(self.compiler))
        pcompile = Popen(command, shell=True, executable="/bin/bash", stdout=PIPE, stderr=PIPE)
        waitpid(pcompile.pid, 0)

        opath = path.join(self.fortpy_templates, "fortpy.o")
        mpath = path.join(self.fortpy_templates, "fortpy.mod")
        if path.isfile(opath) and path.isfile(mpath):
            from shutil import move
            nopath = path.join(self.fortpy_templates, replace("fortpy.o.[c]", self.compiler))
            nmpath = path.join(self.fortpy_templates, replace("fortpy.mod.[c]", self.compiler))
            move(opath, nopath)
            move(mpath, nmpath)
            #Create the version files so we can keep track of the compiled versions.
            vpaths = [nopath + ".v", nmpath + ".v"]
            for vp in vpaths:
                with open(vp, 'w') as f:
                    f.write('#<fortpy version="{}" />'.format('.'.join(map(str, tversion))))
        else:
            msg.err("Unable to generate fortpy.o and fortpy.mod.")