Fortran-FOSS-Programmers / ford

Automatically generates FORtran Documentation from comments within the code.
https://forddocs.readthedocs.io
GNU General Public License v3.0
405 stars 131 forks source link

Issue with preprocessor includes/normal includes #119

Open ollehellman opened 8 years ago

ollehellman commented 8 years ago

Hi,

Bothering you again with preprocessor things. With these files foo.F90:

function A
#include "bar.f90"

and bar.f90

function B

FORD will correctly parse both files via the proprocessor include. However, in the documentation for function B, if I click to view the source, only foo.F90 is there, with the preprocessor macro unexpanded. Is this the desired output?

If i use include "bar.f90" instead of #include "bar.f90" the joined file will be shown by FORD.

Related issue: when using MPI I frequenctly need to add a line

include "mpif.h"

to the source. This causes FORD to not be very happy. Is there an easy way to add a

include "mpif.h" ! FORD_please_ignore_this

or equivalent thing? Sorry about joining questions, but they are sort of the same thing.

cmacmackin commented 8 years ago

I'm not 100% sure what you mean by "click to view the source" in the documentation. Are you looking at the raw source file, the documentation page for the source file, or the excerpt of the source for the function at the bottom of the page?

In any case, it is not my intention to have FORD display preprocessed versions of the code. It will analyze preprocessed versions as not doing so means that you won't get useful documentation, but any excerpts of source code shown are meant to reflect the files as they are written. What I am not sure about is how include commands (rather than macros) could have ended up being expanded in the source you are looking at. Hence why I'd like to know where you are looking.

The question about the mpif.h file, however, I can answer. What you'll want to do there is let FORD know where to look for include files other than the directory the source file is in--just as you would the compiler. You can do this using the include option in the project file. Just specify the same directory as you would when compiling.

ollehellman commented 8 years ago

Hi, I should have explained it better: here is a minimal example: file_a.F90

module foo

type bar
    integer :: i
    contains
    procedure :: fun1
    procedure :: fun2
end type

contains

#include "file_b.f90"

integer function fun2(self,j)
    class(bar) :: self
    integer :: j
    fun2=j+j
end function fun2

end module

and file_b.f90

integer function fun1(self,i)
    class(car) :: self
    integer :: i
    fun1=i+1
end function fun1

produces some odd output: under Procedures, fun1 is listed twice, once associated with file_a.F90 and once with file_b.f90. The one associated with file_b.f90 has the source code correctly extracted, whereas the one from file_a.F90 does not.

I can exclude file_b.f90 from parsing, and fun1 will only be listed once. However, it gets incorrectly associated with file_a.F90, and no source is extracted.

I look through the source to the best of my abilities, but I could not figure it out. If I follow it right, reader.py will expand all the code in the pre-parsing step, which why the double association makes sense. I had trouble finding where the source code chopped up into pieces (the pieces put at the bottom of the page) gets extracted.

It's not that major, but a little annoying.

cmacmackin commented 6 years ago

This would require a different way of looking at code than that currently used by FORD. Include statements are a natural fit for a language like C where the file is the scoping unit. You "import" an entity by including its (header) file. However, Fortran doesn't really think that way; certainly it doesn't since the introduction of modules. The scoping unit is the module, program, or procedure. Procedures, types, variables, etc. are defined within those units. Intuitively, one would expect the definitions to be in the same file as the scoping unit containing them and for this reason I don't think include statements should be used anymore. At least, this is always how I've approached code architecture and the design of FORD reflects that; it associates entities with the file they're defined in. Include statements throw a wrench into this. Correcting these issues would require a much more sophisticated understanding by FORD of exactly where code comes from. Now, there would be some advantages to doing this, but it is not a priority for me.

zerothi commented 6 years ago

Let me add some more context.

I would second fixing this. Using include statements are highly valuable in certain cases where one can reuse the same code for multiple definitions, i.e. same derived type with different data-scopes having a common interface for certain routines. I.e. for creating reference counted objects etc. the include statements are quite useful.

Basically, I think ford should wholly include the #include <files> tags and parse the full file as though it was one file.

Thanks for the software!

