Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

library and/or module

Status
Not open for further replies.

salgerman

Programmer
Jan 14, 2010
520
0
0
US
O.k., as I might have mentioned before, I have used F77 for a while and I am yet to start practicing F90 habits. Now, I want to start.

I have read about modules but the book does not include real examples...can I get some help?

Currently (F77), my "libraries" are simply a set of subroutines that I compiled into *.o files and put them into *.a file; then, I place such *.a in my .../lib directory. When I compile my program that use such library, I pass such directory in the -L flag.

The programs that use the library do not need much; if anything, an include file with necessary declarations. The include file is put in .../include and I pass such path with -I flag at compile time.

How is this done in F90?
What does my library file look like?
Is it enclosed in a module? Where I put my variables and subroutines?
How do I compile this module and how do I deploy it into my library directory?
How do I compile the program that uses the library?

Maybe a short example would be shorter than any explanation?

Thanks in advance for all the hints that you might offer.

Germán

 
There is no change in the library management, because the libraries are not a part of Fortran language. So you have to proceed following the same previous way.

The only difference comes from the existence of new "include" files which are the module files (*.mod) generated by the compiler. They are not exactly include files but, finally, they behave in the same way. For instance, the flag -I is useful to indicate the location of *.mod files used by a fortran source file using these modules (via the F90 fortran instruction USE).

François Jacq
 
There is a little difference from include-files to modules - but this might be important.

If you put your type declarations in an include file, say include.txt contains

real r(10)
integer int(10)

and you include this in your routines, this is just a bunch of statements that are compiled and executed. So each routine where you included this file will have the local variables r and i defined. If you assign a value to r in subroutine 1 this does not affect r in subroutine b.

Code:
program prog
include 'include.txt'
r(1) = 1.0
i(1) = 1
call sub ()
stop
end

subroutine sub ()
include 'include.txt'
write (*,*) r(1), i(1)
return
end

should write
0.0 0
if you do not get an errormessage about uninitialised varaibles anyway.

If you do the same in a module it is a completely different situation. lets say

Code:
module data
    real r(10)
    integer i(10)
end module

program prog
use data
r(1) = 1.0
i(1) = 1
call sub ()
stop
end

subroutine sub ()
use data
write (*,*) r(1), i(1)
return
end

The module provides the data structure for the variables to be saved to, that is all routines that use this module access the same data. That is why the code above should write
1.0 1
to your screen.

Norbert


The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.
 
ooops,
what went wrong with my post? I typed it in just as allways, and now it looks as if all <return>s are gone. Or does it look like this only on my screen ?

If it is not just my screen, what could have been wrong ??

Norbert


The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.
 
Fraçois: Thanks for the hint; I did not know what to do with the *.mod file. So, THAT is the file that I place in the .../include directory.

Norbert: Thanks for verifying that. I did know about the "include.txt" only producing local variables and that is why my "include.txt" files include common blocks, instead of just variable declarations.

Anyway, I tried a simple example and things seems to be working fine...but things are not working out in my actual program...

...the difference between my simple example and the actual program is that my actual program has a couple of functions in the 'contains' clause of the module and I am getting an "undefine reference to" kind of error. There are no complains about the subroutines, just about the functions.

What am I missing?

For example, a module like this works:
Code:
module flib
    implicit none    
    integer :: a 
contains
    subroutine doubleit()
        a = 2*a
    end subroutine doubleit    
end module flib

But one that includes functions does not:
Code:
module flib
    implicit none    
    integer :: a 
contains
    subroutine doubleit()
        a = 2*a
    end subroutine doubleit    

    real function rf1(a,b,c)
        !do something with a,b,c
        !return rf1
    end function rf1
end module flib

What do I need to do to resolve this?

Thanks,

Germán
 
Germàn

question up front: do the code snippets look okay for you ? On my screen I am missing all returns, the code is all on one line. Same to you ? I am recovering from a malware infection and this might be a remnant from it....

To your problem:

Modules are tricky items.

First of all, they add (!) their variable definitions to what you have in your program where you use it. If you have declared rValue in your module and in your routine this conflicts and you get an errormessage at compiletime.

I am not a big friend of putting routines in modules.

First: I do not see the advantage. According to my textbook putting procedures into a module allows the compiler better errorchecking for this is an explicit interface. This is something similar as in C where you declare all your function prototypes at the beginning so the compiler knows from the beginning what to expect from the data and can check the calls for number of arguments, their types and such.

Second: I do not fully understand this contains-statement in modules, I only assume it does the same as when used in normal routines, my docs are not very illuminating here.
If you use CONTAINS in a routine it declares the following function or subroutine as internal to the routine it is contained in. This means the contained procedure and the routine that contains it are sharing their data - unless you declare them otherwise. And here this seems to be the same: Your subroutine works without you passing the variable a in the argument list because it is taken from the shared data.

