# Linking against non versioned or major library

**URL:** https://discourse.cmake.org/t/linking-against-non-versioned-or-major-library/3931
**Category:** Usage
**Tags:** lang:c, comp:gcc, os:linux
**Created:** [August 13, 2021, 10:43am UTC](https://discourse.cmake.org/t/linking-against-non-versioned-or-major-library/3931 "2021-08-13T10:43:18Z")
**Posts on this page:** 12
**Page:** 1

<div class="post-metadata">

### Author: ![emiliogq](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/e/a9a28c/32.png) [@emiliogq](https://discourse.cmake.org/u/emiliogq)
#### Post date: [August 13, 2021, 10:43am UTC](https://discourse.cmake.org/t/linking-against-non-versioned-or-major-library/3931/1 "2021-08-13T10:43:19Z")

</div>

Hello,

I am trying to compile a cpp code which has some external library calls (libnova) among others.

That lib is found using the find\_library call:

```auto
 find_library(NOVA_LIBRARIES NAMES nova
    PATHS ${NOVA_ROOT} ENV INSTALL_LOCATION 
    PATH_SUFFIXES lib lib64
    ${_obLinkDir}
    ${GNUWIN32_DIR}/lib
  )

```

The NOVA\_LIBRARIES cmake var outputs `NOVA_LIBRARIES /usr/lib/x86_64-linux-gnu/libnova.so`  
When the library is linked the makefile output is (object file list removed):

```auto
[100%] Linking CXX shared library libfoo.so
cd /tst/build/src/time && /usr/bin/cmake -E cmake_link_script CMakeFiles/TIME.dir/link.txt --verbose=1
/usr/bin/c++ -fPIC -fopenmp -O3 -DNDEBUG -g -Wall -Wextra -Werror -ggdb -fpermissive -gdwarf-3
-fprofile-arcs -ftest-coverage -fprofile-arcs 
-shared -Wl,-soname,libfoo.so -o libfoo.so object_files.o 
-Wl,-rpath,::::::::::::::::::::::::: /usr/lib/x86_64-linux-gnu/libnova.so 

```

As you can see the libnova lib is a non versioned linked lib, tut if I objdump the generated lib I actually get:

```auto
  NEEDED libnova-0.16.so.0
  NEEDED libstdc++.so.6
  NEEDED libm.so.6
  NEEDED libgomp.so.1
  NEEDED libgcc_s.so.1
  NEEDED libpthread.so.0
  NEEDED libc.so.6

```

And If I ldd the lib:

```auto
root@46bdf6475137:/tst/build/src/time# ldd libfoo.so 
        linux-vdso.so.1 (0x00007ffe4ddad000)
        libnova-0.16.so.0 => /usr/lib/x86_64-linux-gnu/libnova-0.16.so.0
        libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f2762523000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f27623a0000)
        libgomp.so.1 => /usr/lib/x86_64-linux-gnu/libgomp.so.1 (0x00007f276236f000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f2762355000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f2762332000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2762171000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f27626d4000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f276216c000)

```

There are some symlinks but are not used at all:

```auto
lrwxrwxrwx 1 root root 21 Jan 23 2019 /usr/lib/x86_64-linux-gnu/libnova-0.16.so.0 -> libnova-0.16.so.0.0.0
-rw-r--r-- 1 root root 3669184 Jan 23 2019 /usr/lib/x86_64-linux-gnu/libnova-0.16.so.0.0.0
-rw-r--r-- 1 root root 3811162 Jan 23 2019 /usr/lib/x86_64-linux-gnu/libnova.a
lrwxrwxrwx 1 root root 21 Jan 23 2019 /usr/lib/x86_64-linux-gnu/libnova.so -> libnova-0.16.so.0.0.0

```

Also, I tried to remove the symlink “libnova-0.16.so.0” to see if now the linker takes the non-versioned or at least, the major versioned symlink:

```auto
-rw-r--r-- 1 root root 3811162 Jan 23 2019 /usr/lib/x86_64-linux-gnu/libnova.a
lrwxrwxrwx 1 root root 17 Aug 13 10:35 /usr/lib/x86_64-linux-gnu/libnova.so -> libnova.so.0.16.0
lrwxrwxrwx 1 root root 17 Aug 13 10:23 /usr/lib/x86_64-linux-gnu/libnova.so.0 -> libnova.so.0.16.0
-rw-r--r-- 1 root root 3669184 Jan 23 2019 /usr/lib/x86_64-linux-gnu/libnova.so.0.16.0

```

But it still points to an unexisting lib (since I removed it):

```auto
  NEEDED libnova-0.16.so.0
  NEEDED libstdc++.so.6
  NEEDED libm.so.6
  NEEDED libgomp.so.1
  NEEDED libgcc_s.so.1
  NEEDED libpthread.so.0
  NEEDED libc.so.6

```

How can I get the non versioned lib as the linked lib?

Thanks in advance

---

<div class="post-metadata">

### Author: ![fenrir](https://discourse.cmake.org/user_avatar/discourse.cmake.org/fenrir/32/734_2.png) [@fenrir](https://discourse.cmake.org/u/fenrir)
#### Post date: [August 13, 2021, 10:54am UTC](https://discourse.cmake.org/t/linking-against-non-versioned-or-major-library/3931/2 "2021-08-13T10:54:51Z")

</div>

The version that will be written to the NEEDED section depends on the SONAME of the linked library. That means the linker reads it from the file your `/usr/lib/x86_64-linux-gnu/libnova.so` ultimately points to. This has nothing to do with CMake, it’s how the linking works.

So you’d have to build libnova with appropriate SONAME. I do not recommend this however as it’ll break stuff sooner or later when whoever installs your software would have an incompatible version of libnova on their system.

---

<div class="post-metadata">

### Author: ![emiliogq](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/e/a9a28c/32.png) [@emiliogq](https://discourse.cmake.org/u/emiliogq)
#### Post date: [August 13, 2021, 11:18am UTC](https://discourse.cmake.org/t/linking-against-non-versioned-or-major-library/3931/3 "2021-08-13T11:18:09Z")

</div>

Thanks Jakub for replying.

But I already notice what you meant and for that reason I tried to remove the symlink libnova-0.16.so.0 and change the libnova.so symlink to point to a proper SONAME version but it stills pointing to the previous one, even I removed the build directory where the cmake files are created and tried to recreate the build system again by calling cmake. In detail I did:

```nohighlight
root@18be343e093c:/usr/lib/x86_64-linux-gnu# ls -l libnova*      
lrwxrwxrwx 1 root root 21 Jan 23 2019 libnova-0.16.so.0 -> libnova-0.16.so.0.0.0
-rw-r--r-- 1 root root 3669184 Jan 23 2019 libnova-0.16.so.0.0.0
-rw-r--r-- 1 root root 3811162 Jan 23 2019 libnova.a
lrwxrwxrwx 1 root root 21 Jan 23 2019 libnova.so -> libnova-0.16.so.0.0.0

root@18be343e093c:/usr/lib/x86_64-linux-gnu# rm libnova-0.16.so.0

root@18be343e093c:/usr/lib/x86_64-linux-gnu# mv libnova-0.16.so.0.0.0 libnova.so.0.16.0

root@18be343e093c:/usr/lib/x86_64-linux-gnu# rm libnova.so 

root@18be343e093c:/usr/lib/x86_64-linux-gnu# ln -s libnova.so.0.16.0 libnova.so        

root@18be343e093c:/usr/lib/x86_64-linux-gnu# ln -s libnova.so.0.16.0 libnova.so.0

root@18be343e093c:/usr/lib/x86_64-linux-gnu# ls -l libnova*
-rw-r--r-- 1 root root 3811162 Jan 23 2019 libnova.a
lrwxrwxrwx 1 root root 17 Aug 13 11:40 libnova.so -> libnova.so.0.16.0
lrwxrwxrwx 1 root root 17 Aug 13 11:40 libnova.so.0 -> libnova.so.0.16.0
-rw-r--r-- 1 root root 3669184 Jan 23 2019 libnova.so.0.16.0

```

After 6 minutes I realized the system created again the removed symlink:

```nohighlight
lrwxrwxrwx 1 root root 17 Aug 13 11:46 /usr/lib/x86_64-linux-gnu/libnova-0.16.so.0 -> libnova.so.0.16.0
-rw-r--r-- 1 root root 3811162 Jan 23 2019 /usr/lib/x86_64-linux-gnu/libnova.a
lrwxrwxrwx 1 root root 17 Aug 13 11:40 /usr/lib/x86_64-linux-gnu/libnova.so -> libnova.so.0.16.0
lrwxrwxrwx 1 root root 17 Aug 13 11:40 /usr/lib/x86_64-linux-gnu/libnova.so.0 -> libnova.so.0.16.0
-rw-r--r-- 1 root root 3669184 Jan 23 2019 /usr/lib/x86_64-linux-gnu/libnova.so.0.16.0

```

I agree this linking issue is something that probably CMake has nothing to do, but I wondered if there is some CMake option to tell the linker the correct lib filename.

Thanks in advance,

---

<div class="post-metadata">

### Author: ![fenrir](https://discourse.cmake.org/user_avatar/discourse.cmake.org/fenrir/32/734_2.png) [@fenrir](https://discourse.cmake.org/u/fenrir)
#### Post date: [August 13, 2021, 11:48am UTC](https://discourse.cmake.org/t/linking-against-non-versioned-or-major-library/3931/4 "2021-08-13T11:48:00Z")

</div>

Does `objdump -p /usr/lib/x86_64-linux-gnu/libnova.so | grep SONAME` confirm that?

---

<div class="post-metadata">

### Author: ![emiliogq](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/e/a9a28c/32.png) [@emiliogq](https://discourse.cmake.org/u/emiliogq)
#### Post date: [August 13, 2021, 11:52am UTC](https://discourse.cmake.org/t/linking-against-non-versioned-or-major-library/3931/5 "2021-08-13T11:52:28Z")

</div>

Thank you very much,

Now I can see what you meant, sorry for the misunderstanding:

```auto
root@18be343e093c:/tst/build# objdump -p /usr/lib/x86_64-linux-gnu/libnova.so | grep SONAME
  SONAME libnova-0.16.so.0

```

So, the linker takes this name to look for the library.

Very pleased!

---

<div class="post-metadata">

### Author: ![emiliogq](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/e/a9a28c/32.png) [@emiliogq](https://discourse.cmake.org/u/emiliogq)
#### Post date: [August 13, 2021, 2:32pm UTC](https://discourse.cmake.org/t/linking-against-non-versioned-or-major-library/3931/6 "2021-08-13T14:32:59Z")

</div>

Regarding this, I checked out the thirty party libraries that our library use (libnova and boost) and both points the SONAME to the MAJOR.MINOR.PATCH version.

This makes cross compiling (compile in Debian, execute in Centos for instance) more difficult. Is there a way to achieve this?

Thanks in advance!

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [August 13, 2021, 2:41pm UTC](https://discourse.cmake.org/t/linking-against-non-versioned-or-major-library/3931/7 "2021-08-13T14:41:37Z")

</div>

> [@emiliogq](#):
>
> This makes cross compiling (compile in Debian, execute in Centos for instance) more difficult. Is there a way to achieve this?

This is always a problem. You cannot compile against libfoo’s version `x.y` and expect to work when run against `x.z` in general. Some projects make ABI guarantees if `z > y`, but these are rare (glibc, libX11, libstdc++, glib, Qt; certainly _not_ Boost). You’ll need to either compile against the lowest common denominator or ship the libraries you built against.

---

<div class="post-metadata">

### Author: ![emiliogq](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/e/a9a28c/32.png) [@emiliogq](https://discourse.cmake.org/u/emiliogq)
#### Post date: [August 13, 2021, 2:52pm UTC](https://discourse.cmake.org/t/linking-against-non-versioned-or-major-library/3931/8 "2021-08-13T14:52:00Z")

</div>

Exactly this is what we think about, for instance If

- Centos system has Boost 1.66
- Debian system has Boost 1.69

We could compile our library in Centos and execute on Debian. This assumes that there is the same major version in both OS.

However, due to the fact that the SONAME points to the the exact version:

```nohighlight
libboost_atomic.so
  SONAME libboost_atomic.so.1.67.0
libboost_chrono.so
  SONAME libboost_chrono.so.1.67.0
libboost_container.so
  SONAME libboost_container.so.1.67.0
libboost_context.so
  SONAME libboost_context.so.1.67.0
libboost_coroutine.so
  SONAME libboost_coroutine.so.1.67.0
libboost_date_time.so
  SONAME libboost_date_time.so.1.67.0
libboost_fiber.so

```

Even upgrading those libraries within the same OS would require recompile our library since the linker would not be able to find the previous one, would be it?

Thank you all for this amazing support!

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [August 13, 2021, 2:58pm UTC](https://discourse.cmake.org/t/linking-against-non-versioned-or-major-library/3931/9 "2021-08-13T14:58:07Z")

</div>

> [@emiliogq](#):
>
> Even upgrading those libraries within the same OS would require recompile our library since the linker would not be able to find the previous one, would be it?

I wouldn’t trust two Boost builds by different vendors even for the same version. Boost, specifically, is too sensitive to compilers and their version differences. All kinds of compiler flags can affect the ABI making things _silently_ incompatible. The only solution that is reliable (on Linux) is to:

- build against the oldest version that you support and/or need for libraries with ABI compatibility offered; and
- ship copies of everything else.

---

<div class="post-metadata">

### Author: ![fenrir](https://discourse.cmake.org/user_avatar/discourse.cmake.org/fenrir/32/734_2.png) [@fenrir](https://discourse.cmake.org/u/fenrir)
#### Post date: [August 13, 2021, 3:02pm UTC](https://discourse.cmake.org/t/linking-against-non-versioned-or-major-library/3931/10 "2021-08-13T15:02:29Z")

</div>

Just to make sure you understand - the problem is not the SONAME per se but the compatibility guarantees the library authors provide. The SONAME only reflects that so don’t try to get around that by some tricks. Basically your options are:

- only provide source code so users have to build it themselves… ☹
- vendor the libraries
- manage separate builds for different Distros… ☹

---

<div class="post-metadata">

### Author: ![emiliogq](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/e/a9a28c/32.png) [@emiliogq](https://discourse.cmake.org/u/emiliogq)
#### Post date: [August 13, 2021, 3:10pm UTC](https://discourse.cmake.org/t/linking-against-non-versioned-or-major-library/3931/11 "2021-08-13T15:10:57Z")

</div>

Hahaha, yeah I understand, it seems most library dev teams do not like/follow semantic versioning 😛

Actually what we do right now is to have several pipelines (one for distro) but this is a bit unmanageable and we would like to minimize the number of jobs that we have.

Vendoring libraries, as far I understand, it would be pretty much the same as using static libraries of those dependencies, since they are placed into the library or binary that you want to build.

---

<div class="post-metadata">

### Author: ![fenrir](https://discourse.cmake.org/user_avatar/discourse.cmake.org/fenrir/32/734_2.png) [@fenrir](https://discourse.cmake.org/u/fenrir)
#### Post date: [August 13, 2021, 3:21pm UTC](https://discourse.cmake.org/t/linking-against-non-versioned-or-major-library/3931/12 "2021-08-13T15:21:30Z")

</div>

vendoring - The same what @ben.boeckel means with “ship copies of everything else”.

At work I develop few project. Depending on few factors we do two things:

- static builds - useful for tools that are not really expected to be “installed” in any way
- build all used libraries with the product and ship them together. This requires either setting LD\_LIBRARY\_PATH before running, or getting the RPATH right for all the libs and executables you build.

Both approaches have down- and upsides but with combination of both we can build on oldest supported CentOS and it “just works” everywhere.
