The continuing saga of modules in static libraries

The continuing saga of modules in static libraries

A lot of people are confused on this topic, and a lot has been said in this forum, for which I am grateful. Just when I think I understand it (sufficiently to get by), I run into examples that conflict with what I thought I knew. So I must rehash it again.

If a library project has subroutines SubA.f90, SubB.f90, ... and modules ModA.f90, ModB.f90, ... and these are all compiled into a file MyLib.lib, that file will contain object files SubA.obj, ..., ModA.obj, .... The build procedure will also create compiled module object files ModA.mod, ModB.mod, .... that are not contained in MyLib.lib. For these routines to be used by outsiders, I must distribute MyLib.lib and all of the .mod files, and provide instructions to make .lib accessible to their linker and the .mod accessible to their compiler. There are several ways to do this. It can get unwieldy and confusing. In spades sometimes, e.g. if you need to deal with debug and release combinations.

Now I come upon some discussion, and some direct experience, of cases that defy this understanding. I will try to guess some situations that may behave so.

Q1. Suppose the library contains a subroutine SubX that USEs a module ModX. If a client's outside program has a CALL SubX, is it correct to assume this gives his program access to all of the variables and procedures in ModX? This would seem logical, at least regarding the statements in SubX, because all of the compiler needs have already been performed in the creation of SubX.obj. But how about statements in the remainder of the program? What about procedures other than the one that calls ModX? 

Q2. Now consider a slightly different case: the library has a module ModY that CONTAINS a module procedure SubY. If a client program makes a call to SubY, will that also suffice? (I think not, since the program must first USE the module to gain access to the subroutine.)

Q3. Finally, suppose a library has a module ModZ and a simple subroutine called GetModZ that consists of the single line USE ModZ. Then if a client's program has the line CALL GetModZ () wherever it would normally have USE ModZ, would this provide the module access? Could this be a simpler way than distributing the .mod file to a client and providing a method for his compiler to access it? (I'm not seriously considering this, just trying to understand how things work--and it might be worth tinkering with.) 

5 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

 

Q3. Finally, suppose a library has a module ModZ and a simple subroutine called GetModZ that consists of the single line USE ModZ. Then if a client's program has the line CALL GetModZ () wherever it would normally have USE ModZ, would this provide the module access? Could this be a simpler way than distributing the .mod file to a client and providing a method for his compiler to access it? (I'm not seriously considering this, just trying to understand how things work--and it might be worth tinkering with.) 

I think this tells me where the source of confusion is.

OK.  Mod files are "just" compile-time declarations.   There are derived type declarations, interfaces for available interesting routines in the module, global names for interesting data that resides in the module, etc.    The actual code or the actual data storage for global variables really resides in the object file.   The "USE ModX" statement reads that set of declarations, interfaces, etc. and makes the names "known" to the rest of the program *at compile time*.  

Because these are just declarations, they probably will not change between a Debug and Release build, and so you only need to distribute one version of any particular .mod file.   (We distribute the Intel Fortran-supplied mod files in a directory tree that has the name "INCLUDE" in it.)

You can best decide how you'll distribute release vs debug libraries, and others here may have their own advice for how to do that.

Bottom line, the best thing is to devise a scheme where you can distribute both the necessary mod files and libraries.

            --Lorri

 

 

 

