Click here to Skip to main content
15,121,818 members
Articles / Programming Languages / C++
Technical Blog
Posted 28 Jun 2016

Tagged as

Stats

13.5K views
8 bookmarked

Please Have a C API For Your Library

Rate me:
Please Sign up or sign in to vote.
4.78/5 (17 votes)
28 Jun 2016CPOL3 min read
Please have a C API for your library

C++ can be terrible when crossing library and build system boundaries. To provide yet another case in point, let me document for posterity a problem I recently ran into when bundling WebRTC as a third party library in another project - I hope it will save the time for someone in the future. So, having sorted out linker problems due to compiling against different C++ standard libraries (libstdc++ vs libc++ - which perhaps deserves discussion on its own), duplicated symbols between BoringSSL and OpenSSL (Ok, this was not a C++ problem) and similar nuisances, I finally had just a couple of linker errors, albeit somewhat cryptic:

undefined reference to `non-virtual thunk to buzz::IqTask::HandleStanza(buzz::XmlElement const*)'

To make it a bit less cryptic: in case of classes with multiple inheritance, vtbl (table of virtual functions) may not contain pointers to the virtual functions directly, because depending on which pointer the method is called from, an offset may need to be added or subtracted from this pointer before calling that method. This is why virtual table in subclasses points to those short "thunk" functions that usually do just add/sub and jmp - see here and ultimately here for details0.

So, WebRTC's libjingle has a header file which defines class IqTask (a descendant of XmppTask and a couple other classes, therefore multiple inheritance is involved), and that class has a virtual method HandleStanza(). Both our code and WebRTC code include that header, so both need to define a virtual table for that class. Apparently, I missed something and compiler stripped out that thunk from the library or did not generate it altogether?

However, quick check with nm and c++filt did not reveal anything wrong - at first glance, the thunk, referenced in our object file, is present in the library and should link right in:

nm -po *.o | c++filt | grep IqTask::HandleStanza
Module.XMPP.cpp.o:                 U non-virtual thunk to buzz::IqTask::HandleStanza(buzz::XmlElement const*)
librtc_xmpp.a:rtc_xmpp.iqtask.o:0000000000000360 T non-virtual thunk to buzz::IqTask::HandleStanza(buzz::XmlElement const*)

Baffled, I spent some time reading up on how to better debug the linker, before an idea struck me - c++filt may be masking the problem, I need to see the symbols as they are! And indeed - thunk's mangled names were different between the object files (produced by different build processes, mind you):

Module.XMPP.cpp.o:                 U _ZThn136_N4buzz6IqTask12HandleStanzaEPKNS_10XmlElementE
librtc_xmpp.a:rtc_xmpp.iqtask.o:0000000000000360: T _ZThn160_N4buzz6IqTask12HandleStanzaEPKNS_10XmlElementE

I checked the source of __cxa_demangle() for meaning of those numbers, but did not find any clue how to narrow down the cause of the offset discrepancy. Figuring out that this might have been due to mismatch of class layout or number of methods, which should boil down to differences in compiler options or defined symbols, I proceeded to comparing those.

I'll spare you the process of adding/removing compiler flags in both the build systems (for our code and for the library, which uses gyp), and fast-forward to the end: the difference was caused by <span style="font-family: "arial" , sans-serif; font-size: x-small;">_GLIBCXX_DEBUG</span> defined by WebRTC in Debug configuration "just in case". Having unset that (by hacking the .gyp file), I was able to produce the library files with the compatible class layout.

This is not the only problem experienced with the library due to it exposing a C++ API, but that's enough to make a point. C++ is a great language for standalone applications, but for anything that needs binary stability, be it run-time or compile-time (i.e., libraries, shared objects), it is a wrong choice. Some of the problems apply to C as well, but linking to a C library is usually much easier, as well as taking control of its memory allocation (which is another feature that WebRTC regrettably lacks).

I'm beating a dead horse here, and the point of C++ being unsuitable for interfacing with other software has been long made. Still, there are libraries with C++ interfaces out there, that, at least in non-trivial projects, cause more pain than gain. Hence, I kindly ask all current and future library authors: no matter what language you use internally, please, provide a C API to your library - like, literally, extern "C" {...}. Thank you in advance.


0. If you decide to compare this with nullptr, more trickery will be needed on compiler side because the pointer may no longer be arithmetically 0 due to these adjustments.?

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

RCL_SPD
United States United States
No Biography provided

Comments and Discussions

 
GeneralMy vote of 5 Pin
eslipak25-Jul-16 11:01
professionaleslipak25-Jul-16 11:01 
Question+5 +5 +5 +5 +5 +5 Pin
den2k888-Jul-16 4:51
professionalden2k888-Jul-16 4:51 
GeneralMy vote of 5 Pin
henrin29-Jun-16 10:29
Memberhenrin29-Jun-16 10:29 
GeneralMy vote of 5 Pin
hooodaticus29-Jun-16 7:43
Memberhooodaticus29-Jun-16 7:43 
GeneralRe: My vote of 5 Pin
David A. Gray29-Jun-16 11:59
MemberDavid A. Gray29-Jun-16 11:59 
QuestionABI not API Pin
Zebedee Mason29-Jun-16 2:29
MemberZebedee Mason29-Jun-16 2:29 
QuestionAnother Point in Favor of a C API Pin
David A. Gray28-Jun-16 21:14
MemberDavid A. Gray28-Jun-16 21:14 
GeneralMy vote of 5 Pin
David A. Gray28-Jun-16 20:52
MemberDavid A. Gray28-Jun-16 20:52 
GeneralRe: My vote of 5 Pin
Steven J. Ackerman29-Jun-16 7:48
MemberSteven J. Ackerman29-Jun-16 7:48 
GeneralRe: My vote of 5 Pin
Austin Mullins29-Jun-16 8:41
MemberAustin Mullins29-Jun-16 8:41 
David A. Gray wrote:
Moreover, if your library has only a C interface, it cannot be used at all with programs written in anything but C .


I think you meant C++. Otherwise it sounds like you're disagreeing with article. I think you agree with it since you gave it a 5/5.
GeneralRe: My vote of 5 Pin
David A. Gray29-Jun-16 11:53
MemberDavid A. Gray29-Jun-16 11:53 
GeneralRe: My vote of 5 Pin
KarstenK14-Jul-16 2:48
mveKarstenK14-Jul-16 2:48 
GeneralRe: My vote of 5 Pin
David A. Gray14-Jul-16 5:57
MemberDavid A. Gray14-Jul-16 5:57 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.