Build executable on Linux that does not depend on any shared libraries - linux

Environment: Ubuntu 14.04. gcc 4.8.2
I am working on a C++ console application. When I run "ldd" on the executable, I see the following:
linux-vdso.so.1 => (0x00007fffe495e000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f9ffa754000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9ffa38e000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9ffa087000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9ffaa6e000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f9ff9e71000
I am wondering if it is possible to define flags on gcc/linker such that the final executable does not depend on any shared libraries.

Simply add -static while linking :-)
Static linking should be avoided not only for security reasons.
BTW: As I know there is no way to create a static lib from a dynamic one. So if you have only the shared lib, you can't link static.

Related

locate finds library but ldconfig does not

I am using using Centos 6.6 and there is a shared library the build generates used by number of executable and any executable using this shared library cannot find it as seen by ldd.
I can locate the library:
$ locate libcs.so.1
/opt/cloudshield/lib/libcs.so.1
ldd shows the following:
$ sudo ldd /opt/cloudshield/lib/libcs.so.1
ldd: warning: you do not have execution permission for `/opt/cloudshield/lib/libcs.so.1'
linux-vdso.so.1 => (0x00007ffff4fff000)
libc.so.6 => /lib64/libc.so.6 (0x00007f7a0fd56000)
/lib64/ld-linux-x86-64.so.2 (0x000000340ba00000)
$ sudo ldconfig -v | grep libcs.so.1
Is it because of the kernel library linux-vdso.so.1?
Executable cannot find the library libcs.so.1:
[fpeter#localhost radius]$ ldd radius
`linux-vdso.so.1 => (0x00007fff634b4000)
libconfd.so => /home/fpeter/trunk/thirdparty/tailf/confd/lib/libconfd.so (0x00007f5db20e6000)
libcs.so.1 => not found
libpthread.so.0 => /lib64/libpthread.so.0 (0x000000340c600000)
libc.so.6 => /lib64/libc.so.6 (0x000000340c200000)
libm.so.6 => /lib64/libm.so.6 (0x000000340ce00000)
libcrypto.so.1.0.0 => /usr/lib64/libcrypto.so.1.0.0 (0x0000003ba4a00000)
/lib64/ld-linux-x86-64.so.2 (0x000000340ba00000)
libdl.so.2 => /lib64/libdl.so.2 (0x000000340be00000)
libz.so.1 => /lib64/libz.so.1 (0x000000340d600000)
Add /opt/cloudshield/lib/ to your LD_LIBRARY_PATH environment variable, e.g.:
LD_LIBRARY_PATH=/opt/cloudshield/lib
export LD_LIBRARY_PATH
See also How to build library ithoutsudo or
shared libraries.

Libtool: Maintain library dependencies in header files

I am using Libtool and the other GNU Autotools (Autoconf, Automake, etc.) to build a shared library. My library has a dependency on another library (hwloc). I allow the user to specify a custom path for hwloc at configuration (the following is in configure.ac):
# Check for hwloc
AC_ARG_WITH([hwloc], [AS_HELP_STRING([--with-hwloc[[=DIR]]], [Location of the hwloc library])])
AS_IF([test "x$with_hwloc" != x],
[CPPFLAGS="-I$with_hwloc/include $CPPFLAGS"
LDFLAGS="-L$with_hwloc/lib $LDFLAGS"])
AC_CHECK_HEADERS([hwloc.h], [], [AC_MSG_ERROR([hwloc is a required library])])
AC_SEARCH_LIBS([hwloc_topology_init], [hwloc], [], [AC_MSG_ERROR([hwloc is a required library])])
After doing the build process (./configure --with-hwloc=...; make; make install), my shared library file successfully links with hwloc (ldd libmylib.so):
linux-vdso.so.1 => (0x00007ffff331c000)
librt.so.1 => /lib64/librt.so.1 (0x00007fa225c63000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fa225a46000)
libhwloc.so.5 => /home/brooks8/bin/hwloc-1.8.1/lib/libhwloc.so.5 (0x00007fa225816000)
libm.so.6 => /lib64/libm.so.6 (0x00007fa225591000)
libxml2.so.2 => /usr/lib64/libxml2.so.2 (0x00007fa22523f000)
libc.so.6 => /lib64/libc.so.6 (0x00007fa224eab000)
/lib64/ld-linux-x86-64.so.2 (0x0000003532000000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007fa224ca6000)
libz.so.1 => /lib64/libz.so.1 (0x00007fa224a90000)
However, one of my header files includes hwloc. This causes problems when I try and test my library and hwloc is in a non-standard location:
mpicc test.c -I/home/brooks8/bin/mylib/include -L/home/brooks8/bin/mylib/lib -lmylib -o test/test -std=c99 -O3 -g3:
/home/brooks8/bin/mylib/include/include/util.h:14:21: fatal error: hwloc.h: No such file or directory
#include <hwloc.h>
^
Is there a way to solve this issue without needing to link hwloc when I use my library?
Thank you in advance, and please let me know if I should provide any more information regarding my situation.

