LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Fortran 90 AND shared libraries. (https://www.linuxquestions.org/questions/programming-9/fortran-90-and-shared-libraries-699152/)

Gamma_User 01-22-2009 10:38 AM

Fortran 90 AND shared libraries.
 
I created a shared library with my most used mathematical functions using fortran 90. I intended to make my life easier, since I thought I could call the shared functions as simple as I call an intrinsic function like sin(x) or cos(x). However, I noted the functions in the shared library are treated as EXTERNAL functions. At this point my life became hard, because I have to interface my shared functions all the time. Is there a way to overcome this problem using fortran 90? Does this problem appear when using fortran 95?

colucix 01-23-2009 03:54 AM

Using Fortran 90/95 you can either write a library using module interfaces or just simple functions. I think it all depends on how did you wrote the function library and how did you compile/link it. Consider the following (very simplified) example. I am using the Intel fortran compiler on this machine:
Code:

$ ls
my_sum.f90  test.f90
$ cat my_sum.f90
      FUNCTION my_sum(x,y)
      REAL:: my_sum
      REAL:: x, y
      WRITE(*,*) 'x = ', x
      WRITE(*,*) 'y = ', y
      my_sum = x + y
      END
$ ifort -c my_sum.f90
$ ls
my_sum.f90  my_sum.o  test.f90
$ ld -o libtest.so.1 -dy -G -h libtest.so.1 *.o
$ ls
libtest.so.1  my_sum.f90  my_sum.o  test.f90
$ ln -s libtest.so.1 libtest.so
$ ls
libtest.so  libtest.so.1  my_sum.f90  my_sum.o  test.f90
$ cat test.f90
      PROGRAM test
      REAL:: a, b, my_sum
      READ(*,*) a
      READ(*,*) b
      R = my_sum(a,b)
      WRITE(*,*) 'my_sum = ',R
      END PROGRAM test
$ ifort -L. test.f90 -ltest
$ ls
a.out  libtest.so  libtest.so.1  my_sum.f90  my_sum.o  test.f90
$ export LD_LIBRARY_PATH=$(pwd):${LD_LIBRARY_PATH}
$ echo $LD_LIBRARY_PATH
/home/colucix/test:/opt/intel/fc/10.1.015/lib:/opt/intel/cc/10.1.015/lib
$ ldd a.out
        linux-gate.so.1 =>  (0x0041e000)
        libtest.so.1 => /home/colucix/test/libtest.so.1 (0x00475000)
        libm.so.6 => /lib/libm.so.6 (0x004e3000)
        libc.so.6 => /lib/libc.so.6 (0x00111000)
        libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x002da000)
        libdl.so.2 => /lib/libdl.so.2 (0x0050c000)
        /lib/ld-linux.so.2 (0x00380000)
$ ./a.out
6
9
 x =    6.000000   
 y =    9.000000   
 my_sum =    15.00000
$


Gamma_User 01-23-2009 02:15 PM

Ok, I realized. But, suppose instead of my_sum.f90 I have a function
getsize(X) in a separated file:
Code:

function getsize(X)
  implicit none
  integer :: getsize
  real, dimension (:) :: X
  getsize=size(X)
end function getsize

In this case I need to interface the function getsize(X) in the main code:
Code:

program main
  implicit none
  real, dimension (10) :: A
! Interfacing the function getsize
  interface
    function getsize(X)
      implicit none
      integer :: getsize
      real, dimension (:) :: X
    end function getsize
  end interface

  write(*,*) getsize(A)
end program main

otherwise I'll get an error. That is the problem, I think it is not so practical to interface a shared function all the time.

You said it is possible write a library using module interfaces. I tried to do that, but it did not work. Suppose instead of the code above I have (in a separated file)
Code:

module mysize
contains
  function getsize(X)
    implicit none
    integer :: getsize
    real, dimension (:) :: X
    getsize=size(X)
  end function getsize
end module mysize

and as a main program
Code:

