4

How does a commercial library vendor manage to stick to the same ABI over years of development (or is this a bad assumption on my part)?

I would have thought that over time a lot of functions and class interfaces would be completely rewritten. Do they just have the foresight to know what footprint to use from the get-go?

Is it a bad idea to not change the ABI? Like you end up with a horrid ugly mess if you don't; which is more important, ABI staying the same, or the API making sense for a newbie?

EDIT: I may be getting ABI and API confused. As I understand it, changing the API would change the ABI?

  • I might be dense but what is an "ABI?" – Wyatt Barnett Oct 14 '15 at 23:33
  • @WyattBarnett Application Binary Interface API is what programmers use, ABI is how the library is linked to the executable. – NeomerArcana Oct 15 '15 at 0:01
  • Changing either might be a (possibly silent) breaking change in the other, but need not. – Deduplicator Oct 15 '15 at 0:50
4

ABI and API are different, but related things. An API is a contract that describes functionality. The ABI describes how modules communicate at the machine code level. The two can change independently, and one doesn't (or shouldn't) affect the other.

The ABI describes things like how parameters are passed to functions (on the stack, in registers, etc.), how system calls are made, how shared data is accessed, etc. An ABI is machine specific, operating system specific, often language specific, and also application specific.

An API, on the other hand, is often machine, operating system, and language agnostic.

There are large parts of the ABI that you don't often have to think about, because your language compiler and linker handle them for you. You might have to worry about it in some cases, for example the difference between cdecl and stdcall in C and C++. Staying with the same ABI for years is pretty easy for these parts. For example, code written for Win32 in 1995 will still work today. Even libraries that were compiled 20 years ago can be linked with 32-bit code that was compiled today.

Whatever API you're using should be steady across versions. Vendors make a concerted effort to keep the APIs backward compatible so that code written to use version 1 of the library can still link with version 5. Or 17. Granted, the API might be extended, but functions that were available in the first version usually exist and work the same many versions later. The internal implementation might be (very often is) different, but as long as the functions meet the initial contract, it doesn't matter how they're implemented.

Now, where you can get into trouble is if you change a data structure that's passed to or returned by an API function. As was pointed out in the comments, a change to a data structure that doesn't require a source code change, is considered an ABI change. That could be something as simple as changing structure packing, or rearranging the order of the individual structure members. Not to mention adding a field. In any of those cases, the size of the data structure could change, but the new version might very well link with an object module that was compiled for the older version. That would definitely break things.

Those are breaking changes that, although they don't require any source code changes, do require a recompile. And in my opinion if it requires a recompile, then it should be considered an API change.

  • I was just reading this techbase.kde.org/Policies/Binary_Compatibility_Issues_With_C++ which indicates that it's very easy to inadvertently make ABI changes. – NeomerArcana Oct 15 '15 at 2:10
  • You're describing platform-wide aspects of the ABI here, but there are also application-specific aspects. For example, if you add fields to a data structure, applications that were compiled against the old definition still have the old size compiled in, so they'll allocate less memory for instances than the new version of the library expects. The size of the structure is part of the library's ABI, so when it changes, you have to recompile the application using the new header file. (But you haven't broken API, since no source-code changes are needed in the application.) – Wyzard Oct 15 '15 at 3:50
  • @Wyzard: Interesting. I've always considered changing a structure to be an API change. I see that my understanding of ABI / API is somewhat different than what is apparently generally accepted. I will modify my answer accordingly. Thank you. – Jim Mischel Oct 15 '15 at 14:38
  • @NeomerArcana: Thank you for the link. I've updated my answer accordingly. – Jim Mischel Oct 15 '15 at 14:50
  • Adding a field to a structure is an API change, but not one that breaks compatibility with existing source code. But changing the size of a structure is an ABI change that breaks compatibility with existing compiled code. The two are basically independent; you can also make changes that break API but not ABI (such as renaming a field in a structure). In that case, existing compiled code will continue to work, but you have to change the source code before you can compile it again. – Wyzard Oct 15 '15 at 14:55
0

The API is easy to stick to, but the ABI is difficult. For example, ICU has an API for both C and C++:



Module Name 			C 		C++  

Basic Types and Constants 	utypes.h 	utypes.h  

Strings and Character Iteration 	ustring.h, utf8.h, utf16.h, UText, UCharIterator 	icu::UnicodeString, icu::CharacterIterator, icu::Appendable, icu::StringPiece,icu::ByteSink  

Unicode Character
Properties and Names uchar.h, uscript.h C API Sets of Unicode Code Points and Strings uset.h icu::UnicodeSet Maps from Strings to Integer Values (no C API) icu::BytesTrie, icu::UCharsTrie Codepage Conversion ucnv.h, ucnvsel.hb C API Codepage Detection ucsdet.h C API Unicode Text Compression ucnv.h
(encoding name "SCSU" or "BOCU-1") C API Locales uloc.h icu::Locale Resource Bundles ures.h icu::ResourceBundle Normalization unorm2.h icu::Normalizer2 Calendars ucal.h icu::Calendar Date and Time Formatting udat.h icu::DateFormat Message Formatting umsg.h icu::MessageFormat Number Formatting unumberformatter.h, unum.h icu::number::NumberFormatter (ICU 60+) or icu::NumberFormat (older versions) Number Spellout
(Rule Based Number Formatting) unum.h
(use UNUM_SPELLOUT) icu::RuleBasedNumberFormat Text Transformation
(Transliteration) utrans.h icu::Transliterator Bidirectional Algorithm ubidi.h, ubiditransform.h C API Arabic Shaping ushape.h C API Collation ucol.h icu::Collator String Searching usearch.h icu::StringSearch Index Characters/
Bucketing for Sorted Lists (no C API) icu::AlphabeticIndex Text Boundary Analysis
(Break Iteration) ubrk.h icu::BreakIterator Regular Expressions uregex.h icu::RegexPattern, icu::RegexMatcher StringPrep usprep.h C API International Domain Names in Applications:
UTS #46 in C/C++, IDNA2003 only via C API uidna.h idna.h Identifier Spoofing & Confusability uspoof.h C API Universal Time Scale utmscale.h C API Layout Engine/Complex Text Layout loengine.h icu::LayoutEngine,icu::ParagraphLayout ICU I/O ustdio.h ustream.h

But the C++ API is not exposed:

The version of ICU in Windows only exposes the C APIs. It does not expose any of the C++ APIs. Unfortunately, it is impossible to ever expose the C++ APIs due to the lack of a stable ABI in C++.

References

  • I could swear we both link to ICU dynamically & use its C++ API... is it header - only? – Bwmat Sep 20 '18 at 6:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.