Can I install both shared .so and static .a versions of a library? - linux

My questions is related to this: Creating both static and shared C++ libraries
I'm compiling a library in order to install it in ~/local on two different systems. It seems that every time I do this I end up with linker problems that take me hours to figure out. The specific library I'm looking at is primesieve. In that library, it's the default to build static libraries only. Unfortunately the example code count_primes.cpp wouldn't link with the static version of the library on one of my systems, for whatever reason. Eventually I figured out how to build the shared version and the code now compiles nicely, with no ugly hacks necessary.
Given the above, it seems to be that compiling both static and shared versions is a good idea if you're working with multiple systems and want the best chance of having your code compile. Is this true? Are there reasons not to build both versions? I realize that this is a bit of a subjective question but it's a serious programming issue that I think many people here have probably encountered.
PS.
This is what I ended up using to compile and install both shared and static versions of primesieve to ~/local:
make
make lib
make install PREFIX=~/local
make clean
make lib SHARED=yes
make install PREFIX=~/local
The make clean is because of this. I then added this to my .bash_profile:
export LIBRARY_PATH=$LIBRARY_PATH:~/local/lib
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:~/local/lib
export CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:~/local/include
Alternatively, without changing the environment variables I was able to compile the example program count_primes.cpp like this:
g++ -I ~/local/include/ -L ~/local/lib/ -lprimesieve count_primes.cpp

To use a static library you can just include it in the compilation as if it were a regular object file, e.g.
g++ -o foo foo.cpp /path/to/mylib.a
Of course, this means static linking too.
You can still statically link with a dynamic library, so there's not much use for static libraries really.

There is no reason not to build both. Neither library will "do" anything. The shared library will only be loaded if it is in a path viable to the dynamic linker (like you did by adding it to your LD library path). The static one won't be used unless you explicitly link against it - but that is only done at compile (link) time.

Related

Avoid dynamic linking in dependencies

I am developing a project against a custom linux and I am having troubles with dynamic dlls that are referenced by dependencies.
Is there a way to know if a dependency has dynamic linked libraries before hand? Is it possible to somehow avoid those libraries? I want to have a static binary (MUSL didn’t work for me as one dependency doesn’t compile with it).
Thanks
If you're compiling against glibc, you'll need to have at least some dynamic linking. While it is possible to statically link glibc, that isn't a supported configuration since the name service switch won't work in such a case.
In general, you should expect a build-dependency on cc or pkg-config to be an indicator of the use of a C or C++ library. That isn't a guarantee either way, but it is probably going to be the case the vast majority of the time. Some of those libraries will be able to be linked statically, but of course if you do that you must recompile your code every time any of your dependencies has a security update or you'll have a vulnerability. There's unfortunately no clear way to tell whether static linking is an option in such a case other than looking at the build.rs or the documentation of the crate.

How to compile with make but also include all dependencies

