Skip to content

Handling Multiple Compilers

Conrad Rosenbrock edited this page May 1, 2015 · 4 revisions

An important aspect of software testing is making sure that all relevant compiler versions still work when code is changed; otherwise existing users may be locked out from future updates or bug fixes when new features only work with newer compilers. Specifically for Fortran, we also have the the different behaviors of ifort vs. gfortran. For example, each handles random seeds differently; if you want to seed the random number generator to fix the output results of unit tests, then the seed input files for ifort and gfortran are different.

Starting with revision 1.5.4, fortpy supports multiple compilers as described below.

compilers.xml File

This is an example of the new compilers.xml file. It specifies names, keys and paths to compilers available on the local system running fortpy.

<?xml version="1.0"?>
<compilers>
  <compiler path="/usr/local/bin/gfortran" key="g49" name="gfortran49"
	    default="true" />
  <compiler path="/usr/local/bin/ifort" key="i15" name="ifort15" />
</compilers>
  • path specifies the full path to the compiler executable that fortpy should use.
  • key if specified, this key will be spliced into all input/output files that have [c] in the filename (i.e. [c] will be replaced by this key before copying input/output files to execution directories). Additionally, when the unit tests are run, the executing directory will be called module.executable.key for each compiler used.
  • name for the -compiler argument of runtests.py. Change that argument to accept a string. If the string is *, then run the unit tests separately for every compiler in the compilers.xml file. Otherwise, only run those compilers whose names match the string given.
  • default if -compiler is run without specifying a string, this is the compiler that would be used by default. If none of the compilers in the file have this attribute, the first one listed is used.

The path to this file should be specified using the following tag, added to the global fortpy configuration file.

  <compilers>~/codes/fortpy-dist/fortpy/compilers.xml</compilers>

To have fortpy test the code against all the compilers listed in compilers.xml, runtests.py will be executed exactly as before; the only change is that -compilers "*" would be added as an option.

Differing Input Files

As described in the introduction, if different compilers/compiler families need different versions of input/output files, these can be specified by including the compiler key in the file name. When the input/output file is specified in the unit testing XML file, include [c] in the file name at the location where the compiler key should be inserted. As an example, consider the following <input> tag from a testing group:

<test identifier="random" description="Example of random seed with multiple compilers"
      cases="1, 2" timed="true">
   <input folder="./tests" file="randseed.[c].in.{}" rename="randseed.in" />
</test>

Now, suppose that I have the compilers as specified in the example compilers.xml file above. Then, inside the tests folder, I expect to find four files: randseed.g49.in.1, randseed.g49.in.2, randseed.i15.in.1, and randseed.i15.in.2. When these input files are copied to the execution directory, they will all be renamed to randseed.in so that the code can reference only a single file name, independent of the compiler.

When the tests are run with -compilers "*" using runtests.py, fortpy will create three directories:

  • module.random: a clean copy of all the dependencies and make files needed for the compilation.
  • module.random.g49: a copy of module.random which gets compiled with the gfortran compiler.
  • module.random.i15: a copy of module.random, but compiled with ifort instead.

The unit tests are executed in each respective directory.

Compiler Families

In addition to modifying the input file names by compiler (using the [c] field), fortpy also supports replacing compiler families using the field [f]. If the compiler is a gfortran compiler version, the family key is g; for ifort, the family character is i. A file name such as randseed.[f].in.{} from the example above would become randseed.g.in.1 and randseed.i.in.1. The replacement only takes place for file names.