hiker / fab

Flexible build system for scientific software
https://metomi.github.io/fab/
Other
1 stars 0 forks source link

Better Compiler Support #3

Closed hiker closed 1 month ago

hiker commented 6 months ago

ATM a compiler is a plain data object:

class Compiler(object):
    """
    A command-line compiler whose flags we wish to manage.

    """
    def __init__(self, exe, compile_flag, module_folder_flag):
        self.exe = exe
        self.compile_flag = compile_flag
        self.module_folder_flag = module_folder_flag
        # We should probably extend this for fPIC, two-stage and optimisation levels.

COMPILERS: Dict[str, Compiler] = {
    'gfortran': Compiler(exe='gfortran', compile_flag='-c', module_folder_flag='-J'),
    'ifort': Compiler(exe='ifort', compile_flag='-c', module_folder_flag='-module'),
}

Create a better class with some methods to access these flags. Each compiler should have a user name, and an executable name (e.g. we could then create TauIntel as user name, which would call tau_f90.sh, and it's then the responsibility of the user to make sure that the tau used is indeed based on Fortran.

This would allow us to easily declare these wrappers:

class TauIntel(Intel):
   def __init__(self):
     super().__init__(self)
      self._id = "TauIntel'    # Maybe get this from the class name?
      self._exec = "tau_f90.sh"

So we would get the information about flags etc from intel using functions that we just inherit.

We need to work out a few more details as well, e.g. how do we manage a list of compilers, ideally in a way that the user can extend it without modifying tau (e.g. a special env variable or option somewhere to make additional files available???)

hiker commented 6 months ago

Some design ideas:

  1. A base class called Tool, which takes a list of env variables and strings (=commands) to try. It has a run method (and maybe something like get_version). Actually, I think atm fab does a gfortran --help to see if gfortran works, and then later gfortran --version - seems useless to try two things)
  2. From this we derive a generic Compiler class, which additionally provides functions to access the compiler specific flags (module search path esp. ) , the -c flag I think is handled especially in Fab as well.
  3. And based on this we create the immediate compiler files for gfortran, ifort, ifx, etc.
  4. And based on these we can then declare compiler wrapper (tau, Cray's ftn).

Long term we would then move all tools (cpp, linker, maybe even PSyclone) to this Tool base class (not all at once to keep the changes smaller when reviewing).

Oh, we would also need a function to find the right class. E.g. the user specifies (as parameter or $FC) ifort - we need to map this to a class that we import and then use. I can point to the code in psyclone that does something similar (handling the -s command line parameter to call the script with the given name).

Hmm - one thing I am thinking of: is it actually standardised to have a space or not between say -J (where to write modules) and the path? Maybe some compilers need a space (i.e. -J and path are two parameters), and others don't? We could have methods get_module_search_path_flag(self, path): return ['-J', path] or return [f"-J{path}"] (one parameter). This way we would be really flexible in what to do (and the Compiler base class could just do one of the above, so the compiler-specific classes could only set the flag to be -J or -module (intel).

hiker commented 4 months ago

I'm working on this, based on our design document

hiker commented 4 months ago

Todo: