How to prefer one library location vs. another one with Clang? - c++

I have a system-wide libc++.so in /usr/lib64. I want to link my binary against another libc++.so which is located somewhere else, say, in $HOME/.local/lib. Also, I want to be able to find all other libraries the same way as before, assuming that $HOME/.local/lib contains only libc++.so.
I'm trying to do this like: clang++ -L$HOME/.local/lib -lc++, but the compiler still links against /usr/lib64/libc++.so.
How to force the compiler (or linker) to link against a specific library location?

-L adds the directory to the search path used by the linker. This has no effect on the search paths used at runtime. At runtime, the search paths, in order, are:
The environment variable LD_LIBRARY_PATH
rpath specified in the executable
System library path
While you can achieve what you want by specifying the environment variable LD_LIBRARY_PATH=$HOME/.local/lib, it is a bad solution since it modifies the search paths of all executables. Specifying the rpath is a much cleaner solution since it only affects the behaviour of your executable. You can do this through the linker option of your toolchain, which is likely -rpath. So the command would be clang++ -rpath $HOME/.local/lib -lc++.

Related

Load .so from directory relative to loading executable

For various reasons mostly to do with inertia, we don't have a make install target.
Rather, we build our large C++ codebase directly into an FHS-like tree;
output/
bin/
lib/
etc/
...
We've recently switched some third-party libraries to dynamic linking, and so we push a number of .so libraries into lib/.
Now, we're used to being able to just launch our executables from bin/, but that no longer works because the loader doesn't search our lib/ directory.
LD_LIBRARY_PATH would solve this, but we would prefer not to have to provide it before every single executable invocation, and we don't want to stick it in the shell's environment, because we typically switch between a number of different build trees in the same shell.
We've considered adding an rpath entry in the generated ELF, but relative paths are typically resolved against $PWD, not the executable's dirname.
Is there a way to nudge the loader to look in dirname(argv[0])/../lib for .so libs?
Basically, I understand that there are lots of ways we can change our habits to make this work (and probably should), but we prefer not to at this point, so can we coerce the Linux so loader to do what we want? Thanks!
Yes, it is possible using rpath and ${ORIGIN} macro, which is recognized by ld.so at runtime.
From man ld.so:
ld.so understands certain strings in an rpath specification
(DT_RPATH or DT_RUNPATH); those strings are substituted as follows
$ORIGIN (or equivalently ${ORIGIN})
This expands to the directory containing the application executable.
More variables are available. You don't need to coerce the loader to anything. It has the feature for you. :)

Where does the linker get library names?

I'm kind of new to developing, and I am wondering how the linker is getting the library names?
for example, in the linker additions lines, when i wanted to add support for libxml2, the command was -lxml2. yet when i wanted to add the lib for xmlsec, it was -lxmlsec1. when i wanted to add openssl, i needed both a -lcrypto and a -lssl.
can someone explain to me where these library names come from? it doesn't seem very intuitive. if i want to include a library, how am i supposed to find what -l command to use?
this is on a ubuntu system developing a C++ program.
The 'regular' linker is dumbest program I know of :) When it comes for libraries, it follows a very simple set of rules. First, for every -l rule it adds lib in front and .a in the end to form a static library name. It also forms a dynamic library name by adding .so instead of .a. For every -I rule it adds specified path to it's library search paths.
So when it sees a -l rule, and looks into all library paths which were set by -L rules (in the order those appeared in the command line) and sees if it can find dynamic or static library at this location (if it can see both, it picks one depending on -B rule).
This was a generic introduction. Now, to your particular question, in order to check which library you should include, you should read documentation. I always tells you which -l rules you'd need.

how to link shared library from non existing(in compile time) folder

i'm trying to link shared library to another shared library(protobuf) with -rpath option, the problem is that the lib is in another direcory in compile time than in runtime, and -rpath option requires an existing in compile time path. (so i get an "No such file or directory" error)
Is there any workaround for that?
I would rather not to use LD_LIBRARY_PATH variable to solve this problem.
-rpath specifies the runtime library search path.
Here is a quoate from the link Program Library HOWTO
"
During development, there's the potential problem of modifying a library that's also used by many other programs -- and you don't want the other programs to use the developmental''library, only a particular application that you're testing against it. One link option you might use is ld'srpath'' option, which specifies the runtime library search path of that particular program being compiled. From gcc, you can invoke the rpath option by specifying it this way:
-Wl,-rpath,$(DEFAULT_LIB_INSTALL_PATH)
If you use this option when building the library client program, you don't need to bother with LD_LIBRARY_PATH (described next) other than to ensure it's not conflicting, or using other techniques to hide the library. "
I found an answer here Can I change 'rpath' in an already compiled binary?
Changing rpath after compilation solves my problem.
[edited]
There is another, better approach: how to link to shared lib from shared lib with relative path

