Compile a program using another version of a system library with libtool

Anjuta needs now GTK+ 2.18.0 (in fact 2.17.10) while I haven’t updated my system and still have GTK+ 2.16.1. The obvious solution is to download GTK+ 2.18.0, compile and install it in /usr/local as other libraries but it’s not so easy.

GTK+ depends on other libraries GLib, Pango and ATK. At least my version of GLib was too old, so I have download, compiled and installed all these 3 libraries. This step is not really a problem if you have taken care to set the environment variable PKG_CONFIG_PATH=/usr/local/lib/pkgconfig. The configure script will look for a library first in usr/local/lib before checking standard location (/usr/lib).

The troubles come when compiling Anjuta. Anjuta depends on GTK+ and get the new GTK+ version in /usr/local/lib. But it has several others dependencies (by example GConf, Orbit, vte, unique) which depend themselves on GTK+ and they use the old version of GTK+. In the link command, I can see both versions of GTK+. I suppose that the linker keeps only the first one, in this case it is the old one and I get some undefined symbols.

One first easy but lengthy solution, is to download these dependencies (GConf, Orbit, vte…), compile and install them. The problem is that these libraries probably have a few other dependencies so I will have to download and compile quite a lots of packages.

There is a second solution. As GTK+ keeps a backward binary compatibility, there is no need to recompile vte with a newer version of GTK+. Even if it has been compiled with GTK+ 2.16.0, it should work fine with GTK+ 2.18.0. If I can tell these libraries to use the new version everything should work.

How the linker is looking for libraries ? There are several ways to tune this search. One easy way for my case is to define another environment variable LD_LIBRARY_PATH=/usr/local/lib. With this, all programs looking for a dynamic library will look in /usr/local/lib before checking standard paths. This is used at link time and at run time. So all programs will now use the new version of GTK+. But when I’m trying to compile Anjuta, I still get both versions of GTK+.

Why ? The problems comes from libtool. It is a program part of the autotools stuff, which is taking care of building libraries the goal is to make it easier to build shared libraries on all possible platforms. On Linux, the dynamic linker is quite capable so it doesn’t need more information than the library name. On other platform it needs more informations like the list of all dependencies of the library, so even on Linux libtool is replacing each library with a small text file containing these information. It is the .la file. Indeed we can open it in a text editor and see all dependencies using absolute pathes. So by example libOrbit-2 depends on /usr/lib/libglib-2.0.la.

So, to solve my problem I have done the following:

  • Copy  /usr/lib/libvte.la  /usr/lib/libORBit-2.la  /usr/lib/libgconf-2.la  /usr/lib/libunique-1.0.la to /usr/local/lib
  • Edit all these files to change the path of  GLib, GTK+, Pango and ATK to /usr/local/lib

When it is done, libtool will find these .la file before the one in /usr/lib and so add the correct dependencies. It will still use the libraries in /usr/lib as the path of the library is included inside the .la file. (libdir). You will a warning at link time:

libtool: link: warning: `/usr/local/lib/libgconf-2.la’ seems to be moved.

Then, when you compile a library, libtool will create a .la file for this library and it will be put normally in /usr/local/lib. But the absolute pathes of the dependencies in the .la file seems to depend on the path of the .pc file (used by pkg-config). So It is useful to copy the .pc file in /usr/local/lib/pkgconfig too.

Used GIT commands

Generate pathes from git repository
git format-patch origin/master

Get a the remote branch gnome-2-28
git checkout --track origin/gnome-2-28

Commit on a branch the last commit done on master
git cherry-pick master

Remove changes in the index, do not change local file
git reset

Remove changes in local file to match index
git reset --hard
Warning, uncommitted changes are not in any branch. So removing them with the previous command will remove them in all branch.

Change dynamic library search path for an executable

Each executable contains a list of pathes for loading dynamic library. You can get this list using:
readelf -d executable_name
or
chrpath -l executable_name

And it is possible to change this path using:
chrpath -r new_path_separated_by_double_colon executable_name

There are more detailled explanation here: http://www.eyrie.org/~eagle/notes/rpath.html

Read a gconf value and return a default value if missing

A function like gconf_client_get_bool returns FALSE if the value is set to FALSE or if the value is missing. Moreover, the err argument is not set, if the value is missing.

One way to return another default value if the key is missing is to use the function gconf_client_get that will return NULL in this case.

A function to get a boolean value can be written like:

static gboolean
get_bool_default (GConfClient *client, const gchar *key, gboolean def)
{
    gboolean value = def;
    GConfValue* val;

    val = gconf_client_get (client, key, NULL);
    if (val != NULL)
    {
        value = gconf_value_get_bool (val);
        gconf_value_free (val);
    }

    return value;
}

I haven’t found a way to remove a not user defined gconf key, so to check this code, my current solution is just to read another key.