Dealing with missing functions

While I’m still expanding Autotools Mythbuster and tying up some loose ends before going on vacation I’ve been thinking of one particular problem that has hit me in feng and that is: how do you deal with missing functions in various operating systems?

Let me explain; one of the tricks I always stress with autoconf is to reduce the number of tests since that not only reduces the complexity of the configure.ac file for the developer, but also reduces the time wasted by the ./configure run.

To do this, I usually assume the systems I’m building on are standard; this is something that I derived from FFmpeg, that in general assumes that it’s building with a standard-compliant C99 compiler on a POSIX system; this works fine with all the modern Linux systems (especially since POSIX became GLIBC in the latest incarnation), and most other operating systems, once you exclude Microsoft and, partially, OS X (I don’t know about Snow Leopard yet, since I’m not subscribed as a developer). The problem is that often you have to support older operating systems, or systems that are not standard; or on the other hand, you might want to use extensions that are not available on all the operating systems, but are on most.

For these cases, usually you make use of autoconf checks, and then write your own replacement function; this unfortunately leads to nasty side-effect when they are added and at the same time they require duplication of a huge amount of code. Nowadays, on Linux, this can easily be noted in the strlcpy() and strlcat() functions, since they are born on OpenBSD, ported to most *BSD systems, but not (yet) available on the GNU C library: from my latest collision report, I count 66 and 47 copies of those exported (including by KDE libraries, libmagic and others).

To find alternative implementations, you can also look at the gnulib project by GNU itself, that allows to add the proper replacement functions for most of them to your project; I even wrote about that and I do sustain the project, but while it reduces the amount of duplicated source code, it doesn’t help to reduce the redundancy of compiled copies of the same functions over and over.

What we need is a single library where all the replacement functions can be compiled in, and then it can be linked against binaries and other libraries needing functions that are not available on the system. Thanks to options like --as-needed and autoconf auto-discovery of which library holds a given function (the AC_SEARCH_LIBS macro), this shouldn’t really be an excessive problem. The problem here is that you have a non-trivial amount of work for such a library: you need to be compatible with the current interfaces, you might want to have the functions optimised, you might have to deal with license issues.

Ideally, such a library should be released either under BSD license or LGPL, so that it could be used (but not embedded) on a the vastest possible range of software projects. Picking up some functions from gnulib, and others from the BSD C libraries might be a start. Unfortunately some of the functions in gnulib are only GPL-licensed, not LGPL, so we still cannot go with just reusing that code.

But seriously, this is something you got to consider on the long run: supporting older systems where functions are unavailable tend to get more difficult by the year, since more interfaces are added; and unless you get all your interfaces from convenience libraries such as glib, you end up either with a lot of replacement functions, or simply supporting a smaller subset of systems that you might, “if just” you had a way to make use of some extra functions on them.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s