c_include_path vs ld_library_path

On either Ubunutu 12.04 or Springdale 6.4, using gcc and g++, what's the difference between C_INCLUDE_PATH (or CPLUS_INCLUDE_PATH) and LD_LIBRARY_PATH? Is the LD one only used at run-time, and the other two only at compile-time?
Since the INCLUDE and LIBRARY_PATH environment variables seem to be ignored by GCC on these operating systems, which should I set when constructing my ~/.bashrc file to make it as portable as possible (modulo changes in the actual paths) across modern Linux OSes?
LD_LIBRARY_PATH is an environment variable which tells in which directories the dll loader should look for dynamic libraries when you start an executable. The variable is dangerous and deprecated
LIBRARY_PATH - tells linker where too look for libraries while building exe or lib
INCLUDE_PATH - tells where to look for files referred in #include statements
In any case, LIBRARY_PATH and INCLUDE_PATH should be set in a particular build-system, not in bashrc. The easier a script can build c-sources, the more probable your PC may be infected with a rootkit.
BTW: gcc is a wrapper which invokes a proper compiler (e.g. cc or g++) and linker.
g++ is gnu c++ compiler
EDIT
Explanation, why LD_LIBRARY_PATH is dangerous.
I haven't used Linux for a couple of years and I wonder, that this env-variable is still in current distributions. It was considered as deprecated when I was using Linux (around 2006) as it provides very easy to exploit hook.
The problem with it is, it prescribes the order of path's in which ld.so - dynamic linker looks for required libraries. If LD_LIBRARY_PATH contained a writable directory, a hacker (in new speech a cybercriminal) could place in that directory a library with a name likely to be found in a system directory (e.g. /usr/lib). This library could first do any dirty job and then call the original library. Exploiting LD_LIBRARY_PATH is much easier then compromising binaries in system directories. And also such an exploit is hard to detect.

Linux C++ linker /usr/bin/ld

I wrote a small application on Redhat Linux 6 using g++ 4.4.6. After compilation, I received an error
/usr/bin/ld: cannot find -lcrypto
I did a search for the crypto library and find them here,
[root#STL-DUNKEL01 bin]# find / -name libcrypto*
/usr/lib64/libcrypto.so.0.9.8e
/usr/lib64/libcrypto.so.10
/usr/lib64/libcrypto.so.6
/usr/lib64/libcrypto.so.1.0.0
My question is whether the compilation error is caused by /usr/bin/ld not having /usr/lib64/ in the search path? If yes, how can I add it?
Thanks.
No, you have likely incorrectly diagnosed the cause.
You need a libcrypto.so to link against. This is usually a symlink to one of the actual libraries, whose soname (libcrypto.so.??) will be embedded into the binary. Only that library is needed at runtime, but the symlink is necessary to compile.
See Diego E. Pettenò: Linkers and names for more details.
You have to add -L/usr/lib64 when calling gcc or ld.
Note, you can specify LD_LIBRARY_PATH as well/instead, but it is considered harmful to do so. (The link mentions Solaris specifically, but the issues apply to other OSs as well.)
Quote:
LD_LIBRARY_PATH is used in preference to any run time or default system linker path. If (God forbid) you had it set to something like /dcs/spod/baduser/lib, if there was a hacked version of libc in that directory (for example) your account could be compromised. It is for this reason that set-uid programs completely ignore LD_LIBRARY_PATH.
When code is compiled and depends on this to work, it can cause confusion where different versions of a library are installed in different directories, for example there is a libtiff in /usr/openwin/lib and /usr/local/lib. In this case, the former library is an older one used by some programs that come with Solaris.
Sometimes when using precompiled binaries they may have been built with 3rd party libraries in specific locations; ideally code should either ship with the libraries and install into a certain location or link the code as a pre-installation step. Solaris 7 introduces $ORIGIN which allows for a relative library location to be specified at run time (see the Solaris Linker and Libraries Guide). The alternative is to set LD_LIBRARY_PATH on a per-program basis, either as a wrapper program to the real program or a shell alias. Note however, that LD_LIBRARY_PATH may be inherited by programs called by the wrapped one ...
Add the directory to /etc/ld.so.conf
then run "sudo ldconfig" to make the changes take effect.
You can provide the directories to search for the libraries in as a parameter to gcc like so -L<directory_to_search_in>. And note that there can be multiple parameters to -L. Also, are you trying to build a 32-bit application or a 64-bit one?