How to get a list of module procedures

Hello Everyone,

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.

Thanks

2 Likes

Hi Rob,

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
2 Likes

Thank you.

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
2 Likes

If it is not listed in the public section and is called from outside, the compiler will print an error.
But no error if it is not called.

If I don’t know about the existence of that procedure I can’t even call it.

When one has hundreds of procedures it would be helpful to have them listed in top of the module with a double check from the Compiler.

Thanks

The option given by @Beliavsky will detect the not listed procedures, assuming they are not called from other procedures inside the module.

1 Like

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:

  1. Separate out all your implementations from interfaces,
  2. Then ensure your MODULEs only have INTERFACEs and stuff, but no CONTAINS section,
  3. Employ SUBMODULEs for all your implementations i.e., the CONTAINS sections only appear in your SUBMODULEs. And importantly
  4. 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.

Thank you all for helping me.

@NormanKirkby thank you. I think sharing your code can be beneficial even if it’s not the exact solution to my original problem.

@FortranFan thank you. I think your solution is the only way to solve my problem using only standard Fortran.

I’m also thinking of writing a simple python script to check for procedures contained in the contains section but not listed as public or private.

Again Many thanks to everyone for your help.

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.

2 Likes

Please try this link