But if you reference a in the argument list, then the compiler assumes this is not the shared data but creates a new variable local to the procedure, even if it has the same name as the variable in the modules body. So in your function a, b and c are local variables that need a type declaration for you used 'implicit none' in your module. If you would enter a in your subroutine's argument list you would have the same problem there. So enter type declarations for a, b and c into your function and it should be fine - at least if it was true what I am assuming about this CONTAINS-statement in modules.

And because I hate this mess up I do not include routines into a module.

Norbert



The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.
 
Norbert:

First, the appearance of this webpage is fine for me.

Second...I am lost. By the way, I am NOT having a problem with the variables themselves, the error message refers to the functions...they are not recognized.

I am thinking subroutines don't really need a prototype, but functions typically do...that's the part I think I am missing, I just don't know where or how to do that via module (interfaces?).

Anyway, let me try taking the subroutines and functions out of the contains (and module) and putting them by themselves...let's see how things look like and where it is I need to place the various files.

Germán

 
I think that you miss an important subtle thing in the second example :
Code:
module flib
    implicit none    
    integer :: a 
contains
    subroutine doubleit()
        a = 2*a
    end subroutine doubleit    

    real function rf1(a,b,c)
        !do something with a,b,c
        !return rf1
    end function rf1
end module flib

In the function "rf1", "a" is a dummy argument which has nothing to do with "integer :: a" of the module. In practice, these two variables "a" are never related together. Remember that the argument "a" of the function "rf1" is a dummy argument : you may change its name withou changing the result. To avoid confusion, I suggest for instance "aa" instead of "a".

François Jacq
 
I entered your snippet into my compiler and it complained about the return argument of the function.

it must not be

return rf1

but simply

Code:
module flib
   integer a

   contains

   subroutine doubleit ()
      a = 2 * a
   end subroutine doubleit

   real function rf1 (a, b, c) 
      rfl = a + b + c
      return
   end function rf1
end module flib

Then it compiles and links all right with a main program

Code:
program test
use fLib
stop
end

Norbert

The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.
 
In your function rf1() you don't need to use return. You can write it simply so:
Code:
real function rf1 (a, b, c)
  real, intent(in) :: a, b, c 
  rfl = a + b + c
end function rf1
´
Other possible way is to use result, i.e.
Code:
function rf1 (a, b, c) result(res_rf1)
  real, intent(in) :: a, b, c 
  real :: res_rf1 
  res_rfl = a + b + c
end function rf1
 
Mikrom,

you are of course right, you do not need to use the return statement. But some things just are a kind of programming practice to make your code more readable. Just like usíng

end function rf1

intead of simply

end

which would do the job just the same. I prefer to really see where execution of my prog ends - while most of my routines have more than one return-point.

And using the result clause does not contribute to the readability of the code either.

Norbert

The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.
 
Well, I guess my short example was not exactly as my real program. In my real program, I have a few subroutines and a few functions in the "contains" clause of the module; and the very first subroutine calls upon a function shown below and such function, in turn, calls upon other two functions declared further down.

The subroutine and functions as inherited had internal declarations (function prototypes) for the functions to be used to match the type, etc, but that was not quite cutting...

The thing is than in fortran subroutines are very popular and they are very friendly...you never have to do anything about them...but this time I had a couple of functions.

I was hoping for an elegant solution (interfaces?) but I don't know it, yet; so, I have had to resort to a trick I learned in C...since C does not have subroutines and everything is a function, you need function prototypes most of the time...unless, of course, your place your functions in your code in the "correct" order....the one that does not call anything, first; then the one that calls that one, so on...from the "back" to the "front"...

...anyway, by listing my functions first and THEN the subroutines that called them, my program now compiles and runs.

...I thought I shared.

Germán


so, I resorted to a trick I learned in C

It compiles, but I cannot get reached the function rf1, but if I try to actually use, make a call to the function rf1 from my the test program, it is totally ignored as if the command wasn't even there.
 
oops...left over text...is there a way to come back and edit a previous post? Other forums have such ability.
 
gummibaer said:
most of my routines have more than one return-point
In difference to you, I try to write functions with single exit point if possible. IMO, then the functions are better to understand and to debug. Also the resources allocated by the function could be better cleaned on one exit point. But this is my personal coding style which I learned when structured programming was popular :)

gummibaer said:
using the result clause does not contribute to the readability of the code either
But with result() it's simpler to create a function which returns an array or an own defined compound datatype. For these cases I find this feature very useful and IMO it contributes to the readability of the code too.
 
oops...left over text...is there a way to come back and edit a previous post? Other forums have such ability.

Unfortunately not, I would like to edit some of my posts very urgently [blush]. Maybe we could apply to the moderators of this board to include such a feature.

mikrom,
this is the advantage of result(): to be able to define arrays or derived data types as results of functions. I do not know of any different approach. For Windows programming you define call back functions that return to the OS whenever a task is completed. This leads to numerous returns within one procedure.


Germàn,

I fail to see your problem. I have all my functions and subroutines in a library - in fact this is organized by Visual Studio - but still it is libraries. I have them there in an alphabetical order for easy to localise them, not caring about the sequence as they are used.

