language binding error with Fortran: why won't it link to MPI library? - linker

I'm trying to create language bindings for a message passing interface but the compiler can't recognize my reference to the C functions...
I'm currently using gfortran as my compiler on a linux machine... I know the language bindings work, but whenever I try to link them to the mpi library, I get this error:
/tmp/ccwukrNT.o: In function `MAIN__':
hello_init.f90:(.text+0x17): undefined reference to `mpi_init'
collect2: error: ld returned 1 exit status
the commands to compile I am currently using are:
gfortran -ffree-form foo.f90 ~/dir1/dir2/bar.f90 -o <outfile> -L
/home/.fakeroot/lib -I /home/.fakeroot/include/ -lexampi
(exampi is the standard I am currently working on)
As I said, when I use simple hello_world programs and compile all my files manually, this method works, but it fails when I try and link it to a library. Can anyone help me?
here is my current Fortran binding for MPI_Init:
module mpi_f08
interface MPI_Init
subroutine MPI_Init(ierror) bind(C)
integer, optional, intent(out) :: ierror
end subroutine MPI_Init
end interface MPI_Init
end module mpi_f08
The C function I am using is trivial... it's merely interfacing with PMPI_Init()... In any event, the library linking is the main problem... Yes, I have externalized it from C++.
Here is the simple test program I wrote:
program hello_init
use mpi_f08, only : MPI_Init
implicit none
integer :: ierror
ierror = 0
call MPI_Init(ierror)
stop
end program hello_init
I am not too familiar with Fortran... this was given to me as a side project but it's quickly taking up my whole week simultaneously laughs and cries
Thanks!

Related

Calling a Fortran procedure from C that includes a call to an intrinsic Fortran function [duplicate]

