makefilefortranfortran90fortran95

Clean way to separate functions/subroutine declaration from definition in Fortran 90


I am working on a big Fortran 90 code, with a lot of modules. What bothers me is that when I modify the inner code of a function inside a module (without changing its mask), my Makefile (whose dependencies are based on "use") recompile every file that "use" that modified module, and recursively.

But when modifying the inner code of a function without touching its input/output, recompiling other files than the modified one is useless, no?

So I would like to separate the function declaration from their definition, like with the .h files in C or C++. What is the clean way to do this? Do I have to use Fortran include/preprocessor #include, or is there a "module/use" way of doing this?

I have tried something like this, but it seems to be quite nonsense...

main.f90

program prog

  use foomod_header

  integer :: i

  bar=0
  i=42
  call foosub(i)

end program prog

foomod_header.f90

module foomod_header

  integer :: bar

  interface 
    subroutine foosub(i)
      integer :: i
    end subroutine
  end interface

end module foomod_header

foomod.f90

module foomod

  use foomod_header

  contains

  subroutine foosub(i)
    integer ::i

    print *,i+bar

  end subroutine foosub

end module foomod

Solution

  • If submodules aren't an option (and they are ideal for this), then what you can do is make the procedure an external procedure and provide an interface for that procedure in a module. For example:

    ! Program.f90
    PROGRAM p
      USE Interfaces
      IMPLICIT NONE
      ...
      CALL SomeProcedure(xyz)
    END PROGRAM p
    
    ! Interfaces.f90
    MODULE Interfaces
      IMPLICIT NONE
      INTERFACE
        SUBROUTINE SomeProcedure(some_arg)
          USE SomeOtherModule
          IMPLICIT NONE
          TYPE(SomeType) :: some_arg
        END SUBROUTINE SomeProcedure
      END INTERFACE
    END MODULE Interfaces
    
    ! SomeProcedure.f90
    SUBROUTINE SomeProcedure(some_arg)
      USE SomeOtherModule
      IMPLICIT NONE
      TYPE(SomeType) :: some_arg
      ...
    END SUBROUTINE SomeProcedure
    

    Some important notes: