Better Compiler Support
Closed this issue · 3 comments
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???)
Some design ideas:
- A base class called
Tool
, which takes a list of env variables and strings (=commands) to try. It has arun
method (and maybe something likeget_version
). Actually, I think atm fab does agfortran --help
to see if gfortran works, and then latergfortran --version
- seems useless to try two things) - 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.
- And based on this we create the immediate compiler files for
gfortran
,ifort
,ifx
, etc. - And based on these we can then declare compiler wrapper (
tau
, Cray'sftn
).
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).
I'm working on this, based on our design document
Todo:
- Replace other tools to be based on new Tool class
- Remove old tools.py file
- Print toolbox so that it is documented what was used for a build