libraries which exist in a binary's elf RUNPATH are not being used?

I have custom built gcc-4.7.2 in my environment. The system gcc is gcc-4.3.4.
I have patched the RUNPATH for all my custom gcc's binaries and shared libraries using patchelf --set-rpath
However, when I run ldd on my 4.7.2 cc1 it picks up the system libstdc++ instead of the one pointed to by the RUNPATH:
$ ldd /sdk/x86_64/2.11.1/gcc-4.7.2/libexec/gcc/x86_64-suse-linux/4.7.2/cc1
libcloog-isl.so.1 => /sdk/x86_64/2.11.1/gcc-4.7.2/lib/libcloog-isl.so.1 (0x00007f072dce8000)
...
libc.so.6 => /lib64/libc.so.6 (0x00007f072bfe0000)
--> libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007f072bcd5000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f072babe000)
/lib64/ld-linux-x86-64.so.2 (0x00007f072df0d000)
As can be seen the RUNPATH specifies the gcc-4.7.2 library locations:
$ readelf -a /sdk/x86_64/2.11.1/gcc-4.7.2/libexec/gcc/x86_64-suse-linux/4.7.2/cc1 | grep PATH
0x000000000000001d (RUNPATH) Library runpath: \
[/sdk/x86_64/2.11.1/gcc-4.7.2/lib64: \
/sdk/x86_64/2.11.1/gcc-4.7.2/lib: \
/sdk/x86_64/2.11.1/gcc-4.7.2/libexec/gcc/x86_64-suse-linux/lib64: \
/sdk/x86_64/2.11.1/gcc-4.7.2/lib/gcc/x86_64-suse-linux/4.7.2: \
/hostname/sig/lib64: \
/hostname/sig/lib]
I know that libstdc++.so.6 exists in the first entry in the RUNPATH:
$ ls -l /sdk/x86_64/2.11.1/gcc-4.7.2/lib64/libstdc++.so*
lrwxrwxrwx .../sdk/x86_64/2.11.1/gcc-4.7.2/lib64/libstdc++.so -> libstdc++.so.6.0.17
lrwxrwxrwx .../sdk/x86_64/2.11.1/gcc-4.7.2/lib64/libstdc++.so.6 -> libstdc++.so.6.0.17
-rwxr-x--- .../sdk/x86_64/2.11.1/gcc-4.7.2/lib64/libstdc++.so.6.0.17
-rwxr-x--- .../sdk/x86_64/2.11.1/gcc-4.7.2/lib64/libstdc++.so.6.0.17-gdb.py
I don't have an LD_LIBRARY_PATH set in my environment:
$ echo $LD_LIBRARY_PATH
$
How come it doesn't pick up the library found in RUNPATH?
How can I force it to use the gcc-4.7.2 libraries?
The problem is that one of the prerequisites (libppl.so) also imports libstdc++. That prerequisite was built using the system gcc, and therefore finds /usr/lib64/libstdc++.so.6
$ ldd /sdk/x86_64/2.11.1/gcc-4.7.2/lib/libppl.so
linux-vdso.so.1 => (0x00007fffd10db000)
libgmpxx.so.4 => /sdk/x86_64/2.11.1/gcc-4.7.2/lib/libgmpxx.so.4 (0x00007f4716f92000)
libgmp.so.10 => /sdk/x86_64/2.11.1/gcc-4.7.2/lib/libgmp.so.10 (0x00007f4716d26000)
--> libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007f4716a25000)
libm.so.6 => /lib64/libm.so.6 (0x00007f47167a0000)
libc.so.6 => /lib64/libc.so.6 (0x00007f4716441000)
libgcc_s.so.1 => /usr/lib64/libgcc_s.so.1 (0x00007f471622c000)
/lib64/ld-linux-x86-64.so.2 (0x00007f47174b4000)
Once a library has been located by the dynamic linker once, it will no longer be searched for; that location will be used for any subsequent requirements.
I resolved this by rebuilding the prerequisites with the new gcc.
$ ldd /sdk/x86_64/2.11.1/gcc-4.7.2/lib/libppl.so
linux-vdso.so.1 => (0x00007fffd10db000)
libgmpxx.so.4 => /sdk/x86_64/2.11.1/gcc-4.7.2/lib/libgmpxx.so.4 (0x00007f4716f92000)
libgmp.so.10 => /sdk/x86_64/2.11.1/gcc-4.7.2/lib/libgmp.so.10 (0x00007f4716d26000)
--> libstdc++.so.6 => /sdk/x86_64/2.11.1/gcc-4.7.2/lib/../lib64/libstdc++.so.6 (0x00007f4716a25000)
libm.so.6 => /lib64/libm.so.6 (0x00007f47167a0000)
libc.so.6 => /lib64/libc.so.6 (0x00007f4716441000)
libgcc_s.so.1 => /sdk/x86_64/2.11.1/gcc-4.7.2/lib/../lib64/libgcc_s.so.1 (0x00007f471622c000)
/lib64/ld-linux-x86-64.so.2 (0x00007f47174b4000)
I'm thinking the final step is to now rebuild gcc with the newly build prerequisites.
build prerequisites with system gcc
build new gcc
rebuild prerequisites with new gcc
rebuild gcc with rebuilt prerequisites
Whether the final step is necessary I'm not sure.
You need to set the LD_LIBRARY_PATH to point to the desired libstdc++. RUNPATH is evaluated after LD_LIBRARY_PATH.
Quoting from RPATH issue:
The dynamic linker will look for a matching library in the following locations, in this order, which can be changed (see the footnotes below):
1. the DT_RPATH dynamic section attribute of the library causing the lookup
2. the DT_RPATH dynamic section attribute of the executable
3. the LD_LIBRARY_PATH environment variable, unless the executable is setuid/setgid.
4. the DT_RUNPATH dynamic section attribute of the executable
5. /etc/ld.so.cache
6. base library directories (/lib and /usr/lib)

