1

I have a collection of binaries I installed on a Linux machine. They require the libgfortran library, but on execution display the following message:

error while loading shared libraries: libgfortran.so.2: cannot open shared object file: No such file or directory

The machine already had libgfortran installed, but the name of the library file was libgfortran.so.1.0.0 (and libgfortran.so.1 linked to it).

To my surprise, by simply making a symbolic link libgfortran.so.2 to libgfortran.so.1, as follows:

ln -s /usr/lib64/libgfortran.so.1 /usr/lib64/libgfortran.so.2

this solved my problem and the binaries were able to run, apparently without error.

My question is - why did they even run at all?

Is there not an inbuilt mechanism to detect when the API version is different, or is it only based on the filename?

If there is API detection - then should there not have been a symbol error?

Indeed, what is the purpose of having different major versions between libraries if they are in fact compatible?

(Note to answerers: my question is not about libgfortran in particular, this is just an illustrative example.)

Ajjajj
  • 67
  • 5

2 Answers2

3

why did it run at all?

It ran because all the dependent symbols were found in the .so that it loaded

is there an inbuilt mechanism to detect API version differences?

There is symbol versioning support available, but you have to program to it. It totally depends on if the developer makes use of it.

If there is API detection ...?

Again, there is symbol versioning available, which is not quite the same.

What's the purpose of having different major versions if it's still compatible

It's up to the developer.

Note however that it may be that only the elements of the API you made use of were compatible between the two versions. There is every possibility that the code is silently corrupting your data in the background and you won't become aware of it until later down the line.

Anya Shenanigans
  • 91,618
  • 3
  • 107
  • 122
  • Thanks for your answer. I'd assumed some form of symbol or library versioning was inherent in all shared libraries - didn't realise it is actually just based on the aggregate matching of symbols! – Ajjajj May 29 '14 at 14:28
2

Minor versions are normally incremented for releases that are ABI compatible with the previous versions. I.e. an application can and will use a new minor version shared library when the latter is updated.

Major versions are normally incremented for releases that are not ABI compatible with the previous major versions.

Normally, you have three filesystem names for one shared library, e.g.:

lrwxrwxrwx 1 max max       13 May 13 11:13 libfix.so -> libfix.so.0.0
lrwxrwxrwx 1 max max       13 May 13 11:13 libfix.so.0 -> libfix.so.0.0
-rwxrwxr-x 1 max max  1665544 May 13 11:13 libfix.so.0.0

The unversioned libfix.so is just a symlink to the fully versioned one. It is used when you link your application with -lfix using ld linker.

libfix.so.0.0 is the actual shared library. However, this library is linked with -hlibfix.so.0 linker option:

   -h name
   -soname=name
       When creating an ELF shared object, set the internal DT_SONAME
       field to the specified name.  When an executable is linked with a
       shared object which has a DT_SONAME field, then when the executable
       is run the dynamic linker will attempt to load the shared object
       specified by the DT_SONAME field rather than the using the file
       name given to the linker.

So, what happens when the application starts is that runtime linker ld.so actually looks for libfix.so.0, which is a symbolic link to the latest version of the shared library with the same major number. When libfix.so.0.0 is updated to, say, libfix.so.0.1 those symbolic links are updated to point to that new version. Existing and new applications start to use that new version of the shared library next time you start or link them.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • Thank you for the information. I guess this implies that linking the correct library version level (e.g. the choice between fix.so, fix.so.0 or fix.so.0.0) is the responsibility of the program developer, rather than the library developer? – Ajjajj May 29 '14 at 14:32
  • @Ajjajj Developers normally just use `-lfix`, implying they want the latest version most of the time. To link against the older version people normally add something like `libfix-compat.so` symlink to point to the old major version and link against it with `-lfix-compat`. – Maxim Egorushkin May 29 '14 at 14:37