Using a haskell function from C++: Undefined reference error - c++

I want to call haskell functions out of C++ and did use the tutorial at http://www.haskell.org/ghc/docs/7.0.2/html/users_guide/ffi-ghc.html
So I have a haskell file Foo.hs:
module Foo where
foreign export ccall foo :: Int -> IO Int
foo :: Int -> IO Int
foo n = return (length (f n))
f :: Int -> [Int]
f 0 = []
f n = n:(f (n-1))
and called
ghc Foo.hs
which created a Foo_stub.h:
#include "HsFFI.h"
#ifdef __cplusplus
extern "C" {
#endif
extern HsInt foo(HsInt a1);
#ifdef __cplusplus
}
#endif
a Foo_stub.c:
#define IN_STG_CODE 0
#include "Rts.h"
#include "Stg.h"
#ifdef __cplusplus
extern "C" {
#endif
extern StgClosure Foo_zdffoozualy_closure;
HsInt foo(HsInt a1)
{
Capability *cap;
HaskellObj ret;
HsInt cret;
cap = rts_lock();
cap=rts_evalIO(cap,rts_apply(cap,(HaskellObj)runIO_closure,rts_apply(cap, Foo_zdffoozualy_closure,rts_mkInt(cap,a1))) ,&ret);
rts_checkSchedStatus("foo",cap);
cret=rts_getInt(ret);
rts_unlock(cap);
return cret;
}
static void stginit_export_Foo_zdffoozualy() __attribute__((constructor));
static void stginit_export_Foo_zdffoozualy()
{getStablePtr((StgPtr) &Foo_zdffoozualy_closure);}
#ifdef __cplusplus
}
#endif
It also created a Foo_stub.o file.
I now created a main.cpp file:
#include "Foo_stub.h"
int main()
{
foo(3);
}
and tried to compile it.
Using g++ failed:
$ g++ -I/usr/lib/ghc-7.0.3/include/ main.cpp Foo_stub.o
Foo_stub.o: In function `foo':
Foo_stub.c:(.text+0xa): undefined reference to `rts_lock'
Foo_stub.c:(.text+0x18): undefined reference to `rts_mkInt'
Foo_stub.c:(.text+0x20): undefined reference to `Foo_zdffoozualy_closure'
Foo_stub.c:(.text+0x28): undefined reference to `rts_apply'
Foo_stub.c:(.text+0x30): undefined reference to `base_GHCziTopHandler_runIO_closure'
Foo_stub.c:(.text+0x38): undefined reference to `rts_apply'
Foo_stub.c:(.text+0x48): undefined reference to `rts_evalIO'
Foo_stub.c:(.text+0x58): undefined reference to `rts_checkSchedStatus'
Foo_stub.c:(.text+0x62): undefined reference to `rts_getInt'
Foo_stub.c:(.text+0x6d): undefined reference to `rts_unlock'
Foo_stub.o: In function `stginit_export_Foo_zdffoozualy':
Foo_stub.c:(.text+0x80): undefined reference to `Foo_zdffoozualy_closure'
Foo_stub.c:(.text+0x85): undefined reference to `getStablePtr'
collect2: ld returned status 1
so I tried ghc --make. But this also failed:
$ ghc --make main.cpp Foo_stub.o
cc1plus: Warning: Option »-Wimplicit« is valid for C/ObjC, but not for C++ [activated by default]
Foo_stub.o: In function `foo':
Foo_stub.c:(.text+0x20): undefined reference to `Foo_zdffoozualy_closure'
Foo_stub.o: In function `stginit_export_Foo_zdffoozualy':
Foo_stub.c:(.text+0x80): undefined reference to `Foo_zdffoozualy_closure'
collect2: ld returned status 1
How can I compile it?

Try this:
$ ghc --make -no-hs-main main.cpp Foo.hs
I believe the problem is that GHC thinks the stub object file you're passing in is just another object to be linked normally, but you're not passing the Foo.o file itself, so the stub code has nothing to link to! Passing in the source file directly should solve it. (This is just conjecture based on the documentation and the error you're seeing, I haven't tested it.)
I think you could do separate compilation like this:
$ ghc --make Foo.hs
$ ghc --make -no-hs-main main.cpp Foo.o
but I'm not sure. You might also want to look into building your Haskell code into a shared library, and then linking it to your main program normally with g++.
-no-hs-main is required when your program's entry point isn't the Haskell value Main.main, as described in the documentation you linked.

