2

I have compiled a program on my own Ubuntu system. Now I want to run it on a foreign Ubuntu system with same architecture but slightly outdated shared libraries. How do I get the libraries from my own system work on the foreign one? I'm not root on the foreign machine.

So far I tried to copy the files listed by me@mymachine> ldd myprogram together with myprogram into the same directory on the foreign machine. Upon executing me@foreignmachine> ./myprogram there, I expected that the libraries in the same directory would be loaded instead of the outdated ones in the library path. However, I get the error messages

/usr/lib64/libgomp.so.1: version `GOMP_4.0' not found (required by ./myprogram)
/lib64/libc.so.6: version `GLIBC_2.14' not found (required by ./myprogram)

So obviously the libraries I copied have not been loaded, as they had the right version on my system (where I compiled the program).

Is there another working kludge? Static linking doesn't work either (as expected).


Edit: ldd myprogram yielded:

    linux-vdso.so.1 =>  (0x00007ffccabf4000)
    libgfortran.so.3 => /usr/lib/x86_64-linux-gnu/libgfortran.so.3 (0x00007f149b334000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f149b038000)
    libgomp.so.1 => /usr/lib/x86_64-linux-gnu/libgomp.so.1 (0x00007f149ae15000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f149abfe000)
    libquadmath.so.0 => /usr/lib/x86_64-linux-gnu/libquadmath.so.0 (0x00007f149a9bf000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f149a7a1000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f149a3e3000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f149b67d000)
    librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f149a1db000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f1499fd6000)

So I copied the 10 files /lib/x86_64-linux-gnu/libdl.so.2, /lib/x86_64-linux-gnu/librt.so.1, /lib64/ld-linux-x86-64.so.2 etc. to the foreign system. According to what I've found, it seems to be OK not to care about linux-vdso.so.1 as it's generated automatically inside the kernel.

3 Answers3

3

On Linux the dynamic linker does not by default look in current directory. If you indeed include all needed libraries in current directory, it should work:

LD_LIBRARY_PATH=. ./myprogram

If you do not provide all necessary libraries, it might complain or just crash (due to binary incompatibilities that the linker cannot detect only comparing library version numbers).

Reference: man ld.so

LD_LIBRARY_PATH A colon-separated list of directories in which to search for ELF libraries at execution-time. Similar to the PATH environment variable. Ignored in set-user-ID and set-group-ID programs.

  • I tried LD_LIBRARY_PATH="." ./myprogram and got the message memory fault. How do I inquire what's still missing? – Horst Grünbusch May 21 '15 at 14:22
  • If there's no problem (e.g. confidential content), can you pastebin or github gist the output of : export LD_LIBRARY_PATH="." ; strace ./myprogram ? There might be a hint. – Stéphane Gourichon May 21 '15 at 15:14
2

Thanks to this answer of Julien, I added to the linker the options -L. -Wl,-rpath='$ORIGIN'. The -L tells the linker to look for the shared libraries in the directory where you compile. The second option is more important in that now at runtime, the shared libraries in the original directory where the executable is, will be taken. So if I do now ldd /home/on/foreign/machine/myprogram on the foreign machine, I get e.g.

libgfortran.so.3 => /home/on/foreign/machine/libgfortran.so.3

But there is one library left whose entry does not change: /lib64/ld-linux-x86-64.so.2. This is an alias for ld.so @Stéphane pointed at. Now from what he taught me, I concluded to try with the ld-linux-x86-65.so.2-file from my own machine on the other one:

me@foreign:/home/on/foreign/machine> ./ld-linux-x86-64.so.2 ./myprogram

And it finally worked on the foreign machine. Note that I did not change LD_LIBRARY_PATH.

However, I think this works because only the kernel versions (not architecture) are different between both machines.

1

On Linux, there's a big effort for binary compatibility at kernel level, not so much at library level.

What I did several times and worked perfectly is to make on a development machine a chroot with the target machine environment, including compiler. (One can replace chroot with virtual machine or any type of container.)

The binaries you'll make from that kind of environment will always fit perfectly the target machine.

The pros/cons are:

  • chroot or container con: need some efforts (especially the first time) -- chroot is more traditional Unix. schroot might help to tune and use the chroot..
  • chroot or container pro: lightweight on resources (especially chroot)
  • chroot or container pro: somehow easier to make scripted (with schroot especially or a sudo configuration).
  • virtual machines pro: easier for beginners (e.g VirtualBox).
  • virtual machines con: somewhat heavyweight on disk usage and CPU
  • virtual machines con: generally needs graphical access (a user advanced enough to prefer shell access via SSH might be savvy enough to prefer a container or chroot).

In any case, chroot/container/VM can be kept and reused many times.