Statically link GMP to an Haskell application using GHC (+ LLVM)

How can I drop dynamic dependency on libgmp and go from this:
linux-vdso.so.1 => (0x00007fffdccb1000)
libgmp.so.10 => /usr/lib/x86_64-linux-gnu/libgmp.so.10 (0x00007fb01afc1000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fb01acc7000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fb01aabe000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fb01a8ba000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fb01a69d000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb01a2df000)
/lib64/ld-linux-x86-64.so.2 (0x00007fb01b249000)
to this (currently desired):
linux-vdso.so.1 => (0x00007fffdccb1000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fb01acc7000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fb01aabe000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fb01a8ba000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fb01a69d000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb01a2df000)
/lib64/ld-linux-x86-64.so.2 (0x00007fb01b249000)
in a clean and portable way that just works on all GNU/Linux distributions (and not messing up with BSDs (including OS X))?
Do you see any other dependencies that may cause problems in the currently desired list as given above when distributing a single Haskell binary targeting multiple GNU/Linux distributions?
Notes:
my app is GPLv3 so no license violation issues arise regarding GMP
Specifying a path to libgmp.a does not work ( How to selectively link certain system libraries statically into Haskell program binary? ), libgmp is still listed in the ldd output.
If you pass -optl-static -optl-pthread to GHC, it'll statically link all the runtime library dependencies, including GMP. Setting ld-options: -static -pthread in your Cabal file should accomplish the same thing.
That means you'll statically link in glibc too, but that probably won't be a problem, although it might increase binary size quite a bit. Using an alternative libc like musl or uClibc should help counteract that, if it's a problem for you.

What does version info in ldd -v mean?

Version information:
/usr/lib/lapack/liblapack.so:
libc.so.6 (GLIBC_2.14) => /lib/x86_64-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.4) => /lib/x86_64-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libc.so.6
libgcc_s.so.1 (GCC_4.0.0) => /lib/x86_64-linux-gnu/libgcc_s.so.1
libgfortran.so.3 (GFORTRAN_1.0) => /usr/lib/x86_64-linux-gnu/libgfortran.so.3
libgfortran.so.3 (GFORTRAN_1.4) => /usr/lib/x86_64-linux-gnu/libgfortran.so.3
libm.so.6 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libm.so.6
So there are 3 rows of libc.so.6, versioned at GLIBC_2.xx.
What does that mean? What version of libc.so.6 does this liblapack.so require?
How can I get liblapack.so's version?
What does that mean?
It means that liblapack.so requires versioned symbols from libc.so.6 with versions GLIBC_2.2.5, GLIBC_2.4 and GLIBC_2.14. You can read about versioned symbols here.
What version of libc.so.6 does this liblapack.so require?
It requires 2.14 or newer. In general, GLIBC never removes symbols, only adds new ones, and so will still provide symbols versioned at GLIBC_2.2.5 even in the latest GLIBC-2.24.
If it did ever remove such "old" versioned symbol, that would break any old binaries that depended on that symbol (which is why it's not done).
How can I get liblapack.so's version?
It doesn't look like liblapack.so itself is using any versioned symbols. You can look at your package manager to find out what version of liblapack.so you have. Something like:
dpkg -S /usr/lib/lapack/liblapack.so
liblapack-dev: /usr/lib/lapack/liblapack.so
dpkg -l liblapack-dev
...
ii liblapack-dev 3.5.0-2ubuntu1 amd64 Library of linear algebra routines 3 - static version

Resources