This may be a stupid question, but if I compile a shared library using g++ on one distribution of Linux, and then move those libraries as object files via flash drive to another computer with the exact same Linux distro and version of g++ will I still be able to link those libraries in my source files on the second machine?
I'm asking because I don't have the permissions to install the necessary libraries before compiling on the second machine, so it'd be easier for me to just compile them on my own computer and upload the compiled object files via flash drive to the second machine
Let me explain you with some example.
suppose i have binary named myapp in my machine X and i want to run it in another machine Y but when i run then it show me some error like
./myapp: error while loading shared libraries: libcgicc.so.5: cannot open shared object file: No such file or directory
This means I’m using a library that isn’t on the other machine. Of course, I could try installing all the same libraries on Y as there are on X. But i have't permission to do. Then our alternative is to statically link libraries with our program.
On Y, run the command ldd myapp. This will give something like:
libpthread.so.0 => /lib/tls/libpthread.so.0 (0xf7f77000)
libdl.so.2 => /lib/libdl.so.2 (0xf7f73000)
libgd.so.2 => /usr/lib/libgd.so.2 (0xf7f26000)
libcgicc.so.5 => not found <------------------------------------//this library missed
libjpeg.so.62 => /usr/lib/libjpeg.so.62 (0xf7f08000)
libpng12.so.0 => /usr/lib/libpng12.so.0 (0xf7ee4000)
Let’s go back to our compiling machine, machine X, and see what ldd myapp says there for libcgicc:
libcgicc.so.5 => /usr/lib/libcgicc.so.5 (0xb7f18000)
So on machine X, the library we want is in /usr/lib. If we do ls /usr/lib/libcgicc* we can see what versions of this library are available. On machine that is:
/usr/lib/libcgicc.a
/usr/lib/libcgicc.la
/usr/lib/libcgicc.so
/usr/lib/libcgicc.so.5
/usr/lib/libcgicc.so.5.0.1
So there is a static version available,libcgicc.a. If there were not a .a version, we would need to get one - on debian/ubuntu we could track it down by doing (as superuser):
apt-file search libcgicc.a
Now, all we need to do is relink our program, replacing -lcgicc with /usr/lib/libcgicc.a. Now when we do ldd myapp on either machine, we have no more missing libraries.
However, that doesn’t guarantee all libraries are exactly the same version. A frequent problem is libstdc++ for C++ code. If you see a message like this when trying to run your code:
./myapp: /usr/lib/libstdc++.so.6: version `GLIBCXX_3.4.9′ not found (required by ./myapp)
Then you’ve got a version mismatch. This may be fixable by statically linking the libstdc++ library. Check what version of g++ you are using with g++ –version, and then check for libstdc++.a in:
/usr/lib/gcc/[platform-name]/[version]
(location may be different on your computer). Once you track this file down you can link it statically as before.
Related
I have an issue which sounds annoyingly simple, but I feel I've tried everything to resolve it and I'm out of ideas.
I have a program I wrote which uses boost/program_options.hpp using the include statement
#include <boost/program_options.hpp>
This program works on my laptop and now I am trying to put it onto a server where I don't have sudo privileges. On my laptop, where the whole thing works I have boost versions 1.56 and 1.58 and on the server I found 1.53.0. I didn't install or build this though.
The shared library file that exists on the server is:
/usr/lib64/libboost_program_options.so.1.53.0
Running ldd on that gives me the output:
ldd /usr/lib64/libboost_program_options.so.1.53.0
linux-vdso.so.1 => (0x00007ffc54a63000)
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007fc0dcad8000)
libm.so.6 => /lib64/libm.so.6 (0x00007fc0dc7d5000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fc0dc5bf000)
libc.so.6 => /lib64/libc.so.6 (0x00007fc0dc1fe000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc0dd071000)
Which I assume means it's found all its dependencies.
I have made a symbolic link to my home directory to create a libboost_program_options.so link, which I guess means the -lboost_program_options linker flag should work.
The way I compile is by:
g++ -L/home/homeDir code.cpp -o code.o -std=c++11 -Wall -lboost_program_options
And all I get is:
fatal error: boost/program_options.hpp: No such file or directory
#include "boost/program_options.hpp"
^
compilation terminated.
I've tried this with quotes and <>, and without "boost/" etc, but I always get the same complaint. I assume this means that it finds the library as there is no complaint about the -lboost_program_options flag?
While it works on my machine, I may not be using the shared program options library at all. On my laptop I have both a static version of libboost_program_options in my library path which it may be using, and the program_options.hpp header outside of a library which may be in my include path. I feel like I should be able to use the shared library that's on the server and not annoy the server admin for the 5th time (things work really slowly with these things here).
I'm sorry if this is my oversight. I'm fairly new to boost, but I feel like I've tried everything to resolve this myself at the moment.
I'd be happy with any suggestions as to how I could change this... or if I'm just being a bit stupid with using shared libraries.
Thanks in advance.
EDIT:
After more research I feel like I'm just getting confused between static and shared libraries. I'm trying to link a shared library at compile time, which I guess doesn't make sense. Also including the header file of something which should not be linked at compile time makes little sense. My code is clearly designed for the static library.
The error message is produced by the pre-compiler which does not find the Boost header file (as it says in the error message). You need to set the correct include path (-I...) where the Boost library header files are found, obviously they are not under /usr/include.
Path to the Boost libraries (-L...) must be specified accordingly.
Finally: If you are linking against the Boost shared libraries on your system, then you should use the same version of Boost as installed on the server. Otherwise, link against the static libraries, this may make you executable larger, but it will run on any server, regardless of the Boost version installed there (even none).
sudo apt install libboost-program-options-dev
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.
when I compile a c++ program in my computer using g++ and transfer the executable to run it on my university server, I get
./main: /usr/lib/libstdc++.so.6: version `GLIBCXX_3.4.9' not found (required by ./main)
./main: /usr/lib/libstdc++.so.6: version `GLIBCXX_3.4.14' not found (required by ./main)
./main: /usr/lib/libstdc++.so.6: version `GLIBCXX_3.4.11' not found (required by ./main)
The program runs well on my computer, and I don't have privileges to install any new software on my university servers.
any help ?
Thanks
It seems you are using the standard library as a shared library (default behaviour) when linking your program at home.
So rather than really "linking" the library, your linker just resolves some symbols and does another operation, while delaying the actual loading of the library to run-time.
When you execute your program at your university computer, the loader (the program which actually loads your program in memory and throws the main thread) looks for the libraries your program needs and tries to load them (look for LD_LIBRARY_PATH in linux if you feel curious).
The problem here is that you are linking your program at home with a version of the stdlib that is not the same version as what you have at the university. So when the loader tries to find the library, it fails, and so your program cannot be run.
Solutions:
a) To avoid all these problems use static linking instead of dynamic linking. I am not sure if this is possible with stdlib, but I think it is worth to test it (see: http://gcc.gnu.org/onlinedocs/gcc/Link-Options.html and look for "-static" flag)
b) You can try to compile your program at your university computer so it will use the version there.
c) Try to know which stdlib version is installed there and install the same version in your compiler machine.
d) You can try to copy your home version of stdlib to the same folder your application is. This usually works because the loader tends to search for shared libraries in the current application folder before looking in the path set in the environment variable LD_LIBRARY_PATH (linux)
Hope that helps.
P.S.:
Here you have a nice introduction to static vs shared/dynamic libraries http://www.network-theory.co.uk/docs/gccintro/gccintro_25.html
And here (http://en.wikipedia.org/wiki/Library_%28computing%29) a not so nice but more complete library description.
The version of libstdc++.so.6 is too old on the university computer. You have two options:
Statically link with -static. The C++ library will then be merged into the final binary.
Copy the correct version to somewhere in your home directory, then reference it either by passing -rpath /path/to/library/directory at build time, or setting the LD_LIBRARY_PATH environment variable to point to the directory containing the newer libstdc++.so.6.
You can copy your version of the /usr/lib/libstdc++.so.6 to a subdirectory of your home directory of the server, say ~/lib and then run:
$ LD_LIBRARY_PATH=$HOME/lib ./main
Or if you prefer
$ export LD_LIBRARY_PATH=$HOME/lib
$ ./main
And the program should load your private library instead of the system one.
What platforms are you trying to compile for? i.e. 'Your computer' and your 'University servers' ?
You could try compiling your program with the static linking option. This will generate a statically linked executable with all lib dependencies loaded already.
Cheers,
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).
My program is written in C++, using GCC on Ubuntu 9.10 64 bit. If depends on /usr/lib64/libstdc++.so.6 which actually points to /usr/lib64/libstdc++.so.6.0.13. Now I copy this program to virgin Ubuntu 7.04 system and try to run it. It doesn't run, as expected. Then I add to the program directory the following files:
libstdc++.so.6.0.13
libstdc++.so.6 (links to libstdc++.so.6.0.13)
Execute command:
LD_LIBRARY_PATH=. ./myprogram
Now everything is OK. The question: how can I write installation script for such program? myprogram file itself should be placed to /usr/local/bin. What can I do with dependencies? For example, on destination computer, /usr/lib64/libstdc++.so.6 link points to /usr/lib64/libstdc++.so.6.0.8. What can I do with this?
Note: the program is closed-source, I cannot provide source code and makefile.
If you're working on Ubuntu, making a .deb (Debian Package) seems to way to go. Here is a link to get you started.
Your package will state it depends on some other packages (typically the packages that includes libstdc++.so.6.0.13 - i guess the package name is something like libstdc++) and dependencies will be installed when you install your own package using dpkg -i <yourpackage>.deb.
Afterwards, you'll be able to uninstall it using dpkg -r <yourpackage>.
Anyway, never ship such standards files with your own archive. Dependencies exists for this exact purpose.
Hope it helps.
The real problem is that you try to install a binary that use newer versions os common libraries that the ones available on Ubuntu 9.10. The best option should be to make a specific target for the old Ubuntu 7.10 an compile it with the old libraries (that's a backport).
Then you should make two (or more) .deb packages, one for Ubuntu 9.10 and one for Ubuntu 7.10.
Another possibility is to continue doing what you are doing now : set LD_LIBRARY_PATH to point to the desired version of libstdc++ and other necessary libraries. You just set this environment variable in a launcher shell script. In you script you check if the new libraries are available or not and you set your LB_LIBRARY_PATH (say to /usr/local/lib/myprogram/) only if needed. But as others poster pointed out : that's a very bad practice. Anyway, never try to put these provided libraries at their standard place in Ubuntu 9.10, you would risk broking the target system and causing update problems for users or your program if these libraries are officially backported someday.
But if you choose to include your own set of system libraries there is still another way to go than the above one: just link these libraries statically. If a program is the only user of a library as it will probably be in the above scenario you'll lose all advantages of using a shared dynamic library, then why bother with using it at all ? And with stacically linked libraries you won't have to install them.