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
Related
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
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.
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
I am trying to write a makefile for a project. The project involves a test program that defines a main function written in C++11 that is supposed to call a shared object library written in c99 and run some tests.
My makefile successfully compiles the c99 library and produces "libhanoi.so".
When I try to link the C99 library to the C++11 part, I get the following error:
g++ -std=gnu++11 -L. -lhanoi -o main tests/testing.cpp tests/main.cpp
/tmp/cctHQTcW.o: In function `binarion_constructor(unsigned long*)':
main.cpp:(.text+0x28): undefined reference to `binarion64_t'
collect2: error: ld returned 1 exit status
Makefile:29: recipe for target 'tests' failed
make: *** [tests] Error 1
However, the output of "nm -C libhanoi.so" shows that the binarion64_t function is being exported by libhanoi.so:
0000000000000610 T binarion64_t(long long, long long)
When I introduce a typo into the name of libhanoi.so, it introduces an error saying it can't find libhanoi.so.
So it must be able to find libhanoi.so and libhanoi.so is exporting the unimplemented function in main.cpp, yet it still is giving an undefined reference. What's going on?
Minimal example:
hanoi.h:
#ifndef HANOI_H
#define HANOI_H
#include <inttypes.h>
// binarion (base -1+i) constructor
uint64_t binarion64_t(long long A, long long B);
#endif // HANOI_H
binarion.c:
#include "hanoi.h"
uint64_t binarion64_t(long long A,long long B){
return 0;
}
main.cpp:
#include <stdio.h>
extern "C" {
#include "hanoi.h"
};
uint64_t binarion_constructor(uint64_t * args){
return binarion64_t(args[0], args[1]);
}
int main(void){
return 0;
}
Compile:
g++ -std=c99 -c binarion.c
g++ -std=c99 -shared -o libhanoi.so binarion.o -lm
g++ -std=gnu++11 -L. -lhanoi -o main main.cpp
output:
/tmp/ccjoRmCg.o: In function `binarion_constructor(unsigned long*)':
main.cpp:(.text+0x28): undefined reference to `binarion64_t'
collect2: error: ld returned 1 exit status
EDIT:
The commands I'm running are:
gcc -std=c99 -c binarion.c
gcc -std=c99 -shared -o libhanoi.so binarion.o -lm
g++ -std=gnu++11 -L. -lhanoi -o main main.cpp
The files are exactly the ones in the question. The output of "readelf -s libhanoi.so | grep binarion" is:
12: 0000000000000660 19 FUNC GLOBAL DEFAULT 11 binarion64_t
33: 0000000000000000 0 FILE LOCAL DEFAULT ABS binarion.c
46: 0000000000000660 19 FUNC GLOBAL DEFAULT 11 binarion64_t
and the output of "g++ -std=gnu++11 -L. -lhanoi -o main main.cpp" is:
/tmp/cczfgY8M.o: In function `binarion_constructor(unsigned long*)':
main.cpp:(.text+0x28): undefined reference to `binarion64_t'
collect2: error: ld returned 1 exit status
TL; DR:
Use:
gcc -std=c99 -c binarion.c
gcc -std=c99 -shared -o libhanoi.so binarion.o -lm
g++ -std=gnu++11 -L. -lhanoi -o main main.cpp
Explanation:
You should be using gcc to compile a C file, g++ is for C++. When you do g++ -std=c99 -c binarion.c the compiler gives you a hint with:
cc1plus: warning: command line option ‘-std=c99’ is valid for C/ObjC but not for C++
This means that you end up compiling your library as a C++ library. You can verify that by calling readelf -s libhanoi.so | grep binarion:
9: 00000000000005da 19 FUNC GLOBAL DEFAULT 9 _Z12binarion64_txx
29: 0000000000000000 0 FILE LOCAL DEFAULT ABS binarion.c
44: 00000000000005da 19 FUNC GLOBAL DEFAULT 9 _Z12binarion64_txx
As you can see, the function has been name-mangled, which is something C++ does, and C doesn't.
However, when compiling main.cpp you tell the compiler that binarion_t has C linkage:
extern "C" {
#include "hanoi.h"
};
So it is searching for unmangled binarion_t (instead of _Z12binarion64_txx).
I am just trying to compile this file helloworld.cpp
#include <iostream>
#include <cvc4/cvc4.h>
using namespace CVC4;
int main() {
ExprManager em;
Expr helloworld = em.mkVar("Hello World!", em.booleanType());
SmtEngine smt(&em);
std::cout << helloworld << " is " << smt.query(helloworld) << std::endl;
return 0;
}
using g++ helloworld.cpp -lcvc4 -o helloworld -lcvc4 -Wno-deprecated. But it is giving me this error
/tmp/cc9SFpL4.o: In function `main':
helloworld.cpp:(.text+0xac): undefined reference to `CVC4::ExprManager::mkVar(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, CVC4::Type, unsigned int)'
collect2: error: ld returned 1 exit status
Help!
I have installed CVC4 adding repo link in /etc/apt/sources.list and then calling sudo apt-get install cvc4 libcvc4-dev libcvc4parser-dev.
EDIT: I mistyped g++ helloworld.cpp -lcvc4 ... I used g++ helloworld.cpp -o helloworld -lcvc4 -Wno-deprecated. Actually I used all combinations, permutations.
This seems to be a problem with the OP's environment. Both r4C9rAyrd6A1 and I were able to compile the example on our local machines. The specific issue might have been that the OP's compiler wanted the -lcvc4 linker flag after the other flags, e.g. g++ helloworld.cpp -Wno-deprecated -o helloworld -lcvc4 as mentioned in the comments.