cmacmackin commented 6 years ago

In fairness, the use cases you describe are essentially workarounds for missing language features in Fortran. Ideally the include statement would not be necessary to achieve the desired effect. In any case, regardless of any stylistic preferences, getting FORD to handle include in a more sophisticated way than it currently does would be quite difficult. At present it first runs a file through a preprocessor before any further analysis. If it encounters any of Fortran's intrinsic include statements it will then pull in the text from that file. This all allows it to correctly parse the source code and generate meaningful documentation. However, it may not be able to correctly display the source code for each function or derived type that it documents. Because include statements are often used as a somewhat messy workaround (and aren't used in the same way by everyone), I'm also not entirely clear what the appropriate way to handle them would be beyond what is currently done.

In any case, I'm not longer the lead maintainer of FORD and perhaps others would be more willing to consider how to better handle includes and how to go about implementing this.

zerothi commented 6 years ago

@cmacmackin ok, perhaps this should be easily circumvented by issuing the appropriate pre-processor steps.

zbeekman commented 6 years ago

I'll try to take a look soon and help jump on the FORD maintenance tasks

zerothi commented 6 years ago

@zbeekman perhaps you should wait a bit, maybe the fix is already found by @albgar and @vdikan. We'll let you know!

Mbood commented 3 years ago

Did anyone find the fix? @zerothi @vdikan @cmacmackin @zbeekman I have the same problem. and I'm trying to generate the documents in a system which has not Fortran compiler or MPI installed. I deleted all include mpif.90 from the code files, but I ended up with a new error.

Traceback (most recent call last): File "/usr/local/bin/ford", line 8, in sys.exit(run()) File "/usr/local/lib/python3.8/dist-packages/ford/init.py", line 391, in run main(proj_data,proj_docs,md) File "/usr/local/lib/python3.8/dist-packages/ford/init.py", line 342, in main project = ford.fortran_project.Project(proj_data) File "/usr/local/lib/python3.8/dist-packages/ford/fortran_project.py", line 90, in init ford.sourceform.FortranSourceFile(os.path.join(curdir,item),settings, preprocessor, ext in self.fixed_extensions,incl_src=html_incl_src)) File "/usr/local/lib/python3.8/dist-packages/ford/sourceform.py", line 1052, in init FortranContainer.init(self,source,"") File "/usr/local/lib/python3.8/dist-packages/ford/sourceform.py", line 646, in init self.modules.append(FortranModule(source, File "/usr/local/lib/python3.8/dist-packages/ford/sourceform.py", line 789, in init raise ("Found procedure call in {}".format(type(self).name[7:].upper())) TypeError: exceptions must derive from BaseException

zerothi commented 3 years ago

Did anyone find the fix? @zerothi @vdikan @cmacmackin @zbeekman I have the same problem. and I'm trying to generate the documents in a system which has not Fortran compiler or MPI installed. I deleted all include mpif.90 from the code files, but I ended up with a new error.

Traceback (most recent call last): File "/usr/local/bin/ford", line 8, in sys.exit(run()) File "/usr/local/lib/python3.8/dist-packages/ford/init.py", line 391, in run main(proj_data,proj_docs,md) File "/usr/local/lib/python3.8/dist-packages/ford/init.py", line 342, in main project = ford.fortran_project.Project(proj_data) File "/usr/local/lib/python3.8/dist-packages/ford/fortran_project.py", line 90, in init ford.sourceform.FortranSourceFile(os.path.join(curdir,item),settings, preprocessor, ext in self.fixed_extensions,incl_src=html_incl_src)) File "/usr/local/lib/python3.8/dist-packages/ford/sourceform.py", line 1052, in init FortranContainer.init(self,source,"") File "/usr/local/lib/python3.8/dist-packages/ford/sourceform.py", line 646, in init self.modules.append(FortranModule(source, File "/usr/local/lib/python3.8/dist-packages/ford/sourceform.py", line 789, in init raise ("Found procedure call in {}".format(type(self).name[7:].upper())) TypeError: exceptions must derive from BaseException

I think not, the easiest thing is to pre-process the file using regular cpp/gfortran and then post-process the file.