I have CentOS 6.2 (64bit with gcc 4.4.6 as default). Unfortunately, my code only compiles with gcc 3.4.6, so I installed gcc separately (from source) under /home/rajat/local. On linking a simple "Hello World" program, I get the following.
>ldd a.out
linux-vdso.so.1 => (0x00007fff215ff000)
libstdc++.so.6 => /home/rajat/local/lib64/libstdc++.so.6 (0x00007f11853e7000)
libm.so.6 => /lib64/libm.so.6 (0x00000033be400000)
libgcc_s.so.1 => /home/rajat/local/lib64/libgcc_s.so.1 (0x00007f11851ce000)
libc.so.6 => /lib64/libc.so.6 (0x00000033bd000000)
/lib64/ld-linux-x86-64.so.2 (0x00000033bcc00000)
While stdc++ and gcc link to my 3.4.6 libraries, libm and libc still link to default libraries. Is this OK?? The 3.4.6 installation also did not produce libm or libc libraries?
Yes, that's ok.
The libc/libm is part of glibc, not the gcc compiler. libstdc++ on the other hand ls part of gcc.
Libraries in /lib and /usr/lib as well as their 64-bit counterparts are system-wide libraries. They are supposed to be compiler neutral and other compilers besides GCC can also link to them and they actually do, especially since libc is the only portable way to interface with the operating system kernel.
libc writers take great care of writing their header files in such a way as to make different compilers produce the same binary memory objects in order to properly interface with the code in the library. Besides, there is a well-defined OS ABI interface that all compilers adhere to in order to be compatible with one another. This might not be true for languages other than C, e.g. object files from different C++ compiler versions rarely go well with one another.
Compiler-specific libraries are not installed in /lib or /usr/lib and sometimes can be linked statically so that the dependency can be removed.
Related
question
How can I compile a shared library linking with version-independent boost shared library?
My cmakelists.txt is like as follows
find_package(Boost REQUIRED COMPONENTS serialization)
...
target_link_libraries(_omplpy PRIVATE ${Boost_LIBRARIES} ${otherdeps})
And, after compiling this, I checked dependency by ldd command and it shows that only the dependency of boost libraries are too specific (seems that version 1.71.0 is specified, though other libraries does not care about the minor version)
h-ishida#stone-jsk:~/python/ompl-python-thin$ ldd build/_omplpy.cpython-38-x86_64-linux-gnu.so
linux-vdso.so.1 (0x00007ffd34ca9000)
libboost_serialization.so.1.71.0 => /lib/x86_64-linux-gnu/libboost_serialization.so.1.71.0 (0x00007f208012f000)
libboost_filesystem.so.1.71.0 => /lib/x86_64-linux-gnu/libboost_filesystem.so.1.71.0 (0x00007f2080111000)
distir libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f20800ee000)
libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f207ff0c000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f207fdbd000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f207fda0000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f207fbae000)
/lib64/ld-linux-x86-64.so.2 (0x00007f20812a6000)
The problem is, boost libraries version are different for different ubuntu distributions, thus my compiled shard library _omplpy cannot be used in different distribution.
context (maybe unrelated)
I am trying to distribute a python package where a shared library linked with boost stuff is inside. Because python wheel (binary version of package) is only python-version (like 2.7, 3.8), os (mac, windows, ldistirinux), and archtecture dependent (like x86_64, aarch64), it seems impossible to distribute packages dependent on specific ubuntu distribution. For your information, the package mentioned is https://github.com/HiroIshida/ompl-thin-python and corresponding CMakeLists.txt is here https://github.com/HiroIshida/ompl-thin-python/blob/master/CMakeLists.txt
How can I compile a shared library linking with version-independent boost shared library?
You can't, because the different boost libraries are not ABI-compatible. If you somehow succeeded in linking your library with "version-independent boost", the result would be a runtime crash.
Read about the reasons for external library versioning here.
P.S.
I decided to build static boost library with -fPIC option and compile the target library with linking that.
That is much easier, but unless you are very careful with symbol hiding, this approach will cause runtime crashes (if you are lucky) as soon as someone tries to use your python package in program which uses a different version of boost libraries (due to symbol collision and ABI incompatibility). And if you are unlucky, symbol collision may cause other very hard to find bugs.
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.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I know that on Windows, you get some libraries linked in by default to your process- like kernel32.dll, etc. Are there any equivalent libraries on Linux?
I am creating some Linux binaries and looking for support routines, especially malloc, etc. On Windows I simply implemented malloc() on top of HeapAlloc (which is also the approach taken by the VS CRT) but I'm not sure what to do here. For reasons, I'm not going to link to libc when creating the binary if at all possible.
By default, G++ in Linux will link against the C standard library and C++ standard library. Occasionally it will also bring in the math library automatically, although historically you need to ask for that with -lm.
On my Ubuntu box, I compiled and linked the following simple "Hello World" app:
#include <iostream>
int main()
{
std::cout << "Hello world!" << std::endl;
}
I compiled it as follows: g++ hello.cpp
The ldd utility lists the libraries g++ linked this against:
$ ldd a.out
linux-vdso.so.1 => (0x00007fff1d344000)
libstdc++.so.6 => /usr/local/lib64/libstdc++.so.6 (0x00007fd7fb031000)
libm.so.6 => /lib/libm.so.6 (0x00007fd7fadae000)
libgcc_s.so.1 => /usr/local/lib64/libgcc_s.so.1 (0x00007fd7fab97000)
libc.so.6 => /lib/libc.so.6 (0x00007fd7fa813000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd7fb365000)
The first line, linux-vdso.so.1 isn't actually a library. Google it if you want to learn about some magic hackery. The rest are pretty pedestrian:
libstdc++ is the C++ standard library
libm is the aforementioned math library. I don't know if C++ includes it by default, but historically the C compiler did not include it unless you specified -lm at link time.
libgcc_s is a GCC-specific support library, containing various support routines (ie. for oddball things like oddball divides, structure-copies, etc.)
libc is the C standard library. It also contains a lot of POSIX functionality.
ld-linux-x86-64 is the dynamic library loader. This is actually an executable.
So, that's the default bit of kit.
Pieces such as malloc, new, printf, etc. are all in there, along with the full C++ standard library (what some call the "STL").
If you're asking what support comes by default, this is it. If you're trying to implement your own versions of these things... the -nodefaultlibs flag will let you. You might also need -ffreestanding and maybe even -fno-builtins.
If you want to see how these pieces are built (including how glibc calls mmap and/or sbrk to get memory to populate a malloc heap), you can download the source for glibc and take a look. There isn't a level below glibc you can target directly other than making system calls directly.
Assuming you're building your code with GCC / G++, you may need to include some of these libraries, such as libgcc_s and libstdc++. You might be able to limit / eliminate your dependence on libstdc++ if you refrain from using standard library functions, and build with -ffreestanding. But, I'll be honest: I only know of the flag, I've never used it.
I think you want some lower level API for memory management. Then this question might help you.
It suggests mmap function. It hope it might help you.
According to ldd The following libraries are linked by default with g++ 4.8 on my ubuntu linux machine for basic c++ programs.
linux-vdso.so.1 => (0x00007fffe11fe000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f1d1e49b000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f1d1e285000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1d1debc000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f1d1dbb8000)
/lib64/ld-linux-x86-64.so.2 (0x00007f1d1e7c7000)
You can disable linking them using -nodefaultlibs switch but you also need to specify that they need to be linked later using the appropriate switches.
On Linux, glibc is equivalent of a lot of stuff in the Windows libraries. The POSIX C interface functions, including the C standard library and also the kernel system call wrappers are all in libc. It is the primary wrapper layer providing ABI compatibility between various kernel versions. Not using it is very stupid.
The Windows CRT indeed has a different status, because POSIX has a different status on Windows. Where the Win32 API provides the OS interface on Windows, it is POSIX (including the C stdlib!) on Linux.
When on Linux, link glibc.
You will also need to link some compiler support library, be it LLVM's compiler-rt or GCC's libgcc.
A while back, I decided to upgrade to GCC 4.8 in order to get an early start on some c++11 features. I got a bit sidetracked, though, and didn't really put any of the new features to use until a project a few days ago (the new compiler seemed to have been working fine, but it may just be because I wasn't utilizing any new functionality.)
In this new project, when I compiled with the =std=c++11 flag, I had no problems. However, at runtime, I get the error:
./main: /usr/lib/i386-linux-gnu/libstdc++.so.6: versionGLIBCXX_3.4.18' not found (required by ./main)`
I assume that there is a problem linking to a more modern libstdc++ library associated with GCC 4.8, but I can't for the life of me figure out how to fix this or where the appropriate library should be. I remember symbolically linking the g++ and gcc binaries to gcc-4.8, which appears to be working, since g++ -v returns:
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/app/gcc/4.8.0/libexec/gcc/i686-pc-linux-gnu/4.8.0/lto-wrapper
Target: i686-pc-linux-gnu
Configured with: ./gcc-4.8.0/configure --prefix=/app/gcc/4.8.0
Thread model: posix
gcc version 4.8.0 (GCC)
Another thread online led me to look at the ldd output for the program, which did show me that the directory structure for the libstdc++ libraries being linked to was different than the directory structure for the binaries. I couldn't, however, find the appropriate libstdc++ libraries in the latter, so I'm not sure where to look. The output for ldd main is:
./main: /usr/lib/i386-linux-gnu/libstdc++.so.6: versionGLIBCXX_3.4.18' not found (required by ./main)
linux-gate.so.1 => (0xb7791000)
libstdc++.so.6 => /usr/lib/i386-linux-gnu/libstdc++.so.6 (0xb768e000)
libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0xb7662000)
libgcc_s.so.1 => /lib/i386-linux-gnu/libgcc_s.so.1 (0xb7644000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb749b000)
/lib/ld-linux.so.2 (0xb7792000)`
I'm not sure exactly where this is going wrong, and I'll continue Googling and looking around for answers, but any help you guys could offer would be greatly appreciated. If anything is unclear about the issue or I forgot some information, just let me know and I'll try to add that in. Thanks so much!
You need to tell your dynamic linker (it's executed when you run your program) where to find the library. Set LD_LIBRARY_PATH to the path of the library (probably somewhere under /app/gcc/4.8.0/lib or something).
Use find /app/gcc/4.8.0 -name "libstdc++.so.6". Add the directory to your LD_LIBRARY_PATH. e.g with the path I mentioned:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/app/gcc/4.8.0/lib (if you're using a bourne-like shell which the default on Linux).
Then try to run your program.
If it works, you'll probably want to configure your dynamic linker to look in the directory without using LD_LIBRARY_PATH. See man ld.so for details about how to configure the path.
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).