Other than C, Fortran really needs explicit interfacing on very rare occasions only (if you use optional arguments for instance), as long as you stick to fortran and do not do mixed language programming.

But if you want explicit interfacing anyway, write the prototypes of all your subprograms and functions into one big include-file and include this to all your programs. I just checked on my compiler, there is no problem if you add an interface to a function or subroutine to itself, so you need only one include-file for this.

BTW: I prefer logical functions to subroutines. This way you have an easy mechanism to indicate to the calling routine if the function/subroutine performed successfully.

Instead of

call mysub (parameter, iError)
if (iError .ne. 0) then
...

I just can wright

if (.not. myfunc (parameter)) then
...



Norbert


The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.
 
Just to clarify:

for explicit interfacing write a includefile like

Code:
interface
    subroutine Sub1 (ra, rb, rc, id, ie)
        real ra, rb, rc
        integer id, ie
    end subroutine
    real function Func1 (ra, rb, rc, id, ie)
        real ra, rb, rc
        integer id, ie
    end function
    ...
    ...
end interface

and include this to all your procedures just in front of the type declarations.

Otherwise you have to declare the types of your functions (that is the only thing that a function needs more than a subroutine). Once again write an includefile, this time

Code:
    real Func1
    integer Func2
    logical Func3

with just all the names and types of all your functions. You can include this to all your programs as well and you have all the type declarations available anytime without further much ado. You can use this include even in the functions themselves, you just must not declare the function type in the first line:

Code:
    function Func1 (arg1, arg2)  ! instead of 'real function Func1 (...)'
    use myModule    
    implicit none
    real ...
    integer ...
    include 'typedef.txt'       ! in there 'real Func1' is declared
    ....

You do not have to bother in any way about the sequence of the entries in your includes.
I guess this is as comfortable as it can get.

Norbert

The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.
 
You know, somewhere in my head I kept musing on this topic.

And then it occurred to me that I should mention that in any case, if you use modules or includes, there is a penalty to pay for the convenience. The penalty is, that whenever you edit the includes or modules, all the program units that reference it, become outdated and need recompilation. If you have an environment that takes care of this, this is okay, but if you have to manage this manually this can become a nuisance.

One of the reasons I do not use including is, that a full compile of my prog lasts quite long. Not because my prog is such a big thing. But because my virus protection is Norton 360 and this hogs most of my system's resources most of the time. I can easily have lunch during a complete rebuild of my project. But this will change once I replaced Norton 360 with something not that demanding.

Norbert


The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.
 
Gotta catch a flight, I'll see if tomorrow I can post the skeleton of my code to show what I am trying to achieve.

Norton?!?! OMG! I stopped using it when it first went to the version that became such a CPU hogger. I would recommend using something a bit easier on the CPU that is free. Take a look at Avast! They are a company that sale virus protection to corporations, but offer a free version for personal use; this is for 24/7 protection. For virus scan of hard disk once in a while, you can look into Search and Destroy.

gotta run...

Germán
 
Well...I am confused, and I need to take a better look at my program...I put together a small example (like above) that I thought reflected the same thing that I am doing in my actual program and the d..m thing worked...no interfaces, subroutine and function inside module->contains, listed in no particular order, etc...and it worked...

So, thanks for all the hints; but I think I need to go back and strip my program to its bones and double check what's going.

In any case, here are my skeleton test files:

Library file flib.f90:
Code:
module flib
    implicit none    
    real :: a 
contains
    subroutine doubleit()
        write(*,*) ' doubling a'
        a = times2(a)
    end subroutine doubleit    
    
    real function times2(x)
        real x
        write(*,*) ' returning 2 times x'
        times2 = 2.0*x
        return
    end function times2
end module flib

! Compiling, deploying instructions:
!
! g95 -o flib.o -c flib.f90
! ar -crs libflib.a flib.o
!
! cp flib.mod ../include
! cp libflib.a ../lib

Program using library, try.f90:
Code:
program try     
    use flib

    a = 3.0
    write(*,*) 'a = ', a
    call doubleit()
    write(*,*) 'a = ', a
end 

! compiling instructions:
!
! g95 -I../include -o try.o -c try.f90
! g95 -L../lib     -o try      try.o  -lflib
 
One final hint:
My textbook recommends putting procedures in modules and enter the modules into the routines that use this procedure.

This might be a good idea from a pure programming point of view, even if I fail to see it - but not if you are embeded in an organisation with more than one individual at the programming keyboard.

Reason:

Whenever you modify anything within a module - including the program within the module - and bring it to your library then all the programs using this module become outdated at once and need to be recompiled and relinked. If it is only you who uses the library then this might be okay if you have an IDE that follows up on these things. But if your library might be used by other programmers in your organisation then you need to set up an update scheme that includes that all programmers recompile (!!), relink and if necessary redistribute their progs. If the recompile is postponed someone might find out later, when your edit is long past and forgotten history, that suddenly unexpliccable errors come out by 'I just did recompilé, did not change a thing and the prog now produces garbage.'

I would prefer not to.

Norbert

The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top