This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it in Fortran?
(5 answers)
C++/Fortran mixed programming: undefined reference to `_gfortran_reshape_r8'
(3 answers)
Closed 2 days ago.
I'm trying to write a Fortran routine that can be called from a C program. The Fortran code compiles correctly, but when I try to link the C code against the Fortran binary, I get an error saying there's an undefined reference to a Fortran intrinsic routine. Is it possible to write either the Fortran code itself, or its C interface definition, such that a Fortran function that calls a Fortran intrinsic can be called from C? If so, how is this done?
The Fortran code that I want to call from C is in a file called "test.f90":
module test
use, intrinsic :: iso_c_binding, only : c_double
implicit none
contains
function getRand() bind(c)
real(c_double) :: getRand
call random_number(getRand)
end function getRand
end module test
The C code that I want to execute this code is in a file called "main.c":
extern double getrand();
int main(){
double r = 0.0;
r = getrand();
return 0;
}
I tried to build the code with the following commands:
>$ gfortran -c test.f90 (This executed with no error)
Then I ran:
>$ gcc test.o main.c
This command failed with the error message:
/usr/bin/ld: testmodule.o: in function `getrand':
testmodule.f90:(.text+0x15): undefined reference to `_gfortran_random_r8'
collect2: error: ld returned 1 exit status
I'm using gfortran and gcc versions 11.3.0 on Ubuntu 20.04.1, running on Windows WSL version 2. The linker is GNU ld version 2.38.

How to link an externally built C library to Ada default runtime math services (sin, cos, etc.)?

I need to use an externally built C library doing some calculation with trigonometric services to my Ada program. I do it well using an stm32 bb runtime (SFP) but when trying to do the same in a native environment using the default Ada runtime, I end up with linking problems. Hope I can find some help here.
I tried several configurations of project files (gpr) solutions and I always end up with the same kind of linking error:
Memory region Used Size Region Size %age Used/opt/gnat/gnat_native/bin/../libexec/gcc/x86_64-pc-linux-gnu/7.3.1/ld: /home/pulsar/repos/pulsar-software/something/lib_c/libC.a(something.o): in function `compute':
(.text+0xa5): undefined reference to `sin'
collect2: error: ld returned 1 exit status
Here is what I've got so far.
The C library build sequence is as follows (confirmed by the library provider):
$ gcc -c something.c -o something.o
$ ar -r libsomethingLib.a something.o
The C library gpr file something_lib_c.gpr:
library project Something_Lib_C is
for Languages use ("C");
for Externally_Built use "true";
for Source_Dirs use ("src_c");
for Library_Dir use "lib_c";
for Library_Name use "somethingLib";
for Library_Kind use "static";
end Geocaging_Lib_C;
In the lib_c directory, I have the actual library libsomethingLib.a
In the src_c directory, I have the header API to use the C library (something.h):
#ifndef _GEOCAGING_H
#define _GEOCAGING_H
typedef struct something_s something_t;
extern void compute(something_t* const self);
#endif // _GEOCAGING_H
Then here is the Ada project file that wraps the C library something_lib.gpr:
with "something_lib_c.gpr";
project Something_Lib extends "../settings.gpr" is
for Languages use ("Ada");
for Source_Dirs use ("./src_ada");
for Object_Dir use "obj" & "/" & Target & "/" & Build;
end Geocaging_Lib;
In the directory src_ada, I have the Ada API wrapper (something_api.ads):
with Interfaces; use Interfaces;
with Interfaces.C; use Interfaces.C;
package Something_API is
type T_Something is null record;
procedure Compute (Something : access T_Something);
with Import => True,
Convention => C,
External_Name => "compute";
end Something_API;
And finally, I call the compute service from my Ada program by with-ing the Ada API wrapper.
Once again, when building/linking the whole thing for an arm-eabi target, using an stm32-full or stm32-sfp Ada runtime, everything runs well and the behavior of the library is validated.
The whole point is I'd like to do the thing in a native environment in order to run CI tests on it and I can't find a way to pass the link stage.
Last thing, in the Settings.gpr generic project file contains some common Ada build/bind/build switches that I can provide if necessary. But I can't see how this could work in arm and not in native with the same options. This HAS to be linked to the default Ada runtime thing...
Any idea?
If you were building with a C main program, what would you have to do to bring in the maths libraries at link time? ... possibly something like
gcc foo.c -l somethingLib -lm
What you need to do is to arrange for the -lm to be included whenever you call in something_lib_c.gpr.
I think that what you need to do is to modify library project Something_Lib_C to include the line
for Library_Options use ("-lm");
OK, my HUGE apologies to all of you who tried to help...
The solution was more obvious than I thought, I was just too obsessed with the thing working in arm and not in native.
BUT, the solution was simply to add the -lm switch to the global linker switches. Hence:
Ada_Switches_Linker_Native := (
"-Wl,--gc-sections"
,"-Wl,--verbose"
,"-Wl,-lm"
);
package Linker is
case Target is
when "native" =>
for Switches ("Ada") use Ada_Switches_Linker_Native;
...
end case;
end Linker;
In case it could be of interest for someone else, the fact that it works straightforward in arm environment and not in native is because the default runtime does not embed a specific mathematical library and you are supposed to use the C one provided by gcc, linking through the -lm switch.
In the contrary, when using a target specific runtime like arm (for stm32f4 for example), the correct mathematical libraries are provided, selected and automatically linked depending on your compilation options (-mhard-float, -msoft-float, etc.).
Sorry again and thank you very much for your time.

linking multiple files with fortran

I'm new to Fortran but I'm trying to find a way that I can retrieve information from programs I've written without including them as subprograms within my new file. As of right now I have 4 subroutines within my new file and I would like to instead just be able to input the radius into all 4 and receive their respective outputs.
this is the basic format for my code--- basically I want to show that I need 4 separate programs in order to get all the variables needed for the current programs expression.
So far I've tried to use both the include and call expressions but they weren't able to retrieve the information I needed to bring back into my file and they came up with just "not applicable" answers.
program practicedynamo
implicit none
real:: A,B,C, Radius
real::Bsquared,Vsquared
read*,radius
call programA(radius,A)
call programB(radius,B)
call programC(radius,C)
Vsquared=(1.0/3.0)*B
Bsquared= 4*pi*density*Vsquared
gradient=radius*C
Rvector=Bsquared*Vsquared*gradient
ThetaVector=Rvector*sin(A)
end program practicedynamo
!and then my four subroutines would be placed afterwards
!here is an example of one of my subroutines within my actual code (the version above has been simplified and I've changed the variables)
subroutine testdensity(radius,density)
implicit none
real::radius,x,sunradius,density
if (radius>0.and.radius<=695500000) then
sunradius=695500000
x=radius/sunradius
density=((519*x**4.0)-(1630*x**3.0)+(1844*x*x)-(889*x)+155)
print*," "
density=density*1000
print*,"the density is",density, "kg per meters cubed"
else
print*, "this radius is not an option for the sun"
end if
end subroutine testdensity
You haven't mentioned how you are compiling your code, but here are some general ways to include multiple source files in a single executable. You don't need to include the files, you can just compile them separately and link them together. Writing a Makefile to do this is recommended and you can find plenty of examples on that elsewhere.
To compile multiple files into one executable, you need only list them all when compiling
gfortran -o output programA.f90 programB.f90 programC.90 mainprogram.f90
If you do not want to compile them all together or have to recompile when you build, you can compile individual objects, e.g.
gfortran -c -o programA.o programA.f90
gfortran -c -o programB.o programB.f90
gfortran -c -o programC.o programC.f90
and then link as
gfortran -o output mainprogram.f90 programA.o programB.o programC.o
If you are instead trying to use libraries and want program A-C to be in a standalone library, you can first compile the objects as above, then
ar rcs libABC.a programA.o programB.o programC.o
and then compile your main program as
gfortran -o output mainprogram.f90 libABC.a
If you aren't using modules, you'll be responsible for making sure that your calls to external subroutines match the declared interface in the external file. To be safe and have the compiler catch problems with mismatched arguments you can declare explicit interfaces in your program or put the external code into modules and use those modules in the main program.

Linking preinstalled libraries from gfortran in Mac OSx 10.6

I have been trying to compile a certain code written in fortran90 and C, for a few days now. I am using gfortran and gcc. The code needs to link to lapack, blas and fftw3 libraries. I have all three installed in my macbook pro. But when I run the configure script, for some reason, it fails to locate the fftw3 libraries.
Here is my configure line:
./configure --prefix=`pwd` --with-fft=fftw3 \
--with-fft-lib='-I/opt/local/include -L/opt/local/lib -lfftw3 -lm' \
--with-blas='-I/opt/local -L/opt/local -lblas' \
--with-lapack='-I/opt/local -L/opt/local -llapack' \
FCFLAGS='-O3 -m64'
I have used exactly the same linking line for lapack, blas and as well as fftw3. Configure is able to find lapack and blas but fails to link fftw3. Does anyone have any idea what is happening here? I would appreciate any help.
Thanks,
kopinjol
Hi everyone,
First of all thanks Hristo Iliev for your answers earlier. I have been able to fix that problem with linking the libraries. You were right about using different compilers for the libraries and the main code. That was the problem. And when I compiled them with the same compiler, the linking problem went away. But now I have another issue.
In the code there is a function call like this:
call io_open(info_files(n_files)%unit,trim(dir)//"/info")
The io_open function is defined as follows:
subroutine io_open(unit, file, status, form)
integer, intent(out) :: unit
character(len=*), intent(in) :: file
character(len=*), intent(in), optional :: status, form
integer :: iostat
character(len=20) :: status_, form_
The error I get is this:
call io_open(info_files(n_files)%unit, trim(dir)
1
Error: Syntax error in argument list at (1)
Basically it seems that the code gives a syntax error in
trim(dir)//"/info"
which is the filename in the function call.
Now the code compiles without any problem on a linux box (I was using ubuntu, the most recent release). I get the error only on my macbook pro running osx 10.6 .
Also surprisingly, the code compiles when I define an extra variable fname as
fname=trim(dir)//"/info"
and then use it for the function call
call io_open(info_files(n_files)%unit,fname)
Now I can make the substitution in all the function calls in the code, which are quite a few and it will probably take me a few hours to make the change by hand. But it somehow doesn't make sense that the same code with the same compilers compile without error in linux but fails in the mac. Does anyone have any idea as to what may be going wrong? I will appreciate any input.
Thanks in advance,
kopinjol
Thanks for the reply Hristo Iliev. I just figured out the problem. The problem was that I was using different versions of the same compiler. Once I updated the environment variables with compilers of the same versions, it all started working.
This is what I did,
export FC="gfortran-mp-4.6 -m64"
export F77="gfortran-mp-4.6 -m64"
export F90="gfortran-mp-4.6 -m64"
export CC="gcc-mp-4.6 -m64"
export CXX="g++-mp-4.6 -m64"
export CPP="cpp-mp-4.6 -m64 -C -ansi"
export FCCPP="cpp-mp-4.6 -m64 -C -ansi"
export FCFLAGS="-O3"
export FFLAGS="-O3"
As explained in the APE mailing list.
Thanks again,
kopinjol

ld error while building GD library for Haskell on Windows

When installing the Haskell GD package through cabal, on Windows (using MinGW), I get the following warnings:
Warning: resolving _gdImagePtrDestroyIfNotNull by linking to _gdImagePtrDestroyIfNotNull#4
Warning: resolving _gdImageCopyRotated90 by linking to _gdImageCopyRotated#36
Use --enable-stdcall-fixup to disable these warnings
Use --disable-stdcall-fixup to disable these fixups
Note that these are precisely the functions defined in gd-extras.
Then, when actually compiling a Haskell program which uses gd, I get the following errors:
Linking Main.exe ...
[...]\cabal\gd-3000.7.3\ghc-7.4.1/libHSgd-3000.7.3.a(Internal.o):fake:(.text+0x2211):undefined reference to 'gdImageCopyRotated90'
[...]\cabal\gd-3000.7.3\ghc-7.4.1/libHSgd-3000.7.3.a(Internal.o):fake:(.text+0x500a):undefined reference to 'gdImagePtrDestroyIfNotNull'
[...]
collect2: ld returned 1 exit status
I'm unable to figure out how to fix this — it's already taken me ages to get to this point, as I've had many more issues trying to get it working, but this seems like the final hurdle. I have tried enabling/disabling stdcall fixup, and also changing in which file these functions are defined (as gd-extras seemed to be a potential issue), but that hasn't adressed the issues.
Thanks for any help.
You need to pass explicit linker flags to ghc, pointing to the library. The Haskell GD library is automatically linked, but the dll will not be linked as well unless you tell ghc about it. The stdcall-fixup errors are a red herring here.

Resources