Related

Simply including <opencv2/opencv.hpp> results in linking error

Simply including the OpenCV header results in linking error. Why is that?
// test.cpp
#include <opencv2/opencv.hpp>
int foo();
int bar();
int main() {
}
If I compile the file with g++ test.cpp, the following linking error occurs:
/tmp/ccugmQl4.o: In function `cv::String::~String()':
test.cpp:(.text._ZN2cv6StringD2Ev[_ZN2cv6StringD5Ev]+0x14): undefined reference to `cv::String::deallocate()'
/tmp/ccugmQl4.o: In function `cv::String::operator=(cv::String const&)':
test.cpp:(.text._ZN2cv6StringaSERKS0_[_ZN2cv6StringaSERKS0_]+0x28): undefined reference to `cv::String::deallocate()'
collect2: error: ld returned 1 exit status
If I compile with g++ test.cpp -lopencv_core, it works all right.
My question is:
It seems to me that there's no need to resolve undefined symbols if I do not use it, like the functions foo and bar. There's no definition for them but the compile-link process works alright.
I don't use any OpenCV functions either. Why is there linking error only for OpenCV functions?
And what kinds of stuff defined in headers can cause such a linking error?
If you tweak your example a little bit
// test.cpp
int foo();
int bar() {
foo();
}
int main() {
}
You would notice that it'd stop working because linker won't be able to understand what is foo();
The same thing happens when you include opencv header - there are references to functions which are declared but since you never link opencv itself - linker can't figure what those functions are and where to get them.

Error " undefined reference to `std::ios_base" while linking cpp header only library to fortran [duplicate]

