Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

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

Licensed under: CC-BY-SA with attribution
scroll top