program main
  use mysize
  implicit none
  real, dimension (10) :: A

  write(*,*) getsize(A)
end program main

How can I proceed?

Thanks a lot!





Quote:

Originally Posted by colucix (Post 3418366)
Using Fortran 90/95 you can either write a library using module interfaces or just simple functions. I think it all depends on how did you wrote the function library and how did you compile/link it. Consider the following (very simplified) example. I am using the Intel fortran compiler on this machine:
Code:

$ ls
my_sum.f90  test.f90
$ cat my_sum.f90
      FUNCTION my_sum(x,y)
      REAL:: my_sum
      REAL:: x, y
      WRITE(*,*) 'x = ', x
      WRITE(*,*) 'y = ', y
      my_sum = x + y
      END
$ ifort -c my_sum.f90
$ ls
my_sum.f90  my_sum.o  test.f90
$ ld -o libtest.so.1 -dy -G -h libtest.so.1 *.o
$ ls
libtest.so.1  my_sum.f90  my_sum.o  test.f90
$ ln -s libtest.so.1 libtest.so
$ ls
libtest.so  libtest.so.1  my_sum.f90  my_sum.o  test.f90
$ cat test.f90
      PROGRAM test
      REAL:: a, b, my_sum
      READ(*,*) a
      READ(*,*) b
      R = my_sum(a,b)
      WRITE(*,*) 'my_sum = ',R
      END PROGRAM test
$ ifort -L. test.f90 -ltest
$ ls
a.out  libtest.so  libtest.so.1  my_sum.f90  my_sum.o  test.f90
$ export LD_LIBRARY_PATH=$(pwd):${LD_LIBRARY_PATH}
$ echo $LD_LIBRARY_PATH
/home/colucix/test:/opt/intel/fc/10.1.015/lib:/opt/intel/cc/10.1.015/lib
$ ldd a.out
        linux-gate.so.1 =>  (0x0041e000)
        libtest.so.1 => /home/colucix/test/libtest.so.1 (0x00475000)
        libm.so.6 => /lib/libm.so.6 (0x004e3000)
        libc.so.6 => /lib/libc.so.6 (0x00111000)
        libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x002da000)
        libdl.so.2 => /lib/libdl.so.2 (0x0050c000)
        /lib/ld-linux.so.2 (0x00380000)
$ ./a.out
6
9
 x =    6.000000   
 y =    9.000000   
 my_sum =    15.00000
$



colucix 01-26-2009 02:29 AM

Your last example works for me. Here is an excerpt from Stephen Chapman's "FORTRAN 95/2003 for scientist and engineers" (don't waste time to look for it in the web... I have the book) ;)
Quote:

The easiest way to create an explicit interface is to place procedures in a module, and then use that module in the calling program unit. Any procedures placed in a module will always have an explicit interface.
So I just tried the code you provided and it works in the following way:
Code:

$ cat mysize.f90
module mysize
contains
  function getsize(X)
    implicit none
    integer :: getsize
    real, dimension (:) :: X
    getsize=size(X)
  end function getsize
end module mysize
$ ifort -c mysize.f90
$ ld -o libtest.so.1 -dy -G -h libtest.so.1 *.o
$ ln -s libtest.so.1 libtest.so
$ cat main.f90
program main
  use mysize
  implicit none
  real, dimension (10) :: A
  write(*,*) getsize(A)
end program main
$ ifort -L. main.f90 -ltest
$ ls
a.out  libtest.so  libtest.so.1  main.f90 mysize.f90  mysize.mod  mysize.o
$ export LD_LIBRARY_PATH=$(pwd):${LD_LIBRARY_PATH}
$ ./a.out
          10


Gamma_User 01-26-2009 07:39 AM

Hi colucix!

Perhaps the program worked because the mysize.mod and mysize.o files were in the directory. Try to remove them before using the command
Code:

ifort -L. main.f90 -ltest
Look at what happened in my computer:
Code:

