I am working on a large mixed-language code in Fortran 1990 and C++ 11. I recently compiled on a new platform with intel compilers (which I have successfully used before), specifically Intel Version 19.1.1.217.
I have boiled the issue down to a simple test:
f.F90
subroutine ff()
implicit none
call system('echo y')
end subroutine ff
main.cc
#include <iostream>
extern "C"
{
void ff_(void);
}
int main(void)
{
ff_();
return 0;
}
I have emulated exactly how my code is built, which boils down to this:
mpif90 -f90=ifort -c f.F90 -o f.o
mpicxx -cxx=icpc -c main.cc -o main.o
mpicxx -cxx=icpc main.o f.o -L/software/intel/2020.1/compilers_and_libraries/linux/lib/intel64 -lifcore
...after which I get the following:
f.o: In function `ff_':
f.F90:(.text+0xd): undefined reference to `system_'
I am aware that calls to system() are not part of the stardard, but I can successfully compile and run the following with no problem:
p.F90:
program ff
implicit none
call system('echo y')
end program
mpif90 -f90=ifort p.f90 -o pexe && ./pexe
y
This suggests to me that using mpif90 -f90=ifort is imlicitly telling the linker to link in some extra libraries, but running ldd on the resulting executable shows a subset of the libraries linked in when I compile a simple C++ program.
What do I need to link to stop this error?
Well, I stumbled upon the solution immediately after asking this question. By using mpif90 -f90=ifort -v (source files) I was able to see everything that was being linked, and tried each library one at a time until it worked.
Related
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.
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.
This question already has answers here:
How to compile C source code without a main function?
(6 answers)
Closed 7 years ago.
I have a simple C program I have to make (Which can't use a main function).
As such:
test.c
#include <stdio.h>
int getUserID(int id);
int getUserID(int id) {
return 0;
}
Where my current function does nothing as of now:
However, I'm trying to compile this through a makefile, as such:
all:
gcc test.c
Which didn't work because I didn't have a main so then I added the -c command within it.
all:
gcc -c test.c
Which now compiles with make, but gives me an object file (but without a working executable), the executable I get when I try to run it: i.e ./test tells me permission denied
Any help would be greatly appreciated.
You cannot have a C++ or C program without a main (without evil, non-standard hacks at least). You can build a library without a main, but not a standalone executable.
For standalone applications, the main function is crucial because it defines where to start execution.
You can create an image where "main" is not the entry point.
Here is one such way (using gcc on a RHEL6 system):
$ cat sample.c
#include <stdio.h>
#include <unistd.h>
int notmain ( void ) {
printf("hello, world\n");
exit(0);
}
$ cc -ffreestanding -c sample.c
$ ld -enotmain -o sample sample.o -I/lib64/ld-linux-x86-64.so.2 -lc
$ ./sample
hello, world
And, BTW, this is not an "evil, non-standard hack" -- the C Standard defines two execution environments: (1) "hosted", which is the one most people are familiar with, and (2) "freestanding", which is typically some sort of embedded system (a toaster or whatnot).
You can separately compile this c file into an object file, but it will need to be linked with another object file containing the main function to become an executable program.
If you are not allowed to have a main function in this file, there must be another file you are expected to link with it.
I am trying to call a C code double_metaphone.c from R in windows. I am familiar with R , but have not tried C yet.
I have compiled the code and created a shared library as follows in windows using Cygwin gcc including the header file double_metaphone.h
gcc -c double_metaphone.c
gcc -shared -o double_metaphone.dll double_metaphone.o
I have used dyn.load to load the dll file as follows
dyn.load("C:/R/double_metaphone.dll")
getLoadedDLLs() lists double_metaphone.dll, however
is.loaded(double_metaphone.dll)
gives the error
Error in is.loaded(double_metaphone.dll) :
object 'double_metaphone.dll' not found
When I try to use .C() or .Call(), I get
Error in .C("double_metaphone") :
C symbol name "double_metaphone" not in load table
I understand this is a problem with C++ code as in Link1, Link, but why can't I access the shared library for calling C code from R? Where am I going wrong?
As per my understanding "is.loaded" checks for the loaded symbols. As per your header, you can try:
is.loaded("DoubleMetaphone")
To call the method. try:
.C("DoubleMetaphone", <your>, <arguments>)
You need compile and link against R for the shared object to be loadable. e.g.
$ gcc -I/YOUR_R_HOME_DIR/include -DNDEBUG -fpic -c double_metaphone.c -o double_metaphone.o
$ gcc -shared -o double_metaphone.dll double_metaphone.o -L/YOUR_R_HOME_DIR/lib -lR
Or simply
$ R CMD SHLIB double_metaphone.c
As Dirk said, R-exts gives you more details.
And you want to consider Rcpp for writing compiled code in R, which benefits you further down the road.
I am not a Fortran programmer (just a short experience), but I need to compile a program partly written in F77. Someone has compiled it with Absoft compiler before me, but now I need to repeat the procedure on another machine with g77. For Absoft, the makefile has
f77 -f -w -O -B100 -B108 -c *.f
mv *.f flib && mv *.o olib
f77 -B100 -o runme olib/*.o clib/*.o -L/usr/X11R6/lib64 -L/usr/X11R6/lib -lX11 -L$PVM_ROOT/lib/$PVM_ARCH -lfpvm3 -lpvm3 -L$ABSOFT/lib -lU77
I have modified these lines to be
g77 -w -O -B100 -B108 -c *.f
mv *.f flib && mv *.o olib
g77 -B100 -o runme olib/*.o clib/*.o -L/usr/X11R6/lib64 -L/usr/X11R6/lib -lX11 -L$PVM_ROOT/lib/$PVM_ARCH -lfpvm3 -lpvm3 -lgfortran -lgfortranbegin
But I get the following error messages
somefile.f:(.text+0x93): undefined reference to `for_open'
somefile.f:(.text+0xf4): undefined reference to `for_write_seq_fmt'
somefile.f:(.text+0x128): undefined reference to `for_write_seq_fmt_xmit'
somefile.f:(.text+0x454): undefined reference to `for_read_seq'
How can I fix this?
UPDATE1
If I add -libifcore to the end of the last line (linker), then I get
/usr/bin/ld: cannot find -libifcore
I have located the library
$ find /opt/intel/* -name 'libifcore*'
/opt/intel/fce/9.1.036/lib/libifcore.a
/opt/intel/fce/9.1.036/lib/libifcore.so
/opt/intel/fce/9.1.036/lib/libifcore.so.5
/opt/intel/fce/9.1.036/lib/libifcore_pic.a
/opt/intel/fce/9.1.036/lib/libifcoremt.a
/opt/intel/fce/9.1.036/lib/libifcoremt.so
/opt/intel/fce/9.1.036/lib/libifcoremt.so.5
/opt/intel/fce/9.1.036/lib/libifcoremt_pic.a
But even if I do the following in the source directory
$ export PATH=$PATH:/opt/intel/fce/9.1.036/lib/
$ ln -s /opt/intel/fce/9.1.036/lib/libifcore.so
it is not found.
Moreover, it is the same machine where I get another problem How to pass -libm to MPICC? libimf.so: warning: feupdateenv is not implemented and will always fail
It seems that the compiler should find the library, if needed
$ echo $LD_LIBRARY_PATH
/opt/intel/fce/9.1.036/lib:/opt/intel/cce/9.1.042/lib:/usr/local/lib/openmpi:/usr/local/lib:/usr/lib:
Absoft accepted an extended version of Fortran 77 that is not completely compatible with the extended version of Fortran 77 accepted by g77.
So there is no guarantee that you can do this without editing the code. I seem to recall that the Absoft compiler accepted a handy initialization syntax that can not be replicated with g77.
If you want to compile & link using g77, the easiest way is to use the command "g77". (What compiler does f77 invoke on your computer? Try "f77 -v" or similar to find out...) It should automatically find the g77 Fortran-specific libraries. You should not need to explicitly link to Fortran libraries, and especially not to the libraries of gfortran, which is a different compiler. You could also compile & link with gfortran -- it will probably recognize that the source code is Fortran 77 and compile appropriately if the files have the correct file type, otherwise you will have to use options -- for this compiler, use the command "gfortran".
With g77 and gfortran it should not need Intel libraries -- maybe f77 is connected to ifort, the Intel compiler, on your computer?
Edited later:
I suggest trying something simpler first to test your setup.
Try this FORTRAN 77 program as file "junk.f"
C234567
write (6, *) "Hello World"
stop
end
Try this command:
g77 junk.f -o junk.exe
Run it via:
./junk.exe
This will test whether g77 is working.
it looks like you are trying to link with libifcore.
Edit:
You can include this library by adding
'-lifcore' to your compiler options. To quote the gcc tutorial
In general, the compiler option -lNAME will attempt to link object files with a library file ‘libNAME.a’ in the standard library directories.
why do you use g77 and not gfortran?
what do you mean with multiprocessing? openmp or vectorized?
you can use openmp with the gfortran compiler and when you want to use vector mode like the ifort compiler does, you have to specify sse explicitly in the compiler options.
It seems that the problem was in an error in one of the source files, which wasn't a big deal for Absoft compiler. g77 was giving a warning about it, but compiling this file and producing the original errors (mentioned in the question) without a binary.
When I tried ifort, compilation of that file was aborted, but other files were compiled and a binary was created.
fortcom: Error: somefile.f, line 703: An extra comma appears in the format list. [)]
& (1p5e12.3,5h ...,))
-------------------------^
compilation aborted for somefile.f (code 1)
When I removed the extra comma, then both compilers have compiled everything and created binaries, although ifort produced a number of warnings.
Then, when I tried to run both binaries, the one made by Intel comiler was working fine, but the one by g77 was behaving very strange and didn't really do what I wanted.
So now the original problem is resolved, however the code doesn't run in multiprocessing mode, so the binary is unfortunately useless for me.