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!
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.
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.