3

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?

Griffort
  • 1,174
  • 1
  • 10
  • 26
  • 6
    The front-end program `gcc` doesn't link with the C++ standard library. You either have to do it yourself or use `g++` when linking as well. And yes, `g++` can be used to compile and build C source file as well, just as `gcc` can compile C++ source files. I know there are duplicates to this. – Some programmer dude Sep 14 '18 at 08:06
  • Basically don't call C++ from C. C++ library functions will, for instance, use exceptions and the C calling code cannot cope with them. – pmg Sep 14 '18 at 08:07
  • @Someprogrammerdude Unfortunately, due to my circumstances,`gcc` is the only option I have. How would I go about linking the standard library? – Griffort Sep 14 '18 at 08:10
  • @pmg There are plenty of decent ways to deal with that. The OP is not doing any of them, but that is beside the point. – Tim Seguine Sep 14 '18 at 08:10
  • @Griffort Does your cpp lib have to be a static lib? – Tim Seguine Sep 14 '18 at 08:11
  • @TimSeguine I would prefer that, but if making it shared would be the only way to make things work, then I wouldn't mind. – Griffort Sep 14 '18 at 08:13
  • @Griffort It isn't the only way, but I personally would prefer it to explicitly linking against libstdc++. – Tim Seguine Sep 14 '18 at 08:15
  • `__MY_CPP_THING_H` identifier is reserved to the implementation. By defining it, your program will have undefined behaviour. – eerorika Sep 14 '18 at 09:16
  • @user2079303 What makes it reserved? What are the standards for reserved macros? – Griffort Sep 14 '18 at 09:51
  • @Griffort the use of underscores makes it reserved. See the section [lex.name] of C++ standard. Remove the fist two underscores to fix it. – eerorika Sep 14 '18 at 10:26
  • @Griffort the short version is(not 100% true but safe): 1) double underscores are bad, 2) leading underscores are bad. – Tim Seguine Nov 11 '18 at 20:11

2 Answers2

7

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

David Ranieri
  • 39,972
  • 7
  • 52
  • 94
3

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
Sander De Dycker
  • 16,053
  • 1
  • 35
  • 40