The phrases "access to all the variables and procedures in ModX" is potentially confusing.  For code in a scope to be able to access (directly) variables and procedures that are in a module the code needs to have a USE statement for that module (or another module that USE's the subject module), or the code needs to be inside the subject module.  I suspect you are not talking about this sort of "direct" access - rather you are querying whether the bits of the program that have already been compiled into your library (and those bits do contain USE statements and work with module variables directly) continue to work when you library is linked with some other code, in which case the answer to 1 is "Yes", the answer to 2 is that it is a programming error as per your parenthesised bit and the answer to 3 is "Yes, but you need GetModZ to have some executable code in order for it to be useful".

If code is being compiled that has a USE statement, then the compiler needs to be able to find the mod file for the subject module named in that use statement and, with the Intel compiler, the mod files for any modules that the subject module itself uses (and so on).  Once the code has been compiled mod files become irrelevant.  If there's no USE statement in code being compiled, then the compiler doesn't need any mod files.

An example below.  I'm not recommending this approach (because the absence of explicit interfaces gives an unacceptable (in my opinion) risk of client programmer error)... just explaining.  You can provide interface blocks for the external procedures in source form or as a small "stand-alone" module for your clients to use, but then you, as the developer of the library, need to make sure that those interface blocks are always consistent with the interface of the external procedures in your library.  If you don't ensure that consistency, your clients will get very cross.

!--- Client code compiled long after the library has been built.

PROGRAM ClientCode
  ! No use statement here - no mod files needed to compile this.
  ! Can call LibraryProcedure because it is an external procedure.
  CALL LibraryProcedure(integer_arg)
  ! CANNOT call ModuleProcedure, cannot access ModuleVariable.
  !...
  ! In the absence of other information, such as an interface body, 
  ! the compiler will not detect argument mismatches and the newer F90+ 
  ! dummy argument features (assumed shape, pointer, allocatable, optional, 
  ! polymorphic, ...) cannot be used.
  
  CALL LibraryProcedure(real_arg)    ! Uh oh...
  
END PROGRAM ClientCode



!--- Library code compiled separately.

! External procedure for client code to call.
SUBROUTINE LibraryProcedure(integer_arg)
  USE LibraryModule
  !...
  ! Can access ModuleVariable, can call ModuleProcedure because we 
  ! have a USE statement for the relevant module and those names are 
  ! public.
  ModuleVariable = 99
  CALL ModuleProcedure
  !...
END SUBROUTINE LibraryProcedure

MODULE LibraryModule
  !...
  INTEGER, PUBLIC :: ModuleVariable
  PUBLIC :: ModuleProcedure
  !...
CONTAINS
  SUBROUTINE ModuleProcedure
    ! ... do stuff with ModuleVariable ...
  END SUBROUTINE ModuleProcedure
END MODULE LibraryModule

 

"Q3. Finally, suppose a library has a module ModZ and a simple subroutine called GetModZ that consists of the single line USE ModZ. Then if a client's program has the line CALL GetModZ () wherever it would normally have USE ModZ, would this provide the module access?"

No. Calling getModZ provides no access to anything else in the module. The clients program must have use ModZ for data and routines in ModZ to be acccessible. In fact they could not even call getModZ without a use statement.

Quote:

dboggs wrote:

A lot of people are confused on this topic, and a lot has been said in this forum, for which I am grateful. Just when I think I understand it (sufficiently to get by), I run into examples that conflict with what I thought I knew. So I must rehash it again.

If a library project has subroutines SubA.f90, SubB.f90, ... and modules ModA.f90, ModB.f90, ... and these are all compiled into a file MyLib.lib, that file will contain object files SubA.obj, ..., ModA.obj, .... The build procedure will also create compiled module object files ModA.mod, ModB.mod, .... that are not contained in MyLib.lib. For these routines to be used by outsiders, I must distribute MyLib.lib and all of the .mod files, and provide instructions to make .lib accessible to their linker and the .mod accessible to their compiler. There are several ways to do this. It can get unwieldy and confusing. In spades sometimes, e.g. if you need to deal with debug and release combinations.

Now I come upon some discussion, and some direct experience, of cases that defy this understanding. I will try to guess some situations that may behave so.

Q1. Suppose the library contains a subroutine SubX that USEs a module ModX. If a client's outside program has a CALL SubX, is it correct to assume this gives his program access to all of the variables and procedures in ModX? This would seem logical, at least regarding the statements in SubX, because all of the compiler needs have already been performed in the creation of SubX.obj. But how about statements in the remainder of the program? What about procedures other than the one that calls ModX? 

Q2. Now consider a slightly different case: the library has a module ModY that CONTAINS a module procedure SubY. If a client program makes a call to SubY, will that also suffice? (I think not, since the program must first USE the module to gain access to the subroutine.)

Q3. Finally, suppose a library has a module ModZ and a simple subroutine called GetModZ that consists of the single line USE ModZ. Then if a client's program has the line CALL GetModZ () wherever it would normally have USE ModZ, would this provide the module access? Could this be a simpler way than distributing the .mod file to a client and providing a method for his compiler to access it? (I'm not seriously considering this, just trying to understand how things work--and it might be worth tinkering with.) 

dboggs,

Have you referred to any of the books suggested by Dr. Fortran, or perhaps "Fortran 90 for Scientists and Engineers," by Larry Nyhoff and Sanford Leestma?  Just as "a picture is worth a thousand words", time spent studying these books, especially the one by Nyhoff and Leestma, will provide you with much better understanding of how modules work than countless responses on this forum or any other - seriously.

Leave a Comment

Please sign in to add a comment. Not a member? Join today