Bundle c++ application using libc.so.6 - c++

I'm Trying to make my executable portable on linux, to do this i need to copy all the shared library used by the program itself, to check which one do I need I use:
ldd program_name
The output of the program helps me find all the required .so, between these libraries there is:
libc.so.6 => /lib64/libc.so.6 (0x00007f5b61ac2000)
At this point I copied all the libraries in a folder called shared_libs and shipped them alongside the program to another pc, the problem arise when i do:
LD_LIBRARY_PATH=./shared_libs ./program_name
which gives:
[1] 4619 segmentation fault (core dumped) LD_LIBRARY_PATH=./shared_libs ./program_name
I'm pretty sure that libc.so.6 is causing the problem because if I do:
LD_LIBRARY_PATH=./shared_libs ls
with just that library in the shared_libs folder, ls gives seg fault as well.
How can i bundle my application?
EDIT 1: Why i don't link statically everything?
I tried it, The only thing i got was headache...

to do this i need to copy all the shared library used by the program itself
No, you don't. In particular, copying GLIBC simply doesn't work (as you've discovered).
What you actually need is to build your program against an old enough (not newer than any of systems you distribute your program to) libc, and then depend on GLIBC ABI compatibility (which guarantees that programs linked against old GLIBC continue to run correctly when bound to newer GLIBC at runtime).
This can be achieved by either building your program on an old system, or using a chroot, or building a "linux to older linux" cross-compiler.
I'm pretty sure that libc.so.6 is causing the problem
Correct. The reason this doesn't work is explained e.g. here.
The problem is that GLIBC is composed of multiple binaries which all must match. And the path to one of these binaries (the ld-linux) is hard-coded into the program at static link time and can not be changed.

Related

Is it possible to compile statically with gcc or g++ on Linux based systems?

I am working on a project which I would like to be able to "ship" to other Linux based computers as a complete executable with no dependencies. (In order that I can copy just the 1 file to other systems, and then run that file on those systems.)
In the windows world, I think static linking is done just by passing -static to the compiler, perhaps with some other options for specific libraries*, if you are using Visual Studio.
*eg: Using SFML you also have to define SFML_STATIC for some reason?
Is this possible using gcc / g++, and if so how? I tried searching for this but didn't manage to find anything. I have heard before that this may be a non-trivial task.
Edits:
BasileStarynkevitch suggested compiling with the flag -static.
I don't know if this is what I want, but I wrote a test program to try it out:
#include <iostream>
int main()
{
std::cout << "Link statically please" << std::endl;
return 0;
}
And then compiled with:
g++ main.cpp -o a.out -static
g++ main.cpp -o b.out
The results are:
-rwxr-xr-x 1 1653098 a.out
-rwxr-xr-x 1 9167 b.out
So it looks like it might be working?
TonyD suggested a method of checking:
ldd a.out
not a dynamic executable
ldd b.out
linux-vdso.so.1 => (0x00007fff3d5ac000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fce5e34a000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fce5df85000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fce5dc7e000)
/lib64/ld-linux-x86-64.so.2 (0x00007fce5e677000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fce5da67000)
Is it possible to compile statically with gcc or g++ on Linux based systems?
It depends.
You might try to compile and link all your code with gcc -static or g++ -static. In several cases (e.g. pure command-line applications, like your hello world), it would work.
Linux distributions like a lot shared libraries. Most of them are using shared libraries extensively (notably for graphical applications). Read Drepper's How to Write Shared Libraries paper for more.
You might have some licensing issues. To simplify outrageously, it might be illegal (against the LGPL license) to ship code statically linked to some LGPL (or GPL) library. The evil is in the details.
Some core features, notably DNS related (e.g. getaddrinfo(3) & getnameinfo(3)) are internally using plugin techniques à la dlopen(3), so sort-of requires a dynamic libc.so (see nsswitch.conf(5) for more).
Some X11 things, in particular font related, are also expecting plugin related things (IIRC, Xft); perhaps SFML uses them. BTW, SFML is very probably installed as shared libraries, so you'll need to rebuild SFML from source code...
At last, a statically linked program might be more tied to some particular kernel version that a dynamically linked one (in principle, this is not the case). It might happen that you could have incompatibilities with very old or future kernels (but usually not).
See also ldd(1), file(1), pmap(1), proc(5), vdso(7)
It might be actually simpler to ship the source code to the target system, ask the sysadmin to install required dependencies, and build your code on the remote target (e.g. using ssh)
You could try to link statically most libraries but not all (e.g. link statically libstdc++.a and dynamically libc.so) by playing with GCC linking options. See this & that
Perhaps you'll first should try to link statically some SFML demo.... or simply scp your (dynamically linked) binary program and try to run it remotely (it might be able to run).
Compiling with -static appears to work for basic c++ programs, probably all of the standard library?
However when using with other libraries, this may no longer work.

How do I build my Linux c++ app to link to an old version of libc?

I have built an app on Ubuntu 12.04 and have tried running it on an embedded system. I ran apt-cache show libc6 on my dev machine which shows (amongst other things)
Package: libc6
Priority: required
Section: libs
Architecture: i386
Source: eglibc
Version: 2.15-0ubuntu10
Replaces: belocs-locales-bin, libc6-i386
Provides: glibc-2.13-1, libc6-i686
The version of libc6 that exists on the embedded device is 2.8.90. In the \lib directory on the device I have 2 libs
libc-2.8.90.so
libc.so.6
When I copy my application onto the embedded device I get the following errors
/usr/lib/libc.so.6: version `GLIBC_2.15` not found (required by ./ServerSocketApp)
I know that if possible I when I build the application on my dev maching I need to force it to link to the same version of libc6 as exists on the embedded device. The problem I have is that I simply do not know how to do this. Any answers that I have found are meaningless to me right now. Is there some option that I need to pass to g++ to get this to link to version 2.8.90 ??
In desperation I am thinking is it possible to copy the libc on my dev machine onto the embedded device in place of what is there already and hope for the best??? I just cannot seem to find any documentation online that explains in simple terms how you even go about this so any advice at all would be really really welcome as I am tearing my hair out here.
OK, here is a somewhat longer explanation, but proceed with care. I still strongly recommend that you setup a chrooted environment to match the one available on the embedded device and use it during the last stage of your build process.
You should understand how dynamically linked ELF executables are loaded and executed. There is something called the run-time link editor (RTLD), also known as the dynamic linker, that takes care of loading all the necessary dynamically linked libraries, fixing relocations and so on. The name of the dynamic linker is /lib/ld-linux.so.2 on 32-bit Linux systems with glibc2 and /lib64/ld-linux-x86-64.so.2 on 64-bit Linux systems with
glibc2. The dynamic linker is very tightly coupled to the glibc2 library and usually can only handle the matching version of that library. Also the path to it is hardcoded into the executable by the linker (usually ld, implicitly called by the compiler to do the linking). You can easily check the validty of the last statement by simply doing ldd some_elf_executable - the run-time link editor shows up with the full path:
$ ldd some_elf_executable
linux-vdso.so.1 => (0x00007fffab59e000)
libm.so.6 => /lib64/libm.so.6 (0x0000003648400000)
libc.so.6 => /lib64/libc.so.6 (0x0000003648800000)
/lib64/ld-linux-x86-64.so.2 (0x0000003648000000) <--- the RTLD
In order to produce a dynamically linked executable that uses a version of glibc2 different from the one installed on the system, where the executable is to be run, you should link your code with the following set of options to ld:
-rpath=/path/to/newer/libs - this one instructs the dynamic linker to first search /path/to/newer/libs when trying to resolve library dependencies. /path/to/newer/libs should match the path where you have copied the newer glibc2 version on the embedded device
-rpath-link=/path/to/newer/libs - this option instructs the linker (not the dynamic linker) to use /path/to/newer/libs when resolving dependencies between shared libraries during link time - this should not be normally necessary in your case
--dynamic-linker=/path/to/newer/libs/ld-linux.so.2 - this one overrides the path to the RTLD that gets embedded into the executable
The way to provide those options to ld is usually via the -Wl option of GCC.
-rpath=/path/to/newer/libs
becomes:
-Wl,-rpath,/path/to/newer/libs
(notice that the = is replaced by ,)
--dynamic-linker=/path/to/newer/libs/ld-linux.so.2
becomes:
-Wl,--dynamic-linker,/path/to/newer/libs/ld-linux.so.2
You should copy /lib/ld-linux.so.2 from your development system to /path/to/newer/libs/ on the embedded device. You should also copy libc.so.6, the mathematical library libm.so.6 and all the other libraries that are used by the executable or that might get loaded indirectly. Note that libc.so.6 and libm.so.6 are actually symbolic links to the real libraries which have names like libc-2.<version>.so. You should copy those library files and create the appropriate symbolic links to make everybody happy.
This is fundamentally incorrect. While you may be able to hack together a way to link in the old libc, the problem is your environment setup.
When you develop applications for an embedded system. You do so on a host. Generally, the host and embedded device are not on the same architecture. For example, your host is usually a desktop/laptop running on an x86 and the embedded system might be on an ARM. If you happen to be on the same architecture as your embedded device, that is sheer coincidence. Standard practice environment setup should still follow:
The host machine should have a tool chain setup to cross build applications to the embedded architecture
The host machine should have a copy of the full rootfs that exists your embedded device. This will contain all of the libraries that your cross tools will use to compile applications for the embedded system
If you have it setup this way. Development will be easy. You will be able to setup simple, clean make files to build your applications and then just scp the binaries over to the embedded system and run.
You might have some luck compiling with the LSB SDK (http://www.linuxfoundation.org/collaborate/workgroups/lsb/download) which restricts the symbols available to the executable.

How to statically link all libraries except a few using g++?

I have a requirement that I link all my libraries statically including libstdc++, libc, pthread etc. There is one omniorb library which I want to link dynamically.
Currently I have dynamically linked all the libraries.
ldd shows the following
linux-vdso.so.1 => (0x00007fff251ff000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f291cc47000)
libomniDynamic4.so.1 (0x00007f291c842000)
libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007f291c536000)
libm.so.6 => /lib64/libm.so.6 (0x00007f291c2e0000)
libgomp.so.1 => /usr/lib64/libgomp.so.1 (0x00007f291c0d7000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f291bebf000)
libc.so.6 => /lib64/libc.so.6 (0x00007f291bb66000)
/lib64/ld-linux-x86-64.so.2 (0x00007f291ce63000)
librt.so.1 => /lib64/librt.so.1 (0x00007f291b95d000)
libomniORB4.so.1 (0x00007f291b6aa000)
libomnithread.so.3 (0x00007f291cf35000
I need ldd to show libomniDynamic4.so.1 as the only dynamically linked library.
How do I achieve this?
Trying to make a linux executable that runs on all distros eh? Good luck...But I digress...
You want to look at the -v flag output for g++. It shows the internal link commands executed by g++/ld. Specifically, you'll want to inspect the the final link command collect2 and all of its arguments. You can then specify the exact paths to the .a libs you want to link against. You'll also have to track down static libs of everything. My libstdc++.a is in /usr/lib/gcc/x86_64-linux-gnu/4.4/libstdc++.a
rant on: My biggest complaint about linux is the fractured state of executables. Why cant I compile a binary on one machine and copy it to another and run it!? Even the Ubuntu distros one release apart will produce binary files that cannot be run on the other due to libc/libstdc++ ABI incompatibilites
edit #1 I just wanted to add that The script on this page produces a .png of an executables .so dependencies. This is very useful when attempting to do what you describe.
Be aware ldd <exename> will list all dependencies down the chain, not just immediate dependencies of the executable. So even if your executable only depended upon omniorb.so, but omniorb.so depended upon, libphread.so, ldd's output would list that. Look up the manpage of readelf to find only the immediate dependencies of a binary.
One other item that to be aware of. if omniorb.so depends upon libstdc++.so, you'll have no choice but to be dependant on that same lib. Otherwise ABI incompatibilities will break RTTI between your code and omniorb's code.
I need ldd to show libomniDynamic4.so.1 as the only dynamically linked library.
That is impossible.
First, ldd will always show ld-linux-x86-64.so.2 for any (x86_64) binary that requires dynamic linking. If you use dynamic linking (which you would with libomniDynamic4.so.1), then you will get ld-linux-x86-64.so.2.
Second, linux-vdso.so.1 is "injected" into your process by the kernel. You can't get rid of that either.
Next, the question is why you want to minimize use of dynamic libraries. The most common reason is usually mistaken belief that "mostly static" binaries are more portable, and will run on more systems. On Linux this is the opposite of true.
If in fact you are trying to achieve a portable binary, several methods exist. The best one so far (in my experience) has been to use apgcc.
It is very difficult to build a single binary that runs on a lot of Linux distros and linking statically is not the key point.
Please note that a binary built with an older glibc version--i.e., an old Linux distro--may run on newer Linux distros as well. This works because glibc is back-compatible.
A possible way to attain the desired result is:
compile the binary on an old Linux OS
find out all the required libraries for your compiled binary using the command ldd or lsof
(when running) on the binary, details here
copy the required libraries of the old Linux OS in a 'custom-lib' folder
always bundle/release this custom-lib folder with your binary
create a bash script that puts the custom-lib folder on top of the folders list in LD_LIBRARY_PATH environment variable, and then invokes your binary.
In this way, by executing the binary with the bash script, I was able to execute binaries on a wide range of embedded devices with very different Linux versions.
But there are always problematic cases where this fails.
Please note, I always tested this with cli applications/binaries.
Other possible ways..
There also seems to be elegant ways to compile glibc-back-compatible binaries, for example this that seems to compile binaries compatible with older ABI. But I have not checked this route.
when linking, use -static before specifying the libraries you want to link statically to, and use -dynamic before the libraries you want to link dynamically to. You should end up with a command line looking like this:
g++ <other options here> -dynamic -lomniDynamic4 -static -lpthread -lm -lgomp <etc>
Of course, you'll need .a versions of the libraries you want to link statically (duh).

question about compiled program usage of external libraries

I know this might be a very stupid question but I am new to compiled languages (my domain is mostly scripting languages like PHP, Python or JavaScript).
I am learning C++ for one project where it is the only language I can use.
I wrote a program in Ubuntu 10.10 and then compiled it. I can run the generated binary file from cmd like this and it works:
sudo ./compiled-program
But, I have used some external libraries in the program (OpenCV). Does that mean that all computers where I will run the program will have to have OpenCV installed? Or is OpenCV bundled inside the compiled binary file? Will it work on PCs without OpenCV installed?
You should read a few things about libraries, and particularly what makes the difference between static and dynamic libraries. To quote the basic definitions so you get the point :
A static library, also known as an
archive, consists of a set of routines
which are copied into a target
application by the compiler, linker,
or binder, producing object files and
a stand-alone executable file.
[...]
Dynamic linking involves loading the
subroutines of a library (which may be
referred to as a DLL, especially under
Windows, or as a DSO (dynamic shared
object) under Unix-like systems) into
an application program at load time or
runtime, rather than linking them in
at compile time.
Not a stupid question at all!
The "normal" way this works - is that your program has been linked against a "Shared Library" - in which case, yes, the user needs the OpenCV (or whatever bundle includes the shared library) to work.
If you compiled as a static executable, (using the -static) flag, then it, and all libraries would be included directly into your executable, making a bit of a larger executable that wastes more memory, because it isn't using a shared library.
There are ways that you could compile your program to link only your OpenCV libraries as static - but that only can be done if the bundle included a static library ".a" vs. a shared one ".so".
If you had to build your code against dependencies, like OpenCV, it depends on if you did static or dynamic linking.
See here which has sections covering these ideas: http://en.wikipedia.org/wiki/Library_(computing)
For starters, try doing this on the command line:
ldd compiled-program
You will get output like this (as an example, I did ldd on my python binary in /usr/bin):
birryree#lilun:/usr/bin$ ldd python
linux-gate.so.1 => (0xb7ff7000)
libpthread.so.0 => /lib/i686/cmov/libpthread.so.0 (0xb7fd5000)
libdl.so.2 => /lib/i686/cmov/libdl.so.2 (0xb7fd1000)
libutil.so.1 => /lib/i686/cmov/libutil.so.1 (0xb7fcd000)
libssl.so.0.9.8 => /usr/lib/i686/cmov/libssl.so.0.9.8 (0xb7f82000)
libcrypto.so.0.9.8 => /usr/lib/i686/cmov/libcrypto.so.0.9.8 (0xb7e2a000)
libz.so.1 => /usr/lib/libz.so.1 (0xb7e16000)
libm.so.6 => /lib/i686/cmov/libm.so.6 (0xb7df0000)
libc.so.6 => /lib/i686/cmov/libc.so.6 (0xb7caa000)
/lib/ld-linux.so.2 (0x80000000)
Python wants a lot of additional stuff, like libssl (part of OpenSSL), the GNU C library (libc), and some others.
Now if you're going to be moving this thing around to other systems, you either hope they have an environment similar to yours, distribute it as source and use something like the autotools/GNU Build System to build it, or you can forego all that and statically link everything into your binary, which will bring in all the stuff your executable needs without need for a dynamic link.
If you've "compiled against" OpenCV, then machines running your app need it too. You need to copy the libs when you install your app, or ensure that they're already installed.
It depends on wether you are compiling against a shared (Dynamic) library or compiling it into your executable (compiling against a static library). If you are compiling against a shared library you need to distribute the shared library ... otherwise .. you don't.
There are two kinds of libraries, static and dynamically loaded.
Statically loaded libraries are joined with your binary file, while dynamically loaded libraries are loaded at runtime.
It depends on whether or not the executable is statically-built or dynamically linked. In a statically-built executable it is the case that the library files the executable needs are compiled into the executable and there isn't an need to carry around additional library files. In a dynamically linked executable it is the case that the library files the executable needs are linked at runtime and therefore a copy of the library files are needed at runtime.

Dynamic linking a library - successful when executable is built, same setup fails when another .so is made

I am writing a numerical code, in which I would like to use a third-party-written shared library. I am working on an x86_64 k8 architecture, under CentOS. The desired target that I would like to build would be either a Python or a Matlab extension module, which are, from what I understand, gcc-built dynamically-linked shared libraries, with extra Matlab/Python scaffolding built in. I'll focus on Python here, as the same problem happens, and it is probably more familiar to the community.
The library developer provided me originally with dynamic library and some test code written in C++. That's how he intended to distribute his library. I should make a note that I am trying to burden the original developer as little as possible, since the library probably being a side-project for him some time ago, and his test code ends up working OK. Therefore, I am trying to resolve issues on my end to the largest extent I can on my end. I managed to build his examples into executables, only with gcc 4.5.0. Usual gcc version that I use, 4.1.2, produced four "undefined reference to" errors during linking (with g++), specifically to _M_insert<long>(long), _M_widen_init(), _M_insert<double>(double) and __ostream_insert<char, std::char_traits<char> >. These are all part of std namespace. Compiling with g++ 4.5.0 resolved these undefined references and the example executables run correctly. Per E.R.'s comment, readelf -x.comment libmaxent_k8.so, indicates the original libraries were built with gcc 4.4.1.
To test whether linking to a Python extension works, I've built a small, Python extension function in C++ that just adds two numbers. Specifically, it doesn't use anything from the library I would like to use. The interface was SWIG 2.0 generated, compiled with g++ 4.50. and the code runs fine in Python 2.4.3. However, when I try to link to the original library, without ever referencing any symbols from it, the code again links fine, but then during runtime, while importing the extension, I get ImportError: libmaxent_k8.so: undefined symbol: _ZNSo9_M_insertIlEERSoT_, which, by c++filt, is the _M_insert(long), which is one of the original ones, that were undefined when the C++ code was linked using g++ 4.1.2.
I suspect the issue is with mismatched libstdc++ versions during linking and runtime of python, but I don't know how to resolve this. The best-case scenario for me would let me somehow get away without gcc 4.5.0 when linking the extensions, perhaps I was jumping ahead when resolving the original 4 missing references problem. Could the issue be resolved by bing built with somehow statically linking to libstdc++ 6.0.14 (which is a part of gcc 4.5.0) statically, while still retaining their character as dynamically linked libraries? Although, the Python has no problem of cooperating with gcc 4.5.0, Matlab does, and their support claims reliability only up to gcc 4.2.0. For this reason I would like to keep away from compiling with 4.5.0 as little as possible. My gcc comes with 6.0.8 version of libstdc++.
Here are some reports on the library in question. Remember, despite all these references, the code worked when compiled directly to an executable.
$ readelf -aD /home/mbudisic/lib64/libmaxent_k8.so | grep NEEDED
0x0000000000000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
$ ldd -d libmaxent_k8.so
undefined symbol: _ZSt4cerr (./libmaxent_k8.so)
undefined symbol: _ZNSt8ios_base4InitD1Ev (./libmaxent_k8.so)
undefined symbol: _ZSt4cout (./libmaxent_k8.so)
undefined symbol: __gxx_personality_v0 (./libmaxent_k8.so)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00002b92457f3000)
libc.so.6 => /lib64/libc.so.6 (0x00002b9245a01000)
/lib64/ld-linux-x86-64.so.2 (0x000000366e200000)
Running nm -uC libmaxent_k8.so results in 35 'U' labeled symbols, and two 'w' labeled symbols, from libm and libstdc++ libraries, which is far more than reported as undefined in linking/running.
In general, glibc and libstdc++ try to provide backwards compatibility -- a binary built on an older system (or with older GCC) continues to run on a newer system.
The reverse: running binary linked against glibc-2.10 on a glibc-2.5 system, or running a binary built with GCC-4.4 against libstdc++ which came with GCC-4.2 is a non-goal.
Therefore, you must either ask for binaries built with the oldest GCC you want to support (4.2 in your case), or arrange for a new libstdc++ to be used (by modifying LD_LIBRARY_PATH, or by using LD_PRELOAD) for Matlab and Python.
The backward compatibility of glibc is very good, but libstdc++ has more spotty record; so Matlab's claim that only up to libstdc++.so.6.0.8 is stable and supported may well be true. You just have to try it, since (unless you get libmaxent_k8.so built with GCC-4.2) you don't have any other options (that I can think of).
Here is a very good write-up on why linking libstc++ statically may be not a very good idea:
http://www.trilithium.com/johan/2005/06/static-libstdc/