Cannot Call C++ Code from C without Error [duplicate] - c++

This question already has answers here:
How to mix C++ and C correctly
(2 answers)
Closed 4 years ago.
I'm trying to write a C++ library that can be called from C. However, whenever I try to even write a bare minimum example, it crashes with undefined references. Here is my code:
mylibrary.h
#ifndef __MY_CPP_THING_H
#define __MY_CPP_THING_H
#ifdef __cplusplus
extern "C" {
#endif
void printSomething();
#ifdef __cplusplus
}
#endif
#endif
mylibrary.cpp
#include <iostream>
#include "mylibrary.h"
extern "C" {
void printSomething() {
std::cout << "PLEASE PRINT\n";
}
}
main.c
#include "mylibrary.h"
int main() {
printSomething();
return 0;
}
The compiling process goes something like this:
g++ -c mylibrary.cpp -o mylibrary.o (create "mylibrary.o")
ar rcs libmylibrary.a mylibrary.o (create static library "libmylibrary.a")
gcc main.c -L. -lmylibrary (link static library and compile C source file)
However, I receive this error dump:
mylibrary.o:mylibrary.cpp:(.text+0x17): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
mylibrary.o:mylibrary.cpp:(.text+0x32): undefined reference to `std::ios_base::Init::~Init()'
mylibrary.o:mylibrary.cpp:(.text+0x62): undefined reference to `std::ios_base::Init::Init()'
mylibrary.o:mylibrary.cpp:(.rdata$.refptr._ZSt4cout[.refptr._ZSt4cout]+0x0): undefined reference to `std::cout'
collect2.exe: error: ld returned 1 exit status
Any suggestions on how to resolve the error?

mylibrary.o still depends on C++ standard library and gcc doesn't know about it. Call gcc with -lstdc++ in the last step.

Creating a dynamic library instead of a static library should do the trick :
$ gcc -c main.c
$ g++ -fPIC -shared -o mylibrary.so mylibrary.cpp
$ gcc -o main main.o mylibrary.so
and then :
$ LD_LIBRARY_PATH=".:${LD_LIBRARY_PATH}" ./main
PLEASE PRINT
with :
$ objdump -p main | grep NEEDED
NEEDED mylibrary.so
NEEDED libc.so.6
$ objdump -p mylibrary.so | grep NEEDED
NEEDED libstdc++.so.6
NEEDED libc.so.6

Related

How I can link standard C++ libraries with g++ on Windows?

I just have a simple structure:
main.cpp
#include <iostream>
#include "../header_files/h.h"
int main(void)
{
f();
g();
}
src1.cpp
#include <iostream>
void f() { std::cout << "f()" << std::endl; };
void g() { std::cout << "g()" << std::endl; };
h.h
void f(); void g();
I am trying to (only) compile main.cpp and src1.cpp with:
PS> g++ -c main.cpp src.cpp
Then get an executable from the created .obj files:
PS> g++ main.o src.o -o exec.exe
.\ss.o:ss.cpp:(.text+0x17): undefined reference to std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
\ss.o:ss.cpp:(.text+0x26): undefined reference to std::ostream::operator<<(std::ostream& (*)(std::ostream&))
\ss.o:ss.cpp:(.text+0x41): undefined reference to std::ios_base::Init::~Init()
\ss.o:ss.cpp:(.text+0x71): undefined reference to std::ios_base::Init::Init()
Here I am getting a verbose linker error; that's because I am using iostream library; I just need to tell g++ how to link to this library or any other standard library I want to use. How I can do that?
Actually I can use g++ main.cpp src1.cpp -o test, or using any IDE, but I do not need to do this. Just need a way to tell g++ (maybe via command-line args) how to go to the actual definitions. I need to produce the .exe file from the generated obj files, not something else.
Windows: x64
g++ -ver: x86_64-8.1.0-posix-seh-rt_v6-rev0 (mingw64)
Not using any IDEs

building a .so that is also an executable with C++

Based on building a .so that is also an executable I'm trying o reproduce with C++ and I'm getting a segmentation fault on main program execution.
/* pie.cpp */
#include <cstdio>
int foo()
{
printf("in %s %s:%d\n", __func__, __FILE__, __LINE__);
return 42;
}
int main()
{
printf("in %s %s:%d\n", __func__, __FILE__, __LINE__);
return foo();
}
/* pie.h */
#ifndef PIE_H
#define PIE_H
int foo();
#endif
/* main.cpp */
#include <cstdio>
#include <string>
#include "pie.h"
std::string data;
int main()
{
data="TEST";
printf("in %s %s:%d [%s]\n", __func__, __FILE__, __LINE__, data.c_str());
return foo();
}
$ g++ -fPIC -pie -o pie.so pie.cpp -Wl,-E
$ g++ main.cpp ./pie.so
$ ./pie.so
in main pie.cpp:10
in foo pie.cpp:5
$ ./a.out
Segmentation fault (core dumped)
$
I the definition of "data" is moved from global to local it runs.
It seems that global variables are not being initialized.
Can someone explain what happens and what should be done to make it run?
gdb backtrace on code file result:
Program terminated with signal SIGSEGV, Segmentation fault.
#0 std::string::size (this=0x404080 <data>) at /usr/src/debug/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/x86_64-redhat-linux/libstdc++-v3/include/bits/basic_string.h:716
716 { return _M_rep()->_M_length; }
(gdb) bt
#0 std::string::size (this=0x404080 <data>) at /usr/src/debug/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/x86_64-redhat-linux/libstdc++-v3/include/bits/basic_string.h:716
#1 std::string::assign (this=0x404080 <data>, __s=0x402010 "TEST", __n=4) at /usr/src/debug/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/x86_64-redhat-linux/libstdc++-v3/include/bits/basic_string.tcc:262
#2 0x00000000004011c5 in main () at main.cpp:9
Thanks!
I just tried code from my old answer; it no longer works using a recent GLIBC (I have 2.31-9+build1):
$ gcc -fPIC -pie -o pie.so pie.c -Wl,-E
$ gcc main.c ./pie.so
$ ./pie.so
in main pie.c:10
in foo pie.c:5
$ ./a.out
./a.out: error while loading shared libraries: ./pie.so: cannot dynamically load position-independent executable
Using your C++ example, I can't build it with your commands:
$ g++ -fPIC -pie -o pie.so pie.cc -Wl,-E
$ gcc main.cc ./pie.so
/usr/bin/ld: /tmp/ccaXra73.o: in function `main':
main.cc:(.text+0x13): undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::operator=(char const*)'
/usr/bin/ld: main.cc:(.text+0x1f): undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::c_str() const'
/usr/bin/ld: /tmp/ccaXra73.o: in function `__static_initialization_and_destruction_0(int, int)':
main.cc:(.text+0x77): undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string()'
/usr/bin/ld: main.cc:(.text+0x8c): undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()'
collect2: error: ld returned 1 exit status
If I link with g++ (as you should when you have C++ code), then it links fine but fails the same way as C code does:
$ g++ main.cc ./pie.so
$ ./pie.so
in main pie.cc:9
in foo pie.cc:4
$ ./a.out
./a.out: error while loading shared libraries: ./pie.so: cannot dynamically load position-independent executable
So I guess the answer is: it wasn't intended to work this way (and worked in the past "by accident"), and now GLIBC detects and rejects it.

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
// ^^^^^^^^

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.

Problems with wrapping a C++ code

To try the C++ code wrapping within C, I used the following:
header.h
#ifdef __cplusplus
extern "C"
#endif
void func();
source.cpp
#include "header.h"
#include <iostream>
extern "C" void func()
{
std::cout << "This is C++ code!" << std::endl;
}
and source.c
#include "header.h"
int main()
{
func();
}
To compile and link, I used the following sequence:
g++ -c source.cpp
gcc source.c source.o -o myprog
The error I get is:
ence to std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)'
source.cpp:(.text+0x1c): undefined reference tostd::basic_ostream >::operator<<(std::basic_ostream >& (*)(std::basic_ostream >&))'
source.o: In function __static_initialization_and_destruction_0(int, int)':
source.cpp:(.text+0x45): undefined reference tostd::ios_base::Init::Init()'
source.cpp:(.text+0x4a): undefined reference to std::ios_base::Init::~Init()'
source.o:(.eh_frame+0x12): undefined reference to__gxx_personality_v0'
collect2: ld returned 1 exit status
How can I make this simple code compile and run? It should serve as a basis for my future
development.
Link with g++ as well:
g++ -c source.cpp
g++ source.c source.o -o myprog
Or better:
g++ -c source.cpp -o source_cpp.o
gcc -c source.c -o source_c.o
g++ -o myprog source_cpp.o source_c.o
Best to avoid the common prefix source.{cpp,c} as it causes confusion.
You'll still have to link with the C++ linker:
gcc -o source-c.o source.c
g++ -o source-p.o source.cpp
g++ -o myprog source-c.o source-p.o
Your C++ object file will need to resolve symbols from the C++ library, which only the C++ linker will pull in automatically. (Alternatively, you could specify the library manually for the C linker.)
you can't do that, you can compile C code with gcc, and then link it with c++ objects with g++, referring to the symbols defined in the C objects via the extern keyword, but you can't do the opposite