I’m wondering if it there is a way to have, at the start of a module, a list of all module procedures in such a way that if a procedure is not contained in that list then is not callable or the Compiler will throw an error.
I find difficult to find what procedures are contained in a module by only examining the entire module content and having to look at procedures implementations.
Assuming you’re the one writing the code, you could declare everything in the module as private (default public) and explicitly list public procedures or variables. E.g.:
module m
implicit none
private
public :: sub1, sub2, ...
...
contains
subroutine sub1()
...
end subroutine sub1
subroutine sub2()
...
end subroutine sub2
...
end module m
What if a procedure is implemented in the contains section but I forgot to write it on the public declaration section? When the module contains hundred of procedure missing one is easy.
What I’m searching for is for the Compiler to throw an error if the procedure is in the contains section but not in the “list” section.
Yes, and with gfortran you can use the -Werror=unused-function option to prevent modules with dead code (private procedures that are not invoked within the module) from being compiled. With this option, for the file
module m
implicit none
private
public :: foo
contains
subroutine foo()
print*,"in foo"
end subroutine foo
!
subroutine bar()
print*,"in bar"
end subroutine bar
end module m
gfortran says
private.f90:10:14:
10 | subroutine bar()
| ^
Error: 'bar' defined but not used [-Werror=unused-function]
f951.exe: some warnings being treated as errors
My solution was to script an automatic way of generating explicit interfaces to “module procedures” but this can be alot of work, then put the implementations into one or more submodules.
I think my script was based on one by Metcalf et al.
Initial pain for long term gain.
The stdlib goes further and uses the explicit interfaces as the sole point of declaration of even purely internal variables.
More than happy to share my code if you think it might help.
@Rob777 , you will know the Fortran standard itself does not provide an easy/convenient solution for what you seek. But you can look into utilities elsewhere that come close to what you are after or write one yourself.
With standard Fortran the approach suggested by @milancurcic upthread can be a good practice that you will find generally helpful.
Other than that, you can consider a long-winded approach as follows:
Separate out all your implementations from interfaces,
Then ensure your MODULEs only have INTERFACEs and stuff, but noCONTAINS section,
Employ SUBMODULEs for all your implementations i.e., the CONTAINS sections only appear in your SUBMODULEs. And importantly
Use the MODULE clause on all your subroutines and functions.
This way the interface construct becomes the list you want. Then if something is in your CONTAINS section but not in your “list”, the compiler will diagnose the omission. You can see this in the example below:
module m
interface !<-- Here's your "list"
module subroutine sub()
end subroutine
end interface
end module
submodule(m) sm
contains
module subroutine sub() !<-- note the MODULE clause
print *, "Hello World!"
end subroutine
module function fun() result(r) !<-- note the MODULE clause
integer :: r
r = 42
end function
end submodule
C:\Temp>ifort /c /standard-semantics m.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.3.0 Build 20210609_000000
Copyright (C) 1985-2021 Intel Corporation. All rights reserved.
m.f90(10): error #6115: A separate interface body must have been declared in the program unit or an ancestor of the program unit for the separate module procedure. [FUN]
module function fun() result(r)
…
compilation aborted for m.f90 (code 1)
So you can see the compiler detects and reports an error about the function FUN since it’s not on the “list” err… the interface block. This approach will be seen by many as verbose and boilerplate but that’s the pain you’ve to put up with for your gain.
sounds like you have your answer, but as a footnote there are commands that can extract symbol names from object files and executables that can be useful, as well as compilers with options to list procedure names as they are compiled and so on. Before modules and generic names were introduced Unix/GNU-Linux users could usually just
enter
nm --defined-only *.o
there is an equivalent MSWIndows command but I do not remember it. The nm(1) command is still useful, but you have to know a little bit about how your compiler mangles procedure names contained in modules, and you often just get a list of all the specific procedures instead of a generic name (but if generic you already have a list in your global module area). So if it is just a one-time thing and you have the object or archive files for the routines you might just want to do an nm command, or look at what your compiler options provide or commands like objdump(1) or readelf(1); and even ld(1). I thought gfortran had an option to verbosely list the names as they were compiled; but perhaps not – I cannot find it. Some vendors supply commands to display information from mod files and/or have them hidden in their products that are primarily developer tools too; but that all gets very compiler-specific. But in some cases instead of writing or looking for parsers the nm(1) might be enough; and short of full language parsers just grepping for subroutine, function, and entry can tell you a lot; or a quick hack of f90split(1) might work; althought I do not know if the last version of f90split(1) knows about submodules.