Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
New Contributor I
35 Views

Interface to functions in an external module

I am collecting some routines that are in various modules into a static library library. These routines are common to a number of our programs. They take a long time to compile and are rarely changed; thus, at least to me anyway, are great candidates for extraction to a static library that will link with the programs that depend on them.

However, three of the routines I want to extract to the static library use functions from a module defined in each program itself. Here is the basic definition of the module:

      MODULE PROGRAMPROPERTIES
!-
      PUBLIC GET_PROGRAM_NAME
      PUBLIC GET_PROGRAM_VERSION
      PUBLIC GET_REVISION_DATE
      PUBLIC WRITE_PROG_DATA_TO_TRACE
!-
      CONTAINS
...
      END MODULE PROGRAMPROPERTIES

All of the public definitions are functions that are identically defined as follows:

      FUNCTION GET_PROGRAM_VERSION() RESULT(c_program_version)

      CHARACTER (LEN=200) :: c_program_version ! The Program Version

      END FUNCTION GET_PROGRAM_VERSION

Basically, the module exists in each program to return its name and version info, etc.

The three procedures will not compile without access to the module so I figure that a way around this is to declare an interface in the library procedures that would then call the functions in the PROGRAMPROPERTIES module in each program - that is assuming I understand the use of the interface keyword in FORTRAN. (While I have developed a taste for FORTRAN, I am primarily a C#/C++ programmer and understand the use on interfaces in that world quite well.)

Here is an example function that I want to extract to the static library. Note it contains a use statement for the PROGRAMPROPERTIES module, and that I am not the original author of the routines.

      FUNCTION OUT_REVISION () RESULT (i_void)
!-
      USE PROGRAMPROPERTIES
      USE COMMAND_LINE_FUNCTIONS
      USE F95_UTILITY_FUNCTIONS      
!-
      CHARACTER (LEN=200) :: c_file            ! ini file name
      CHARACTER (LEN=200) :: c_ident           ! Defines the identifier in the ini file
      CHARACTER (LEN=200) :: c_sect            ! Defines the section in the ini file
      CHARACTER (LEN=200) :: c_revision        ! Revision of the program
!-
      INTEGER i_10   ! The number 10
      INTEGER i_void ! Return Zero
!-
      c_revision = GET_REVISION_DATE() ! Returns the revision date of the program.
      i_void  = 0
!-
      c_file = ini_readcla_3 () ! Read the third command line argument
!-
      c_sect  = 'VERSION INFO'
      c_ident = 'REVISIONDATE'
      i_10    = 10
      i_void  = SET_CASE_SENSITIVE (.FALSE.)      
      i_void  = ini_writeppsl (c_sect,c_ident,c_revision,i_10,c_file)
!-
      END FUNCTION OUT_REVISION

Each function is itself contained in a module that I hope to make part of the static library.

I am looking for an example of how I would replace the use statement for the PROGRAMPROPERTIES module with an interface so that I can compile the library without the PROGRAMPROPERTIES module, and have the library routines call the module functions when necessary.

Anyone have any idea how to accomplish this?

Thanks in advance!

0 Kudos
2 Replies
Highlighted
Black Belt
35 Views

What's best depends a lot on the structure of your static library, but you can pass procedures - so the simplest solution is just to pass the procedures as required.

! In the static library...
MODULE MyStaticLibrary
  ...
  FUNCTION OUT_REVISION(GET_REVISION_DATE) RESULT(i_void)
    ...
    INTERFACE
      FUNCTION GET_REVISION_DATE()
        IMPLICIT NONE
        CHARACTER(200) :: GET_REVISION_DATE
      END FUNCTION GET_REVISION_DATE
    END INTERFACE
    ...
    c_revision = GET_REVISION_DATE()
  END FUNCTION OUT_REVISION
END MODULE MyStaticLibrary



! In the client program...

PROGRAM MyClientProgram
  USE MyStaticLibrary
  ...
  INTEGER :: discarded_results_suggest_function_should_be_a_subroutine
  ...
  discarded_results_suggest_function_should_be_a_subroutine = OUT_REVISION(  &
      get_revision_date_for_my_client_program )
  ...
CONTAINS
  FUNCTION get_revision_date_for_my_client_program() RESULT(d)
    CHARACTER(200) :: d
    d = 'Tomorrow'
  END FUNCTION get_revision_date_for_my_client_program
END PROGRAM MyClientProgram

Once passed, a static library can "remember" the procedures passed into it by storing the procedures in procedure pointers.

Going further, you could bundle the interfaces for those four procedures up into a derived type with bindings or similar.

0 Kudos
Highlighted
New Contributor I
35 Views

Thanks for your reply.

Your post gave me the idea to define a custom type in the static library, then populate the variables in the type with the values from each application (obviously with a USE statement in the relevant application code) at startup. Each application will have a unique instance of the custom type, and the static library will have access to that type so that it can return the appropriate values for each application as necessary. That should work and will simplify the code. It seems like it will be about the same amount of work.

Thanks again!

0 Kudos