Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: Have f2py handle hybrid F77/F90 codebases #9928

Closed
wants to merge 7 commits into from

Conversation

rolk
Copy link
Contributor

@rolk rolk commented Oct 26, 2017

Some of the older codebases consists of a mix of files written in Fortran 77 and Fortran 90. Probably these started out as Fortran 77 long time ago and then Fortran 90 features were introduced when that became available. However, they are not necessarily careful in using the corresponding file extension for the source files, preferring to keep the existing extension for all files.

This lead into a problem when running them through f2py, as the parser chokes on newer constructs if it has been set in legacy mode. And this mode is determined by the file extension before parsing takes place.

This changeset introduce a new option, --std=f90, which force the parser into Fortran 90 mode, even if the file extension is .f or .for. The name of the option is based on a corresponding option that can be used for the compiler. I though about scanning the compiler options for such a flag, but in most cases, this triggers a strict standard compliance, which these older codebases are not ready for, hence an f2py option.

The alternative to such a switch would be to scan through all files, looking for Fortran 90 constructs. I am open to such a solution if that would be deemed preferrable over a new command-line option, but it then incurs a cost of scanning through every file passed to f2py.

The f2py crackfortran parser (which reads declarations from Fortran
files) assumed that all files with extension .f or .for is according
to Fortran 77 standard. However, some legacy codebases use these
extensions also for Fortran 90 code. This applies particularily to
projects which started in Fortran 77 but migrated halfway to Fortran
90 when it arrived.

This patch lets you set an option in the parser to disregard the file
extension when trying to infer the language level of the file. (Such
options are (unfortunately) passed to the compiler as global variables)
Allow a command-line option to f2py to specify that we want the internal
parser to always regard files to be according to a certain Fortran
standard. The command-line option is modeled after a similar option that
is used for the compilers (which is also why both single and double
dashes are accepted).

An alternative to such an option would have been to look for a --std=
switch sent to the compiler, but there is (currently) no settings for
common flags to both F77 and F90 compilers. Also, using the standard
options to the compiler may trigger a more stricter compliance mode,
which may not be desirable with old codebases.

To use this functionality, pass the (named) parameter
f2py_options='-std=f90' to the Extension object in setup.py
The new -std= option must be recognized as an f2py option and passed to
the code path that generates the extension module source.
Previous version would only check for module headers if the file
extension was .f90 or .f95. However, hybrid F77/F90 codebases may
have modules (for allocatable common variables, for instance) and
these may not use .f90 as extension.

This patch disables the assumption about file name, so that every
Fortran source file is scanned for module headers regardless.
We don't want client modules to alter the _f90_mod_ext option flag
willy-nilly; by introducing a context manager, it is more easily
traced where this flag is set.
If we have declared that all our source is Fortran 90, then all of it
should be scanned for module headers, so that they can be compiled first
to generate module intermediate files.
Give a short overview of the switch to enable this functionality and an
example of a case where you would use it.
@njsmith
Copy link
Member

njsmith commented Oct 26, 2017

I know very little about fortran, but if compilers are happy to ignore the extension and automatically do the right thing, then it seems like ideally f2py should do the same? Is there ever any circumstance where your --std=f90 flag would be harmful?

@rolk
Copy link
Contributor Author

rolk commented Oct 27, 2017

@njsmith You mean: Why go through all the hoops and make the code more convoluted by having an extra option, if it is possible to instead just remove the extension check and always scan the code as Fortran 90? I agree it's a good question; sorry for not addressing this in the proposal.

Honestly, I don't know the full impact of doing that. One snag I can think of is that .f/.for is supposed to be "fixed form", where which column text is in is significant, whereas in .f90 files it may be either "fixed form" or "free form"; it may be that there is code which can be interpreted differently between these two, but I don't have any examples to give.

I don't have enough knowledge about the implementation of the 'crackfortran' internal parser, but just that there is a check on extension that toggles an internal flag makes me suspicious that there is someone out there depending on this (as usual xkcd has this covered).

a Fortran source file is according to Fortran 90 standard or not and
thus may contain a module (which must be compiled before other sources).
"""
def __init__(self, override = True):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PEP8, no spaces in keyword argument defaults, i.e., override=True.

@charris
Copy link
Member

charris commented Oct 28, 2017

Apparently the file extension is not part of the Fortran standard, merely convention. I suppose it could vary between compilers. Looking at ifort and gfortran, it seems that the extension can be overridden, although with different options in the two. So I'm curious as to what the mixed type files look like, are they just fixed-format files that make use of later features? Also, is the problem with f2py parsing of the files, or with compiling the files?

@charris
Copy link
Member

charris commented Oct 28, 2017

If it is f2py that is the problem, and it sounds like it, anyreason not to always parse as newer fortran, or perhaps wait for an error and then try the newer version, using fixed-format in both cases.

@charris charris changed the title ENH: Have f2py handle hydrid F77/F90 codebases ENH: Have f2py handle hybrid F77/F90 codebases Oct 28, 2017
@charris
Copy link
Member

charris commented Oct 29, 2017

Just an observation, but someday we should replace the command line parser in f2py with argparse. The current code dates from 2005.

@rolk
Copy link
Contributor Author

rolk commented Oct 30, 2017

@charris

I'm curious as to what the mixed type files look like
It is not as much that that there are files containing mixed content (for instance common blocks in modules), but that libraries tend to use the same extension everywhere regardless and let the compiler sort out which language level it really is. That becomes a problem because f2py doesn't use the compiler to retrieve the interface but its own 'crackfortran' parser.

any reason not to always parse as newer fortran,

Probably, since the original crackfortran code had -f77 and -f90 options (why not just do everything in Fortran 90 mode if that was viable?).

or perhaps wait for an error and then try the newer version

That is of course an option; buffering all print/outmess/errmess until it is determined if there was an error or not, if there was attempt to redo it in Fortran 90 mode, and it that case signal so to the build system.

@rolk
Copy link
Contributor Author

rolk commented Oct 30, 2017

in that case signal so to the build system

There is a problem here; f2py2e.run_compile calls setup, which indirectly calls f2py again, this time run_main which leads to callcrackfortran. I am having trouble to see how to cleanly get information from the latter (that we needed to use Fortran 90 scanning even though the file extension says otherwise) up to run_compile again, so that it can further instruct the module compilation to do modules first.

Unless we of course ditch the whole file extension part from misc_utils also, and always scan the Fortran files for module headers and in that case compile them first. What do you think?

@pearu pearu added this to In progress in f2py usage via automation Feb 20, 2021
Base automatically changed from master to main March 4, 2021 02:04
@melissawm
Copy link
Member

Hello @rolk - is this PR something you are still interested in working on? In that case, would you add a test for it? Thanks!

@HaoZeke
Copy link
Member

HaoZeke commented Aug 25, 2021

Automatically "doing the right thing" is a bad idea, for an explanation of why we should support std=BLA even beyond just free-form / fixed form, see #5486.

@melissawm
Copy link
Member

@pearu do you have an opinion on whether this should be closed on can be picked up?

@HaoZeke
Copy link
Member

HaoZeke commented Jun 8, 2022

Closing this for now (distutils is on the way out, not sure this is a good thing to do, new CLI incoming), but @NamamiShanker you can consider this case (forcing F90+ for a given filetype) for the new CLI in progress.

@rolk thanks for working on this and for the valuable discussion.

@HaoZeke HaoZeke closed this Jun 8, 2022
f2py usage automation moved this from In progress to Done Jun 8, 2022
@HaoZeke HaoZeke mentioned this pull request Jun 8, 2022
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

Successfully merging this pull request may close these issues.

None yet

6 participants