This question already has an answer here:
Linking Fortran and C++ binaries using gcc
(1 answer)
Closed 3 years ago.
I am trying to link a header only library (which is in cpp) to a fortran code. I am using this example to test my library.
$ cat cppfunction.C
#include<cmath>
#include<mylib/mylib.hpp>
extern "C"
{
void cppfunction_(float *a, float *b);
}
void cppfunction_(float *a, float *b)
{
*a=7.0;
*b=9.0;
}
$ cat fprogram.f
program fprogram
real a,b
a=1.0
b=2.0
print*,"Before fortran function is called"
print*,'a=',a
print*,'b=',b
call cppfunction(a,b)
print*,"After cpp function is called"
print*,'a=',a
print*,'b=',b
stop
end
For compiling I am using:
$ gfortran -c fprogram.f
$ g++ -c cppfunction.C
$ gfortran -lc -o fprogram fprogram.o cppfunction.o
This runs fine if I remove my library header. But have this error when included:
cppfunction.o: In function `__static_initialization_and_destruction_0(int, int)':
cppfunction.C:(.text+0xa1): undefined reference to `std::ios_base::Init::Init()'
cppfunction.C:(.text+0xb0): undefined reference to `std::ios_base::Init::~Init()'
collect2: error: ld returned 1 exit status
Anything I might be doing wrong?
You're not linking the C++ standard library:
gfortran -lc -lstdc++ -o fprogram fprogram.o cppfunction.o
// ^^^^^^^^

How to force g++ linker to load a symbols not being directly called - avoiding undefined reference

The problem I'm facing is difficult to describe and explain, but let's try...
Enrivornment: Ubuntu, C++ and g++
So I have an hierarchy of c++ projects and namespaces:
main: My main program - that calls....
objectaccess: Access objects (read, write, update, delete) - that calls...
commonaccess: Encapsulate access to sqlite3 functions (sqlite3_open, sqlite3_exec, etc.) - that calls...
sqlite3.so: The Sqlite3 library.
So, an example call code would be:
#include "objectaccess.hpp"
#include "commonaccess.hpp"
int main()
{
int id = 10;
myobjecttype mo = objectaccess::get(id);
}
At objectaccess I have:
#include "commonaccess.hpp"
namespace objectaccess {
myobjecttype get(int id)
{
myobjecttype mo = commonaccess::getFromTableX(id);
return mo;
}
}
At commonaccess I have:
#include <sqlite3.h>
namespace commonaccess {
myobjecttype getFromTableX(int id)
{
sqlite3_init(whatever...);
sqlite3_exe(whatever...);
myobjecttype retobject;
retobject.whatever = data1;
return retobject;
}
}
The code runs fine and is tested, except for one problem. All three namespaces are in different projects delivering a dynamic library (commonaccess.so and objectaccess.so) except for the main program that returns a binary executable.
My problem is:
At main, if I make a call to any of commonaccess functions, I get the following errors on linking:
g++ -L"/home/workspace/objectaccess/Debug"
-L"/home/workspace/commonaccess/Debug"
-L/usr/lib/i386-linux-gnu -Xlinker -rpath="./" -o "test" ./src/test.o
-lsqlite3 -lobjectaccess -lcommonaccess
/home/workspace/commonaccess/Debug/libcommonaccess.so: undefined reference to `sqlite3_close'
/home/workspace/commonaccess/Debug/libcommonaccess.so: undefined reference to `sqlite3_exec'
/home/workspace/commonaccess/Debug/libcommonaccess.so: undefined reference to `sqlite3_free'
/home/workspace/commonaccess/Debug/libcommonaccess.so: undefined reference to `sqlite3_errmsg'
/home/workspace/commonaccess/Debug/libcommonaccess.so: undefined reference to `sqlite3_open'
/home/workspace/commonaccess/Debug/libcommonaccess.so: undefined reference to `sqlite3_last_insert_rowid'
collect2: error: ld returned 1 exit status
This is simply solved adding at main() a call to any function of commonaccess, like:
#include "objectaccess.hpp"
#include "commonaccess.hpp"
int main()
{
commonaccess::dummycall();
int id = 10;
myobjecttype mo = objectaccess::get(id);
}
Actually calling a dummy function is not desired, so:
a) Why the linker is not being able to solve these references without directly calling any of the commonaccess functions?
b) Why only adding a call to the lower hierarchy namespace in the main program "teaches" the linker about real reference to sqlite3 functions?
Switch the order of libraries being linked. GNU linker can't reorder them, nor keeps references to calls not used so far, so -lsqlite3 is currently useless. Put it after the library that actually uses sqlite3 calls, something like g++ -L"/home/workspace/objectaccess/Debug" -L"/home/workspace/commonaccess/Debug" -L/usr/lib/i386-linux-gnu -Xlinker -rpath="./" -o "test" ./src/test.o -lobjectaccess -lcommonaccess -lsqlite3

undefined reference to function in gcc

I am trying to use a C static library but getting the following error while compiling/linking in gcc. The main file test.c needs to call a function from the static library libtest.a
Header file : testcplusplus.h
void print_cplusplus(int b);
testcplusplus.c :
#include <stdio.h>
#include "testcplusplus.h"
void print_cplusplus(int b) {
printf ("Value of b is %d \n",b);
}
Main C file : test.c
#include <stdio.h>
#include "testcplusplus.h"
int main() {
int a = 2 ;
print_cplusplus(a);
}
Commands Used :
g++ -c -o testcplusplus.o testcplusplus.c
ar rvs libtest.a testcplusplus.o
gcc -o test test.c -L. -ltest **// Error comes here**
Error:
In function `main':
test.c:(.text+0x15): undefined reference to `print_cplusplus'
collect2: ld returned 1 exit status
You only specify function parameter types when you declare/define the function, not when you call it. The function call should look like
print_cplusplus(a);
You also need to include testcplusplus.h from test.c so that the declaration is available when you call it. The return type of main needs to be int; and print_cplusplus should either have void return type, or should return a value.
Finally, you'll need to declare the function extern "C" for it to be callable from a C program - but only when compiling C++.
// testcplusplus.h
#ifdef __cplusplus
extern "C" {
#endif
void print_cplusplus(int b);
#ifdef __cplusplus
}
#endif
You don't rewrite a variables type when you use it, it's only used in declarations:
print_cplusplus(a);

Building a dynamic library with haskell and using it from C++

I want to build a dynamic library containing haskell functions. I work on linux and want to call this dynamic library from C++ code.
I used the example at http://wiki.python.org/moin/PythonVsHaskell and have the following files:
Test.hs:
{-# LANGUAGE ForeignFunctionInterface #-}
module Test where
import Foreign.C.Types
hsfun :: CInt -> IO CInt
hsfun x = do
putStrLn "Hello World"
return (42 + x)
foreign export ccall
hsfun :: CInt -> IO CInt
module_init.c:
#define CAT(a,b) XCAT(a,b)
#define XCAT(a,b) a ## b
#define STR(a) XSTR(a)
#define XSTR(a) #a
#include <HsFFI.h>
extern void CAT (__stginit_, MODULE) (void);
static void library_init (void) __attribute__ ((constructor));
static void
library_init (void)
{
/* This seems to be a no-op, but it makes the GHCRTS envvar work. */
static char *argv[] = { STR (MODULE) ".so", 0 }, **argv_ = argv;
static int argc = 1;
hs_init (&argc, &argv_);
hs_add_root (CAT (__stginit_, MODULE));
}
static void library_exit (void) __attribute__ ((destructor));
static void
library_exit (void)
{
hs_exit ();
}
Now I compile this files to a dynamic library:
$ ghc -dynamic -shared -fPIC -optc '-DMODULE=Test' Test.hs module_init.c -o libTest.so
[1 of 1] Compiling Test ( Test.hs, Test.o )
Linking libTest.so ...
This creates among other things the file Test_stub.h:
#include "HsFFI.h"
#ifdef __cplusplus
extern "C" {
#endif
extern HsInt32 hsfun(HsInt32 a1);
#ifdef __cplusplus
}
#endif
and Test_stub.c:
#define IN_STG_CODE 0
#include "Rts.h"
#include "Stg.h"
#ifdef __cplusplus
extern "C" {
#endif
extern StgClosure Test_zdfhsfunzua165_closure;
HsInt32 hsfun(HsInt32 a1)
{
Capability *cap;
HaskellObj ret;
HsInt32 cret;
cap = rts_lock();
cap=rts_evalIO(cap,rts_apply(cap,(HaskellObj)runIO_closure,rts_apply(cap,&Test_zdfhsfunzua165_closure,rts_mkInt32(cap,a1))) ,&ret);
rts_checkSchedStatus("hsfun",cap);
cret=rts_getInt32(ret);
rts_unlock(cap);
return cret;
}
static void stginit_export_Test_zdfhsfunzua165() __attribute__((constructor));
static void stginit_export_Test_zdfhsfunzua165()
{getStablePtr((StgPtr) &Test_zdfhsfunzua165_closure);}
#ifdef __cplusplus
}
#endif
Then I create a cpp file main.cpp:
#include "Test_stub.h"
#include <iostream>
using namespace std;
int main()
{
cout << hsfun(5);
}
and want to compile and link it. But when I call g++, it says:
$ g++ -I/usr/lib/ghc-7.0.3/include -L. -lTest main.cpp
/tmp/ccFP2AuB.o: In function `main':
main.cpp:(.text+0xa): undefined reference to `hsfun'
collect2: ld gab 1 als Ende-Status zurück
So I added the Test_stub.o file to the command line (although I think the hsfun function should already be defined in libTest.so which is added via the -lTest parameter. I don't think, I should link the Test_stub.o file into the executable because I want to use dynamic linking), but this also doesn't work:
$ g++ -I/usr/lib/ghc-7.0.3/include -L. -lTest main.cpp Test_stub.o
Test_stub.o: In function `hsfun':
Test_stub.c:(.text+0x9): undefined reference to `rts_lock'
Test_stub.c:(.text+0x16): undefined reference to `rts_mkInt32'
Test_stub.c:(.text+0x1d): undefined reference to `Test_zdfhsfunzua165_closure'
Test_stub.c:(.text+0x28): undefined reference to `rts_apply'
Test_stub.c:(.text+0x2f): undefined reference to `base_GHCziTopHandler_runIO_closure'
Test_stub.c:(.text+0x3a): undefined reference to `rts_apply'
Test_stub.c:(.text+0x4a): undefined reference to `rts_evalIO'
Test_stub.c:(.text+0x5c): undefined reference to `rts_checkSchedStatus'
Test_stub.c:(.text+0x66): undefined reference to `rts_getInt32'
Test_stub.c:(.text+0x70): undefined reference to `rts_unlock'
Test_stub.o: In function `stginit_export_Test_zdfhsfunzua165':
Test_stub.c:(.text.startup+0x3): undefined reference to `Test_zdfhsfunzua165_closure'
Test_stub.c:(.text.startup+0x8): undefined reference to `getStablePtr'
collect2: ld gab 1 als Ende-Status zurück
Do I have to link the Test_stub.o? If yes, why? And which arguments should I pass to the linker?
Probably easier than wrestling with g++ is letting ghc do the work,
ghc main.cpp -o hithere -L. -lTest -lstdc++
did the job for me after creating the shared lib the way you did. I have tested it with 7.2.2 and 7.0.2, both worked here.