hoggar%~/fortran/code ls
mysize.f90  uselib.f90
hoggar%~/fortran/code cat mysize.f90
module mysize
contains
  function getsize(X)
    implicit none
    integer :: getsize
    real, dimension (:) :: X
    getsize=size(X)
  end function getsize
end module mysize
hoggar%~/fortran/code cat uselib.f90
program main
  use mysize
  implicit none
  real, dimension (10) :: A

  write(*,*) getsize(A)
end program main
hoggar%~/fortran/code gfortran -c mysize.f90
hoggar%~/fortran/code ld -o libtest.so.1 -dy -G -h libtest.so.1 *.o
hoggar%~/fortran/code ln -s libtest.so.1 libtest.so
hoggar%~/fortran/code rm *.mod *.o
hoggar%~/fortran/code ls
libtest.so  libtest.so.1  mysize.f90  uselib.f90
hoggar%~/fortran/code gfortran -L. uselib.f90 -ltest             
uselib.f90:2.12:

  use mysize
            1
Fatal Error: Can't open module file 'mysize.mod' for reading at (1)


Thank you!

Quote:

Originally Posted by colucix (Post 3421362)
Your last example works for me. Here is an excerpt from Stephen Chapman's "FORTRAN 95/2003 for scientist and engineers" (don't waste time to look for it in the web... I have the book) ;)

So I just tried the code you provided and it works in the following way:
Code:

$ cat mysize.f90
module mysize
contains
  function getsize(X)
    implicit none
    integer :: getsize
    real, dimension (:) :: X
    getsize=size(X)
  end function getsize
end module mysize
$ ifort -c mysize.f90
$ ld -o libtest.so.1 -dy -G -h libtest.so.1 *.o
$ ln -s libtest.so.1 libtest.so
$ cat main.f90
program main
  use mysize
  implicit none
  real, dimension (10) :: A
  write(*,*) getsize(A)
end program main
$ ifort -L. main.f90 -ltest
$ ls
a.out  libtest.so  libtest.so.1  main.f90 mysize.f90  mysize.mod  mysize.o
$ export LD_LIBRARY_PATH=$(pwd):${LD_LIBRARY_PATH}
$ ./a.out
          10



colucix 01-26-2009 08:03 AM

It works for me. But...
1) you have to preserve the mysize.mod and put it in some Include path, since it is used during the compilation of the main program
2) you have to tell to the system where to find the shared library, that is change the LD_LIBRARY_PATH environment variable accordingly OR use ldconfig to add the directory containing the libraries to the cache of the shared objects.
This equals to provide a devel package, that is: if you want to share with others the newly created libraries you have to provide both the libs and the includes. The library will be enough for already compiled executables linking against it. In addition the .mod will be necessary to develop and compile new applications!

I try again, just to be sure:
Code:

$ pwd
/home/colucix/test_lib
$ ls
include  lib  main.f90  mysize.f90
$ ifort -c mysize.f90
$ ld -o libtest.so.1 -dy -G -h libtest.so.1 *.o
$ ls
include  lib  libtest.so.1  main.f90  mysize.f90  mysize.mod  mysize.o
$ rm mysize.o
$ mv libtest.so.1 lib/
$ mv mysize.mod include/
$ ln -s libtest.so.1 lib/libtest.so
$ ls -l lib/
total 12
lrwxrwxrwx 1 colucix users  12 Jan 26 14:57 libtest.so -> libtest.so.1
-rwxr-xr-x 1 colucix users 1327 Jan 26 14:54 libtest.so.1
$ ifort -I./include -L./lib main.f90 -ltest
$ export LD_LIBRARY_PATH=$(pwd)/lib:${LD_LIBRARY_PATH}
$ echo $LD_LIBRARY_PATH
/home/colucix/test_lib/lib:/opt/intel/fc/10.1.015/lib:/opt/intel/cc/10.1.015/lib
$ ./a.out
          10



All times are GMT -5. The time now is 06:23 AM.