I'm compiling a C++ program on linux, and I can run make and it all compiles, but when I need to downgrade or change one of it's dependencies for another program, it breaks. I was wondering if it was possible to create a standalone executable, with dependencies bundled inside? There's not many dependencies, so size isn't an issue.
So, what you're asking is, can you link with static versions of libraries (which are included in the program directly) instead of dynamic versions of libraris (shared libraries) which are kept external to your program.
The answer is "yes", but it's not always straightforward. First you have to ensure you actually have the static versions of the libraries installed in your system: the static and dynamic libraries are different files and often the "standard" installation provides only the dynamic library.
If you're already compiling code against those libraries you probably already have the static libraries installed because, at least on GNU/Linux systems, the static libraries are often included in the "dev" packages along with the header files etc. needed to compile code.
To make this work you need to modify your linker command line. If you have a sufficiently new version of the binutils package (which provides the linker), you can change your link line to replace arguments like -lssl -lcrypto with arguments like -l:libssl.a -l:libcrypto.a (don't forget the colon after the -l) and that should do it.

In Ubuntu (14.04), is there an equivalent to /etc/ld.so.conf.d for the linker?

This is a question about centrally-located path specs, like PATH, LD_LIBRARY_PATH, and LIBRARY_PATH.
I know that there are two ways of specifying shared library paths for the loader: add them to LD_LIBRARY_PATH, or add files to /etc/ld.so.conf.d/. I also know that the latter is considered the more modern and preferred way to do it.
I also know that you can specify standard library paths for the linker by editing LIBRARY_PATH. Is this still the "modern" way to do it, or is there now a "ld.so.conf.d-style" alternative that I should be using?
EDIT: People are asking "why", so:
I'm using a Python package (Theano) that dynamically generates and compiles CUDA and C++ code when run. One of the libraries it links to is NVidia's cuDNN. I don't know why Theano's developer's have it link to the static lib and not the dynamic lib.
There isn't any equivalent to ld.so.conf.d/ for static libraries. You still just specify the standard linker search paths via the LIBRARY_PATH environment variable, and additional paths through command-line flags to the linker.
To be clear:
LIBRARY_PATH: Used by the linker at compile time. Is used by the linker to find both static and dynamic libraries.
LD_LIBRARY_PATH: Used by the loader at run time to find dynamic libraries.
static libraries are resolved at (static) link time and by definition don't have any runtime aspects.
My opinion is that you should avoid using static libraries and always prefer shared libraries.

How to statically-link a complex program

In Linux, downloaded a program source and want it to be statically linked.
Have a huge Makefile there,
I
./configure
make
to compile.
prehpes it's a bit too general to ask, but how can I make the binary statically linked?
EDIT: the reason for this is wanting to make sure the binary will
have no dependencies (or at least as few as possible), making it possible to run on any Linux based computer, even one without Internet connection, and non-updated Linux.
Most autoconf generated configure script will allow you to make a static build:
./configure --enable-static
make
If that doesn't work, you may be able to pass linker flags in via LDFLAGS, like this:
./configure LDFLAGS=-static
Yeah, you need to edit the make file and add the -static parameter to gcc during the link.
I assume it's using gcc to compile a series of c programs, although you will have to look in the Makefile to find out.
If so, you can adjust the gcc lines in the makefile to do static linking, although depending upon the structure of the program, this may be a complex change. Take a look at man gcc to see how this is done.
I'd be interested to know why you are statically linking. Have you considered using prelinking instead?
You should be aware that there may be licence problems to doing this if all components are not GPL.
If you cannot compile a static binary, I've had good results using Statifier.

Loading multiple shared libraries with different versions

I have an executable on Linux that loads libfoo.so.1 (that's a SONAME) as one of its dependencies (via another shared library). It also links to another system library, which, in turn, links to a system version, libfoo.so.2. As a result, both libfoo.so.1 and libfoo.so.2 are loaded during execution, and code that was supposed to call functions from library with version 1 ends up calling (binary-incompatible) functions from a newer system library with version 2, because some symbols stay the same. The result is usually stack smashing and a subsequent segfault.
Now, the library which links against the older version is a closed-source third-party library, and I can't control what version of libfoo it compiles against. Assuming that, the only other option left is rebuilding a bunch of system libraries that currently link with libfoo.so.2 to link with libfoo.so.1.
Is there any way to avoid replacing system libraries wiith local copies that link to older libfoo? Can I load both libraries and have the code calling correct version of symbols? So I need some special symbol-level versioning?
You may be able to do some version script tricks:
http://sunsite.ualberta.ca/Documentation/Gnu/binutils-2.9.1/html_node/ld_26.html
This may require that you write a wrapper around your lib that pulls in libfoo.so.1 that exports some symbols explicitly and masks all others as local. For example:
MYSYMS {
global:
foo1;
foo2;
local:
*;
};
and use this when you link that wrapper like:
gcc -shared -Wl,--version-script,mysyms.map -o mylib wrapper.o -lfoo -L/path/to/foo.so.1
This should make libfoo.so.1's symbols local to the wrapper and not available to the main exe.
I can only come up with a work-around. Which would be to statically link a version of the "system library" that you are using. For your static build, you could make it link against the same old version as the third-party library. Given that it does not rely on the newer version...
Perhaps it is also possible to avoid these problems with not linking to the third-party library the ordinary way. Instead, your program could load it at execution time. Perhaps then it could be shadowed against the rest. But I don't know much about that.

Resources