LWN.net Logo

Zeuthen: Writing a C library, part 2

Zeuthen: Writing a C library, part 2

Posted Jun 28, 2011 18:05 UTC (Tue) by jhhaller (subscriber, #56103)
Parent article: Zeuthen: Writing a C library, part 1

Maybe a comment for part 2, but getting APIs right is important. For a counter-example, look at the Service Availability Forum APIs. They use C structure pointers as parameters to functions. As the first version of the API was used, improvements were made. The standard doesn't come with an implementation, so there was no feedback to the API until people started to implement it. As they found that there were missing or new pieces which needed to be added to the structures, a backwards compatibility issue arose. To solve it, new structures were created with a number appended to the structure to version control the structure. That, of course, caused the function to take a different parameter type, so the function name got a number appended. This would allow an unchanged client to use the associate library, while an updated client could use the new functionality.

If APIs are likely to be extended in the future, the API needs to allow for that. This generally means that the callers will have unattractive code as they fill out the data to call the function in an extensible manner. There are a couple of ways to build extensible data. One is to use opaque objects with setters and getters. The other is to use tag/value lists, which is quite often the underlying mechanism for setters and getters. It's unattractive, but better than trying to remember if the disinter_3 function takes the Foo_2 or Foo_3 argument type.


(Log in to post comments)

Zeuthen: Writing a C library, part 2

Posted Jun 28, 2011 20:04 UTC (Tue) by cmccabe (guest, #60281) [Link]

It really seems like what they should have done was just install multiple versions of the library. Then if you want to link against one specific version, you can just specify that on the link line. Then say goodbye to unattractive code and wacky hacks.

Zeuthen: Writing a C library, part 2

Posted Jun 28, 2011 21:10 UTC (Tue) by elanthis (guest, #6227) [Link]

That still requires renaming all your functions and other public symbols at the very least. Otherwise you end up having a dependency on libfoo which needs version 1 of the library and a dependency on libbar which needs version 2 of the library and you're screwed.

Zeuthen: Writing a C library, part 2

Posted Jun 28, 2011 22:14 UTC (Tue) by cmccabe (guest, #60281) [Link]

I guess I see your point.

I was about to write something here about symbol versioning being the solution to this problem, but... the more I read about it, the less helpful it seems.

Zeuthen: Writing a C library, part 2

Posted Jun 29, 2011 13:43 UTC (Wed) by michaeljt (subscriber, #39183) [Link]

> I was about to write something here about symbol versioning being the solution to this problem, but... the more I read about it, the less helpful it seems.

Does that include the simple form of versioning, as in prefixing every public symbol with a prefix like "mylib1_" or "mylib2_" for version 2? In that system new symbols can be added to a given version, but breaking the API/ABI contract on any given symbol is a bug which should be fixed with a minor release.

Zeuthen: Writing a C library, part 2

Posted Jun 29, 2011 16:31 UTC (Wed) by cmccabe (guest, #60281) [Link]

Manually versioning symbols is portable and should work fine. I was commenting that gcc's built-in symbol versioning seems complex and might not be the best solution.

Zeuthen: Writing a C library, part 2

Posted Jun 29, 2011 21:10 UTC (Wed) by hmh (subscriber, #3838) [Link]

Hmm, actually there is a rather simple rule: if your library could ever be used by something other than an application (i.e. by another library, by plugins, or worse, by glibc plugins or libraries that a libc plugin might use), version the symbols.

You don't need to go to the lengths that glibc does (which is to actually keep compatibility to earlier ABIs by providing differently versioned versions of the same symbol :p). What you have to do is really track ABI changes properly, change your SONAME every time the ABI changes in an incompatible way, and version every linker-visible symbol with the library name and soname. You could do better than that (like glibc does), but it is not strictly necessary in most cases.

The reason is the usual app A uses lib B and lib C, and lib B also uses lib C. App A was built against lib C ABI 1, lib B ABI 2. lib C got upgraded to abi 2, lib B got rebuilt against it, and now App A needs both lib C abi 1 and lib C abi 2 to be able to run -- instant meltdown.

This happens all the time, and it makes life HELL for distros. An extremely good example of a library that breaks the world rather easily when its symbols are not versioned is libdb.

And you will want to use the linker symbol versioning instead of static versioning, otherwise, you'd break the API all the time. BTW, it is not a gcc thing, it is an ELF thing, and Solaris has been doing it since forever.

I just wish it was easier to do symbol versioning.

Zeuthen: Writing a C library, part 2

Posted Jul 3, 2011 6:30 UTC (Sun) by cmccabe (guest, #60281) [Link]

> And you will want to use the linker symbol versioning instead of static
> versioning, otherwise, you'd break the API all the time. BTW, it is not a
> gcc thing, it is an ELF thing, and Solaris has been doing it since forever.

from http://www.airs.com/blog/archives/220

> Ulrich Drepper and Eric Youngdale introduced a much more sophisticated
> symbol versioning scheme, which is used by the glibc, the GNU linker, and
> gold. The key differences are that versions may be specified in object
> files and that shared libraries may contain multiple independent versions
> of the same symbol

In other words, this is a gcc-specific ELF extension. I wonder if LLVM supports it yet? I found a page from 2008 that said that LLVM didn't have support for this yet, but then I got tired of using the Google.

Zeuthen: Writing a C library, part 2

Posted Jul 3, 2011 9:39 UTC (Sun) by nix (subscriber, #2304) [Link]

Yes, its a Linuxism (and very much more useful than Solaris symbol versions), but a lot of the syntax of the file, and the underlying idea, was a Solarisism first.

Zeuthen: Writing a C library, part 2

Posted Jul 3, 2011 17:07 UTC (Sun) by paulj (subscriber, #341) [Link]

Symbol map files are supported by several proprietary Unix toolchains, including Suns' and (iirc) HPs'. The syntax is nearly identical twixt Solaris and GNU (there's certainly a useful common subset iirc). The ELF symbol stuff is at least very very similar in concept. It might even be standardised, and/or tools may know the differing formats. Binary compatibility across different OSes tends not to be the most important of issues though..

Zeuthen: Writing a C library, part 2

Posted Jul 6, 2011 15:54 UTC (Wed) by jwakely (subscriber, #60262) [Link]

> In other words, this is a gcc-specific ELF extension.

It's not gcc-specific, it's done by GNU binutils not gcc

http://sourceware.org/binutils/docs-2.21/as/Symver.html
http://sourceware.org/binutils/docs-2.21/ld/VERSION.html

libpng

Posted Jun 29, 2011 14:47 UTC (Wed) by tialaramex (subscriber, #21167) [Link]

This type of thing is what went wrong in libpng. Their worst sin was /inserting/ new structure members into an existing structure definition which was part of their public ABI. But there were many others, including changing the declaration of ABI functions depending on your build flags.

For a while its authors tried being indignant, insisting that you should only use a libpng program with the precise build of the precise version of the library against which it was compiled.

Eventually we managed to explain to them how ABI compatibility works, and the modern libpng takes roughly the getter/setter approach with the caller having only an opaque handle to the internal structures.

Copyright © 2013, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds