[libgpiod] C++ Bindings ABI Compatibility

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Good evening, Bartosz!

Starting another email thread on this subject for future
searchability, although some previous discussion was held under the
'[libgpiod] cxx bindings: time_point vs duration' thread.

In that thread, you last said:

> I started reading on my own and I think I now have a slightly better
> idea about C++ and its ABI. I also see what a mess the original
> libgpiod bindings are in terms of ABI compatibility but fear not!
> Right now (v2.0) is the time to make it better! :)
>
> At a personal level I'm not too concerned about the ABI compatibility
> of C++ bindings - I much more care about the API. This is because
> libgpiod is aimed mostly at bespoke embedded distros (yocto,
> buildroot, openwrt etc.) I understand however that it's an important
> issue for distros.
>
> I didn't know any better at the time of writing libgpiodcxx so I just
> put all private members in the main header, exposing them to the users
> of the library. I'm not sure why I didn't realize that C++ classes are
> basically C structs (and exposing them amounts to exposing struct in a
> C header) but I just didn't know any better.
>
> I assume that you'll either propose to use the Pimpl pattern or a
> header-only library. I noticed that Pimpl is what Qt5 uses while
> header-only is more of a boost thing. If so - the timing is great as
> I'm open to either solution for libgpiod v2.0.


If you did some general reading on the topic, you'll realise just how
fortunate we are to be talking about Linux here and not Microsoft
Windows.  It's an absolute minefield.  In fact, Microsoft now
instructs developers to not provide C++ ABIs and to use a stable
platform ABI such as C, COM or WinRT.  Many of Microsoft's libraries
are written in C++, but a C ABI is provided to avoid ABI related
issues.  And then there is the fact that a process can have multiple
'components' loaded using different versions of the Microsoft C
Runtime (CRT), each possessing different heaps, etc.  It causes a lot
of pain for a lot of individuals and parties.

You may or may not be surprised how many professional software
developers / engineers have no clue regarding ABI compatibility.  Most
of them learn the hard way (which is exactly how it was brought to my
attention and my what a hard lesson it was).  But none of us are born
knowing everything.

Generally speaking, if you have a shared library largely implemented
in C++ and ABI compatibility is of a concern to you, your options are
as follows:

1.  Provide a C ABI to the library, wrapping the C++ internals.
Resource management should be handled within the library and handles
or opaque pointers should be used to pass references to library
managed resources to the using application.  Exceptions and non plain
old data (POD) type objects should not cross the shared library -
application boundary.

2.  Provide a C++ ABI, but implement the PImpl pattern such that it is
possible to maintain ABI compatibility for the major version releases
of the library (implementation details may be changed to implement bug
fixes, etc, which is not possible without using the PImpl pattern).
Even with this approach, there are limitations as to what should be
passed over the shared library - application boundary.

3.  Opt to provide a static library instead of a shared library.  The
shared library should be built with the same compiler and compiler
version as that to be used for the application, etc, in order to avoid
issues.  If linking fails here, this is still preferable to
experiencing loading and linking issues with shared libraries, which
may only become apparent once the application and library is deployed
and executed at runtime.

4.  Provide a header-only library, which is a popular option for many
C++ libraries these days.  This option is not without its
disadvantages, but the worry of library interface ABI compatibility
disappears.  This approach, much like the static library approach,
allows the full feature set of C++ to be utilised within the library
interface (e.g., the use of exceptions, etc).

You're right in that Qt makes use of the PImpl pattern.  The framework
uses return codes for error handling, as exceptions are still
problematic with this approach, and mostly Qt interface types or POD C
types are exchanged over the shared library - application boundary.
Some standard library types are passed across the boundary and this is
usually where problems arise.

For libgpiod, I would personally recommend going down the header-only
library approach.  The typical structure of most boost libraries, in
my opinion, would serve as a good model for the implementation of the
libgpiod C++ binding as a header-only library.  What would your
thoughts on this be?

Best Regards,
Jack



[Index of Archives]     [Linux SPI]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux