Undefined reference to LAPACK and BLAS subroutines - fortran

I'm trying to understand how BLAS and LAPACK in Fortran work and so on, so I made a code that generates a matrix and inverts it.
Here's the code
program test
Implicit none
external ZGETRF
external ZGETRI
integer ::M
complex*16,allocatable,dimension(:,:)::A
complex*16,allocatable,dimension(:)::WORK
integer,allocatable,dimension(:)::IPIV
integer i,j,info,error
Print*, 'Enter size of the matrix'
Read*, M
Print*, 'Enter file of the matrix'
READ(*,*), A
OPEN(UNIT=10,FILE = '(/A/)' ,STATUS='OLD',ACTION='READ')
allocate(A(M,M),WORK(M),IPIV(M),stat=error)
if (error.ne.0)then
print *,"error:not enough memory"
stop
end if
!definition of the test matrix A
do i=1,M
do j=1,M
if(j.eq.i)then
A(i,j)=(1,0)
else
A(i,j)=0
end if
end do
end do
call ZGETRF(M,M,A,M,IPIV,info)
if(info .eq. 0) then
write(*,*)"succeded"
else
write(*,*)"failed"
end if
call ZGETRI(M,A,M,IPIV,WORK,M,info)
if(info .eq. 0) then
write(*,*)"succeded"
else
write(*,*)"failed"
end if
deallocate(A,IPIV,WORK,stat=error)
if (error.ne.0)then
print *,"error:fail to release"
stop
end if
close (10)
end program test
The matrix A is in a file, which I'm calling, and also I say the size of the matrix (M ). When I copile them with gfortran I get these message
/tmp/ccVkb1zY.o: In function MAIN__':
test.f03:(.text+0x751): undefined reference tozgetrf_'
test.f03:(.text+0x85d): undefined reference to `zgetri_'
collect2: error: ld returned 1 exit status
I have installed BLAS and LAPACK installed so I don't know if I'm calling in a right way the library.
Any suggestion?

It looks like you might not have linked to the libraries. Try:
gfortran -o test test.f03 -llapack -lblas
This causes the linker (the program which joins all the program parts together; usually called "ld" on UNIX) to include the library code for the LAPACK call (or a dynamic link to it) in your program.
If the result of the above line is "cannot find -llapack" or similar, there are two common problems:
Libraries can be "shared" (names ending ".so") or "static" (names ending ".a"); the linker will look for the shared one, so if you only have the static one you should add "-static" before the library link:
gfortran -o test test.f03 -static -llapack -lblas
This will also make it look for the static version of BLAS; if you need the shared version, add "-shared" in front of the "-lblas":
gfortran -o test test.f03 -static -llapack -shared -lblas
You might find this page helpful.
The linker isn't looking in the right directory for the libraries. You need to locate the actual library (called something like "liblapack.so" or "liblapack.a") and make sure the directory it's in is included in the directories the linker looks in, e.g. to get it to look in "/mylibs/maths" as well:
gfortran -o test test.f03 -L/mylibs/maths -llapack -lblas

Related

Using FFTW3 Fortran library in MacOS

I am getting the following error while trying to compile a Fortran program with gfortran and FFTW3 library. The program however compiles successfully with the Intel compiler ifort.
Error
Undefined symbols for architecture x86_64:
"__gfortran_os_error_at", referenced from:
_MAIN__ in ccAVlghr.o
ld: symbol(s) not found for architecture x86_64
Compile Command
gfortran -I/usr/local/include -L/usr/local/lib pois.f90 -lfftw3 -lm
pois.f90 is the program which contains FFTW3 commands to solve a Poisson equation through Fourier transform.
The equivalent C program also compiles and executes successfully. The FFTW3 statements are inserted in Poisson.f90 as per FFTW3 documents. The routine which uses FFTW3 commands is given below
subroutine fft_forward(j,f,Fr,Fi)
use, intrinsic :: iso_c_binding
implicit none
include 'fftw3.f03'
double precision :: f(j),Fr(j),Fi(j)
integer :: i,j
type(C_PTR) :: plan
complex(C_DOUBLE_COMPLEX) :: FF(j)
plan = fftw_plan_dft_r2c_1d(j,f,FF,FFTW_ESTIMATE)
call fftw_execute_dft_r2c(plan,f,FF)
call fftw_destroy_plan(plan)
do i = 1,j
Fr(i) = real(FF(i))/j
Fi(i) = aimag(FF(i))/j
enddo
Fr = Fr/j; Fi = Fi/j
end
I also tried using a compiler flag -lgfortran but got the same error. Any suggestion will be of great help.
It probably depends on what you did while installing GNU Fortran, FFTW, et al.
In my case, it works as expected.
I have GNU Fortran installed from sources: gcc-9-2-0
Then, I have built FFTW using my own installation of GNU Fortran
./configure --prefix=$HOME/opt/usr/local/fftw/fftw-3.3.10 CC=gcc-9.2.0 MPICC=mpicc F77=gfortran-9.2.0
make
make install
and then, I have compiled your sample using
gfortran-9.2.0 -I$HOME/opt/usr/local/fftw/fftw-3.3.10/include -L$HOME/opt/usr/local/fftw/fftw-3.3.10/lib -lfftw3 -lm -c simple.f90
I have also added short _main stuff like so to double check it links with the stuff
program main
print *, 'Hello'
end program main
after building, it runs as expected
gfortran-9.2.0 -I$HOME/opt/usr/local/fftw/fftw-3.3.10/include -L$HOME/opt/usr/local/fftw/fftw-3.3.10/lib -lfftw3 -lm simple.f90 -o main
./main
Hello
I guess you have sort of a messy GNU Fortran + FFTW installation.

Building an executable shared library with ifort

There are several excellent discussions on SO already covering how to produce an executable shared library on Linux:
See https://unix.stackexchange.com/questions/7066
and building a .so that is also an executable as examples
In C/C++, this seems relatively straightforward; essentially there are two parts:
Add an .interp section to the ELF (as ld doesn't include one for shared libraries) by including something along these lines in the library source:
const char interp_section[] __attribute__((section(".interp"))) = "/path/to/dynamic/linker";
Set an appropriate entry point when linking, using -Wl,-e,entry_point
Does anyone know how to achieve this with a library written in Fortran? Specifically, how to add a .interp section to a shared library compiled with ifort?
With help of a C compiler to create an additional object file to be linked to the dynamic library, such a Fortran90 executable and dynamic link library can be created:
/* stub.c: compile e.g. with gcc -c stub.c
const char dl_loader[] __attribute__((section(".interp"))) =
"/lib64/ld-linux-x86-64.so.2";
/* adjust string if path or architecture is different */
! testif.f90: compile e.g. with ifort -c -fPIC testif.f90
subroutine execentry
write(*,*) 'Written from executable.'
! without call to exit seems to lead to segmentation fault
call exit(0)
end subroutine
subroutine libroutine
write(*,*) 'Written by libroutine.'
end subroutine
! linktest.f90: compile e.g. with ifort -c linktest.f90
! main Fortran program for testing
program linktest
call libroutine
end
For compilation and linking:
gcc -c stub.c
ifort -c -fPIC testif.f90
ifort -c linktest.f90
ifort -shared -o libtestif.so testif.o stub.o -Wl,-e,execentry_
ifort -o linktest linktest.o -L. -ltestif
Executing the dynamic link library directly ./libtestif.so will call execentry, and running the link test program
LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./linktest
will call libroutine.
The C code is only needed to create the .interp section. The underscore in the ld flag -Wl,-e,execentry_ is added according to the symbol name mangling for Intel ifort (or GNU gfortran) vs. GNU or Intel C compilers.

Calling C++ from Fortran with OpenMPI

I am having a compile-time issue which I have reduced to the following test case. I wish to call a C++ routine from fortran and have the C++ routine be MPI aware.
Consider the following sample code,
Fortran main:
! -- main.f90
program main
implicit none
external return_three
integer return_three
write(*,*) return_three()
end program main
C++ subroutine:
// -- subs.cpp
#include <mpi.h>
extern "C"
{
int return_three_();
}
int return_three_()
{
return 3;
}
Note that, for the problem to reproduce, I only need to include mpi.h.
Compiling with GCC 5.3 and OpenMPI 1.10.1 (I checked GCC 4.8 and PGI 15.10 too) gives the following problem during linking:
% mpic++ -c subs.cpp
% mpifort -c main.f90
% mpifort -o main subs.o main.o -lstdc++ -lgcc_s
subs.o: In function `MPI::Intracomm::Intracomm()':
subs.cpp:(.text._ZN3MPI9IntracommC2Ev[_ZN3MPI9IntracommC5Ev]+0x14): undefined reference to `MPI::Comm::Comm()'
subs.o: In function `MPI::Intracomm::Intracomm(ompi_communicator_t*)':
subs.cpp:(.text._ZN3MPI9IntracommC2EP19ompi_communicator_t[_ZN3MPI9IntracommC5EP19ompi_communicator_t]+0x19): undefined reference to `MPI::Comm::Comm()'
subs.o: In function `MPI::Op::Init(void (*)(void const*, void*, int, MPI::Datatype const&), bool)':
subs.cpp:(.text._ZN3MPI2Op4InitEPFvPKvPviRKNS_8DatatypeEEb[_ZN3MPI2Op4InitEPFvPKvPviRKNS_8DatatypeEEb]+0x24): undefined reference to `ompi_mpi_cxx_op_intercept'
subs.o:(.rodata._ZTVN3MPI3WinE[_ZTVN3MPI3WinE]+0x48): undefined reference to `MPI::Win::Free()'
subs.o:(.rodata._ZTVN3MPI8DatatypeE[_ZTVN3MPI8DatatypeE]+0x78): undefined reference to `MPI::Datatype::Free()'
collect2: error: ld returned 1 exit status
It seems to me like mpifort is missing some C++-related libraries. It's my understanding that mpifort should be used to compile a fortran main program, though. The problem doesn't occur with Intel 16.0 compiled against OpenMPI 1.10.1.
My questions are:
What's going on here? Why is Intel able to handle this sample code and PGI/GCC is not?
Is there a portable way to include C++ subroutines with MPI in a fortran code?
(if possible) Is there an easy way to fix my current problem? I'm trying to compile a package on my machine, so it'd be best if I could just add -lmagicfix or something.
I was able to compile your code with GCC 5.3.0 and openMPI 1.10.2 by adding -lmpi_cxx in the final step:
% mpic++ -c subs.cpp
% mpifort -c main.f90
% mpifort -o main main.o subs.o -lstdc++ -lmpi_cxx
The reason is that the openMPI wrapper compilers mpifort and mpic++ link to different MPI libraries. You can check this with the -showme:libs option:
% mpifort -showme:libs
mpi_usempif08 mpi_usempi_ignore_tkr mpi_mpifh mpi
% mpic++ -showme:libs
mpi_cxx mpi
So in order to use the C++ MPI library, you have to tell mpifort explicitly to link to it.

Error in linking gfortran to LAPACK and BLAS

I have installed LAPACK and BLAS from Synaptic package manager in Ubuntu.
whereis libblas
libblas: /usr/lib/libblas.so /usr/lib/libblas.a /usr/lib/libblas
whereis liblapack
liblapack: /usr/lib/liblapack.a /usr/lib/liblapack.so
When I try to compile the randomsys1 example with gfortran I get the following error messages.
gfortran randomsys1.f90 -L/usr/lib/lapack -llapack -L/usr/lib/libblas -lblas
/tmp/cclwtifh.o: In function `MAIN__':
randomsys1.f90:(.text+0x12): undefined reference to `init_random_seed_'
collect2: error: ld returned 1 exit status
or
gfortran randomsys1.f90 -llapack -lblas
/tmp/ccB1isEC.o: In function `MAIN__':
randomsys1.f90:(.text+0x12): undefined reference to `init_random_seed_'
collect2: error: ld returned 1 exit status
As per my understanding, it is the recommended way to link gfortran with lapack and blas (kindly refer to gfortran LAPACK “undefined reference” error). Thanks in advance for pointing out the correct way to compile the fortran code using gfortran.
Give this a try
gfortran randomsys1.f90 -L/usr/lib -llapack -L/usr/lib -lblas
I think you went one directory too far
I wrote a program using the LAPACK eigensolver and here is how I successfully compiled it on my own computer. It was used to calculate modes of a spring-mass system.
gfortran eigen.f90 -L/usr/local/lib -lblas -L/usr/local/lib -llapack
This also works on my computer
gfortran eigen.f90 -lblas -llapack
I just tried both to verify.
PS, now that you know how to compile, I think you need the subroutine init_random_seed in your program (goes after "contains" but before "end program"). This one is from google. No idea if it is what you need, your professor should be able to steer you correctly here.
! Initialize the random number generator using current time,
! so a new sequence of random numbers is generated each
! execution time.
! Taken from http://gcc.gnu.org/onlinedocs/gfortran/RANDOM_005fSEED.html
SUBROUTINE init_random_seed()
INTEGER :: i, n, clock
INTEGER, DIMENSION(:), ALLOCATABLE :: seed
CALL RANDOM_SEED(size = n)
ALLOCATE(seed(n))
CALL SYSTEM_CLOCK(COUNT=clock)
seed = clock + 37 * (/ (i - 1, i = 1, n) /)
CALL RANDOM_SEED(PUT = seed)
print *, "Using random seed = ", seed
print *, " "
DEALLOCATE(seed)
END SUBROUTINE
I had the same problem. I followed the recommendation above and
it worked. Here's my working example batch file (it has to be executed
in the cmd window):
gfortran -c for\kurs_evd.f90
gfortran -o kurs_evd.exe kurs_evd.o charint.o -L/usr/lib -llapack -L/usr/lib -lblas
kurs_evd.exe

Compiling program using gfortran and the HDF-EOS2 library

I have the problem of linking the HDF-EOS library to a Fortran90 program. I have compiled the library from source to a directory specified in $prefix. My simple compile command is:
gfortran -I$prefix/include -L$prefix/lib -Wl,-rpath -Wl,$prefix/lib -lhdfeos -lGctp -lmfhdf -ldf -lz -lsz -ljpeg tst.f90
When compiling, I get the following error:
undefined reference to `gdopen_'
In the program, which I am not supposed to change, the HDF-EOS library is used via the external keyword, e.g.
integer(kind=4), external :: gdopen
In the library, nm $prefix/lib/libhdfeos.a | grep gdopen gives me:
00000000000120c0 T gdopen
When compiling with -fno-underscoring, I get just a different error:
gfortran -fno-underscoring -I$prefix/include -L$prefix/lib -Wl,-rpath -Wl,$prefix/lib -lhdfeos -lGctp -lmfhdf -ldf -lz -lsz -ljpeg tst.f90
the error is then:
undefined reference to `gdopen'
Also, gfortran finds the libraries, otherwise it would complain. Is the error related to the underscore? What else can I try? I work on Fedora and gfortran version 4.7.2.
Yes, very likely to be caused by the underscore.
Try compiling with -fno-underscoring (https://gcc.gnu.org/onlinedocs/gfortran/Code-Gen-Options.html), but fixing it by a proper bind(C) interface would be better.
This tutorial (Did you read it before going here? Very easy to find even for a complete novice in the library, like me.) also states you should use -fno-underscoring.
Continue by implementing the rest what the tutorial recommends, including compiling with FC=$(HDF4_DIR)/bin/h4fc.