Having trouble linking C++ to Fortran using ICL/IFORT - c++

So I'm following the example from
http://difdop.polytechnique.fr/wiki/index.php/How_to_Bessel_Functions_in_C
Except I'm trying to use the intel compilers ICL and IFORT instead of gcc and g77.
The code I have in C++ is:
extern "C" void zbesj_(double*, double*, double*, int*, int*, double*, double*, int*, int*);
typedef std::complex<double> CplxDbl;
CplxDbl besselj(double nu, CplxDbl z)
{
int kode=1;
int n=1;
double zr=z.real();
double zi=z.imag();
int nz,ierr;
double cyr[1],cyi[1];
CplxDbl res;
zbesj_(&zr,&zi,&nu,&kode,&n,cyr,cyi,&nz,&ierr);
if(ierr!=0){
printf("error!\n");
}
return CplxDbl(cyr[0],cyi[0]);
}
int _tmain(int argc, _TCHAR* argv[])
{
CplxDbl J0=besselj(0.0,CplxDbl(0.1,0.2));
printf("\nJ0(0.1+0.2i)= %.17f %+.17f I\n",J0.real(),J0.imag());
return 0;
}
Additionally, I have zbesj.f and all its dependencies. I've tried calling ICL first, then IFORT and vice versa. Doesn't compile :(
icl -c CallFortranFromC.cpp
ifort -o test CallFortranFromC.obj *.f
Always end up with the same linker error:
CallFortranFromC.obj : error LNK2019: unresolved external symbol zbesj_ referenced in function main
test.exe : fatal error LNK1120: 1 unresolved externals
Any help is appreciated!

You have a mismatch on symbol names in the link stage. If you do:
dumpbin /SYMBOLS zbesj.obj
you'll see symbol name in object file is UPPER CASE and has no trailing UNDERSCORE.
Easiest fix is this (assuming you don't want to change your C code):
icl -c CallFortranFromC.cpp
ifort /names:lowercase /assume:underscore -o test CallFortranFromC.obj *.f

Related

Undefined symbol for dlsym in C++ [duplicate]

This question already has answers here:
What is the effect of extern "C" in C++?
(17 answers)
Closed 3 years ago.
I have one C++ program which I want to load into my current running C++ program. Following are the snippet
File : a.cpp
#include<bits/stdc++.h>
using namespace std;
void abc() {
cout << "This is abc" << endl;
}
File : mainFile.cpp
#include <bits/stdc++.h>
#include <dlfcn.h>
int main(int argc, char **argv) {
system("g++ -fpic -shared -ldl -o a.so a.cpp");
void *lib = dlopen("./a.so", RTLD_NOW);
if (!lib) {
printf("dlopen failed: %s\n", dlerror());
return 1;
}
void (*f)();
f = (void (*)()) dlsym(lib, "abc");
if (f) {
f();
} else {
printf("dlsym for f1 failed: %s\n", dlerror());
}
dlclose(lib);
return 0;
}
I am compiling with the following commands
g++ -w mainFile.cpp -ldl -o mainFile && ./mainFile
Output:
dlsym for f1 failed: ./a.so: undefined symbol: abc
Please help.
I am compiling in Ubuntu 16.04 with g++ version g++ (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609
OBSERVATION
What's strange is, when I have the above a.cpp file as a.c and with only stdio.h as header and also with a -fpermissive flag, the program compiles and I get the output as This is abc. I do not understand why the CPP version fails. The reason I cannot use CPP (or rather hesitate to go the .C route) is that my project requires OOPS concept and I have to use classes in the library file. The above example is only to simplify the objective.
Note: I have followed the following references but none helped.
Can you dynamically compile and link/load C code into a C program?
undefined reference to `dlopen' since ubuntu upgrade
C dlsym undefined symbol
In C++ names are mangled, that is, the name of the symbol in the library is not just abc. Instead it has additional characters (decoration) that describe the arguments etc. of that function. That is why you don't find the function by the name abc.
You have two options:
Look up the mangled name (which may be difficult/non-portable since mangling depends on the compiler).
Declare function abc() as extern "C" { void abc(); }. This requests C-linkage for the function and thus prevents name mangling.
See also the many pointers you got in the comments.

A problem when compiling a simple C++ program

When I compile a simple C++ program like this:
#include<iostream>
using namespace std;
int main()
{
cout << "hello word" << endl;
return 0;
}
I got some error message,
This is part of the error message:
In file included from e:\mingw\lib\gcc\mingw32\8.2.0\include\c++\cstdlib:75,
from e:\mingw\lib\gcc\mingw32\8.2.0\include\c++\ext\string_conversions.h:41,
from e:\mingw\lib\gcc\mingw32\8.2.0\include\c++\bits\basic_string.h:6391,
from e:\mingw\lib\gcc\mingw32\8.2.0\include\c++\string:52,
from e:\mingw\lib\gcc\mingw32\8.2.0\include\c++\bits\locale_classes.h:40,
from e:\mingw\lib\gcc\mingw32\8.2.0\include\c++\bits\ios_base.h:41,
from e:\mingw\lib\gcc\mingw32\8.2.0\include\c++\ios:42,
from e:\mingw\lib\gcc\mingw32\8.2.0\include\c++\ostream:38,
from e:\mingw\lib\gcc\mingw32\8.2.0\include\c++\iostream:39,
from F:\Desktop\web\web\work_one\test.cpp:1:
e:\mingw\include\stdlib.h:90:1: error: '_BEGIN_C_DECLS' does not name a type
_BEGIN_C_DECLS
^~~~~~~~~~~~~~
e:\mingw\include\stdlib.h:363:1: error: '__CRT_ALIAS' does not name a type
__CRT_ALIAS __cdecl __MINGW_NOTHROW
^~~~~~~~~~~
e:\mingw\include\stdlib.h:367:1: error: '__CRT_ALIAS' does not name a type
__CRT_ALIAS __cdecl __MINGW_NOTHROW
^~~~~~~~~~~
e:\mingw\include\stdlib.h:444:55: error: '_locale_t' has not been declared
__int64 _wcstoi64_l(const wchar_t *, wchar_t **, int, _locale_t);
^~~~~~~~~
e:\mingw\include\stdlib.h:447:65: error: '_locale_t' has not been declared
unsigned __int64 _wcstoui64_l(const wchar_t *, wchar_t **, int, _locale_t);
^~~~~~~~~
e:\mingw\include\stdlib.h:866:1: error: '_END_C_DECLS' does not name a type
_END_C_DECLS
^~~~~~~~~~~~
This seems to be a problem with the header file syntax, but I did not modify the head file.
I use this command to compile:
g++ -g -std=c++11 F:\Desktop\web\web\work_one\test.cpp -o test.exe
My operating system is Win10.
The g++ version is g++ (MinGW.org GCC-8.2.0-3) 8.2.0
G++ I got from http://www.mingw.org/
Possible solution to this already exists here
Just change -std=c++11 with -std=gnu++11
Finally, I fixed the problem. The reason for this problem is that I installed codeblocks.
codeblocks adds environment variables to my computer, like C_INCLUDEDE_PATH, CPLUS_INCLUDE_PATH, and LIBRARY_PATH. When I deleted these environment variables, the problem was fixed.

Fortran subroutines produce "Undefined symbols" error when linking to c++ program

I am writing a short program to test calling the fortran Stripack library from c++. The c++ and fortran files each compile successfully, but errors occur when linking.
The c++ code is as follows:
#include <iostream>
#include <cmath>
#ifdef __cplusplus
extern"C" {
#endif
void trmesh_(int&,float[],float[],float[],int[],int[],int[],int&,int[],int[],float[],int&);
void trlist2_(int&,int[],int[],int[],int&,int[][3],int&);
#ifdef __cplusplus
}
#endif
int main(){
// Variables for distributing points on sphere.
int polar = 16;
int azimuth = 32;
int n = polar*azimuth-azimuth+2;
float radius=1.0;
// Define variables needed by Stripack
float xs[n];
float ys[n];
float zs[n];
int list[6*(n-2)];
int lptr[6*(n-2)];
int lend[6*(n-2)];
int near[n];
int next[n];
float dist[n];
int ltri[2*n-4][3];
int lnew;
int ier;
int nt;
// Distribute n points on surface of unit sphere .
// xs, ys, zs store x, y, and z components pf each point position.
zs[0] = 1;
xs[0] = 0;
ys[0] = 0;
zs[n] = -1;
xs[n] = 0;
ys[n] = 0;
for (int ii=1; ii<polar; ii++){
for (int jj=0; jj<azimuth; jj++){
zs[(ii-1)*azimuth+jj+1] = radius*cos(ii*M_PI/polar);
xs[(ii-1)*azimuth+jj+1] = radius*sin(ii*M_PI/polar)*sin(jj*2*M_PI/azimuth);
ys[(ii-1)*azimuth+jj+1] = radius*sin(ii*M_PI/polar)*cos(jj*2*M_PI/azimuth);
}
}
// Call stripack subroutines to obtain list of triangles ltri
trmesh_(n,xs,ys,zs,list,lptr,lend,lnew,near,next,dist,ier);
trlist2_(n,list,lptr,lend,nt,ltri,ier);
// Output list of triangles
for (int ii =0; ii<n; ii++){
std::cout << ltri[ii][0] << " " << ltri[ii][1] << " " << ltri[ii][2] << std::endl;
}
}
I compile the files as follows:
ifort -c stripack.f90
clang++ -c -O0 -std=c++11 -c -o main.o main.cpp -g
clang++ -o main stripack.o main.o
The first two compilations work fine, but the last one produces the following results. It seems like the subroutines in the fortran file can't find standard fortran functions? I have tried with gfortran and the same problem occurs. Any suggestions as to what is going on would be greatly appreciated.
Undefined symbols for architecture x86_64:
"___libm_sse2_sincos", referenced from:
_trplot_ in stripack.o
_vrplot_ in stripack.o
"___svml_sincos2", referenced from:
_trans_ in stripack.o
"_for_date_and_time", referenced from:
_timestamp_ in stripack.o
"_for_stop_core", referenced from:
_trmesh_ in stripack.o
_addnod_ in stripack.o
"_for_trim", referenced from:
_timestamp_ in stripack.o
"_for_write_seq_fmt", referenced from:
_delnod_ in stripack.o
_edge_ in stripack.o
_timestamp_ in stripack.o
_trlprt_ in stripack.o
_trmesh_ in stripack.o
_addnod_ in stripack.o
_trplot_ in stripack.o
...
"_for_write_seq_fmt_xmit", referenced from:
_delnod_ in stripack.o
_edge_ in stripack.o
_timestamp_ in stripack.o
_trlprt_ in stripack.o
_trmesh_ in stripack.o
_addnod_ in stripack.o
_trplot_ in stripack.o
...
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I will demonstrate this is a link issue by example, you need do a little bit more research to solve the problem, as the information you provide is not complete.
!fortran code, named as x.f90
subroutine testFDLL(str, n) bind(c, name='testFDLL_as_C')
use ISO_C_BINDING
integer(c_int), value :: n
character(kind=c_char), intent(in) :: str(n)
write(6,*)" Hello FORTRAN : let us do something ...",str
return
end
The following C code is used for demonstration (you have got C++ mostly right already).
//c named as y.c
#include <stdio.h>
#include <string.h>
int main()
{
void testFDLL_as_C(char *str, int n);
char str[] = "Hello from C";
testFDLL_as_C(str, strlen(str));
return 0;
}
If you compile and link use the following
ifort -c x.f90
gcc y.c x.o -W -Wall
Depend on version of ifort and OS, should get error similar as the following
x.o: In function `testFDLL_as_C':
x.f90:(.text+0x42): undefined reference to `for_write_seq_lis'
x.f90:(.text+0x74): undefined reference to `for_write_seq_lis_xmit'
collect2: error: ld returned 1 exit status
You may noticed the undefined reference name pattern is similar with yours, if you link with
gcc y.c x.o -W -Wall -L/path/to/your/ifort_lib -lifcore -ldl
The problem should be solved. Depend on the FORTRAN feature you used, you may need link some more ifort library. This part need you do some research and figure out.

Linker error of unused variable and function

I have written following test program
int proc1();
extern int globalvar;
int func1 ()
{
return globalvar + 1;
}
int func2()
{
return proc1()+3;
}
int main()
{
return 0;
}
As you can see that this program is not doing anything. However, while compiling it, I faced linker error of globalvar and int proc1() despite the facts that these are not going to be referenced from the entry point function main.
I faced problem on both Windows(using cl) and Linux(using gcc).
Is there any way to instruct the compiler/linker not to link this unreferenced global variable and function from the entry point (on cl, gcc and clang)?
Exact error message on Windows:
test.obj : error LNK2019: unresolved external symbol "int globalvar" (?globalvar##3HA) referenced in function "int __cdecl func1(void)" (?func1##YAHXZ)
test.obj : error LNK2019: unresolved external symbol "int __cdecl proc1(void)" (?proc1##YAHXZ) referenced in function "int __cdecl func2(void)" (?func2##YAHXZ)
test.exe : fatal error LNK1120: 2 unresolved externals
You can fix this, in gcc, like this:
gcc -ffunction-sections -Wl,--gc-sections test.c
That does two things:
It instructs the compiler to emit each function in its own 'section' in the binary file.
It instructs the linker to discard (garbage collect) sections that are not referenced.
This means that func1 and func2 will be discarded, and therefore there will be not more references to globalvar or proc1.

Inluding functions in header file [duplicate]

This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 9 years ago.
I have header file:
dictionary.h:
#ifndef dictionary_h__
#define dictionary_h__
extern char *BoyerMoore_positive(char *string, int strLength);
extern char *BoyerMoore_negative(char *string, int strLength);
extern char *BoyerMoore_skip(char *string, int strLength);
#endif
function definations: dictionary.cpp
#include<stdio.h>
#include<string.h>
char *BoyerMoore_positive(char *string, int strLength)
{
} ---- //for each function
and main file main.cpp:
#include "dictionary.h"
#pragma GCC diagnostic ignored "-Wwrite-strings"
using namespace std;
void *SocketHandler(void *);
int main(int argv, char **argc)
{
----
skp = BoyerMoore_skip(ch[i], strlen(ch[i]) );
if(skp != NULL)
{
i++;
printf("in\n");
continue;
}
printf("\n hi2 \n");
str = BoyerMoore_positive(ch[i], strlen(ch[i]) );
str2= BoyerMoore_negative(ch[i], strlen(ch[i]) );
----
}
When I execute main.cpp
it gives:
/tmp/ccNxb1ix.o: In function `SocketHandler(void*)':
LinServer.cpp:(.text+0x524): undefined reference to `BoyerMoore_skip(char*, int)'
LinServer.cpp:(.text+0x587): undefined reference to `BoyerMoore_positive(char*, int)'
LinServer.cpp:(.text+0x5bd): undefined reference to `BoyerMoore_negative(char*, int)'
collect2: error: ld returned 1 exit status
I dont know why it could not find the function!
Help appreciated!
You need to compile both source files into main.o and dictionary.o and then link these object file together into the final executable:
$ g++ -c main.cpp
$ g++ -c dictionary.cpp
$ g++ -o myexe main.o dictionary.o
Or you can build and link in one go:
$ g++ -o myexe main.cpp dictionary.cpp
You'd normally create a Makefile to take the drudgery out of this process, which might be as little as (untested):
myexe: main.o dictionary.o
Then it's simply:
$ make
Are you sure that your dictionary.cpp is included to your project and built without errors?
Linker can't find those functions in object-files after compilation, check out full log for compilation error or success of your dictionary.cpp file.