RPATH equivalent for executables - c++

I have a c++ shared library which as part of its normal behaviour fork()/execs() another executable containing some unstable legacy code. This executable is not useful other than with this library, so I'd like to avoid placing it in a PATH directory. I'd also like to be able to install multiple copies in various locations, so hard coded paths are not desirable. Is there anything equivalent to a RPATH that will allow exec() to find this executable? Alternatively, is it possible to query the rpath of a shared library from the library itself?
Edit: This post suggests the latter is possible. I'll leave this open in case anybody knows the answer to the asked question. Is there a way to inspect the current rpath on Linux?

You can always use getenv to get the environment within the shared object, but is RPATH really what you want to use for that? Wouldn't it be better to have the shared object have some sort of configuration file in the user's home directory (or custom environment variable) that tells it which location to use run the external binary?

I think the best way to do this is to set an environment variable and use execve() to run the binary. Presumably you could just set PATH and then execve() a shell that would use PATH to find a copy of the executable. The library equivalent would be to set LD_LIBRARY_PATH and execve() a binary that has this library as a dependency.
In either case, you are not changing the external environment, only manufacturing a modified copy that is used with execve().

Related

Setting environment variables for run-time in compile-time

I have a C++ Vulkan program that needs multiples libraries to be available at run-time. Also, Vulkan has a feature called "Validation Layers" which is configured with a config file.
In run-time my program needs to know where those libraries are and where that config file is. I'm guessing there's no way of doing it programmatically, but if there is let me know. To workaround this I set environment variables, namely LD_LIBRARY_PATH (for it to find the libraries) and VK_LAYER_PATH (for it to find Vulkan's Validation Layer config file).
This works, but I want a better way to do this, because this doesn't allow me to simply double-click the file and run it. I must first set the env vars, which is bad if I'm deploying the program.
My question is: is there a compiler/linker option to do this?
This is the workaround I'm using in my makefile:
run:
LD_LIBRARY_PATH=./path/to/lib1/:./path/to/lib2 VK_LAYER_PATH=./path/to/vulkan/config ./program_name
I am using Linux, g++ and make.
If you know where the libraries you need to link against will be installed you could set an rpath. This will add the search path to the ELF header. When the dynamic linker runs it will search these locations in addition to the default locations.
Add to your compilation line -Wl,-rpath ./path/to/lib1/ to drop lib1 from the LD_LIBRARY_PRELOAD list. The -Wl is needed so the the compiler passes the flag onto the linker where it is actually recognized.
This blog seems to have a good description of all the different options

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. :)

Linking and Add Executable on CMAKE?

I am learning CMAKE and the example I have has both link_directories before and after add_executable. My question is: how does the process work? Which is supposed to go first and what is the purpose of one going before the other?
Not sure if this order matter. Probably not. "link_directories" will tell the compiler where to look for the libraries you desire to use. The names of the libraries you put in "target_link_libraries" command.
Actually, with CMake, "link_directories" is not used too often. Usually you use a module script to find your libraries with "find_package" (e.g., findCUDA, findJPEG, etc...) and pass to "target_link_libraries" the variables defined by these scripts containing the full path of each library.

Load shared library by path at runtime

I am building a Java application that uses a shared library written in C++ and compiled for different operating systems. The problem is, that this shared library itself depends on an additional library it normally finds under the appropriate environment variable (PATH, LIBRARY_PATH or LD_LIBRARY_PATH).
I can - but don't want to - set these environment variables. I'd rather load the needed shared libraries from a given path at runtime - just like a plugin. And no - I don't want any starter application that starts a new process with a new environment. Does anybody know how to achieve this?
I know that this must be possible, as one of the libraries I use is capable of loading its plugins from a given path. Of course I'd prefer platform independent code, but if this ain't possible, seperate solutions for Windows, Linux and MacOS would also do it.
EDIT
I should have mentioned that the shared library I'd wish to use is object oriented, which means that a binding of single functions won't do it.
Un UNIX/Linux systems you can use dlopen. The issue then is you have to fetch all symbols you need via dlsym
Simple example:
typedef int (*some_func)(char *param);
void *myso = dlopen("/path/to/my.so", RTLD_NOW);
some_func *func = dlsym(myso, "function_name_to_fetch");
func("foo");
dlclose(myso);
Will load the .so and execute function_name_to_fetch() from in there. See the man page dlopen(1) for more.
On Windows, you can use LoadLibrary, and on Linux, dlopen. The APIs are extremely similar and can load a so/dll directly by providing the full path. That works if it is a run-time dependency (after loading, you "link" by calling GetProcAddress/dlsym.)
I concur with the other posters about the use of dlopen and LoadLibrary. The libltdl gives you a platform-independent interface to these functions.
I do not think you can do it for it.
Most Dlls have some sort of init() function that must be called after it have been loaded, and sometime that init() function needs some parameters and returns some handle to be used to call the dll's functions. Do you know the definition of the additional library?
Then, the first library can not simply look if the DLL X is in RAM only by using its name. The one it needs can be in a different directory or a different build/version. The OS will recognize the library if the full path is the same than another one already loaded and it will share it instead of loading it a second time.
The other library can load its plugins from another path because it written to not depend on PATH and they are his own plugins.
Have you try to update the process's environment variables from the code before loading the Dll? That will not depends on a starter process.

How to change the library include path of a binary from bash?

I have a software properly installed on Kubuntu.
Now, I am patching and testing some of its libraries.
How can I start the software from bash so that it loads my patched libraries instead of the official libs?
e.g.:
the official libs are locate in /usr/lib/
my patch libraries (used during test development) are in /home/user/dev/lib/
I tried:
$ set LD_LIBRARY_PATH=/home/user/dev/lib/
$ binary_app &
but to no avail.
I'd prefer a solution that can be set from the bash, but if it's not possible, I could also modify the cmake file of this C++ software.
The aim is to allow me to easily start the application either with the vanilla libs, or with my patched libs to see the differences.
Edit: it's a KDE .so file
The library I am testing is a KDE4 library. The official lib is in /usr/lib/kde4/ . In that directory, none of the library start with the lib prefix.
Whether I do:
/lib/ld-linux-x86-64.so.2 --list --library-path PATH EXEC
or
ldd EXEC
The library is not listed at all.
On the other hand, if if move the original library away from /usr/lib/kde4/, the application starts but the corresponding functionality is missing.
Are KDE4 libraries loaded in a specific way? Maybe the variable to set is different...
Edit 2
All the answers are good and useful... unfortunately, it turned out that the problem does not appear to be related to the lib path setting. I'm dealing with a plugin architecture and the .so loading path appears to be hard-coded somewhere in the application. I need to spend more time within the source code to understand what's happening... Thanks and +1 to all.
From 'man bash':
When a simple command other than a builtin or shell function is to
be executed, it is invoked in a
separate execution environment that
consists of the following. Unless
otherwise noted, the values are
inherited from the shell.
[....]
ยท shell variables and functions marked for export, along
with variables exported for the
command, passed in the environment
You need to 'export' a variable if it is to be seen by programs you execute.
However, you can also try the following:
/lib/ld-linux.so.2 --library-path PATH EXECUTABLE
See http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html
Try export LD_LIBRARY_PATH=... instead of set.
I already put this in a comment but after thinking about it I think the best way to do this (using a different library just for testing/debugging) is using LD_PRELOAD, see What is the LD_PRELOAD trick?
From the man page:
LD_PRELOAD
A whitespace-separated list of additional, user-specified, ELF shared libraries to be loaded before all others. This can be used to selectively override functions in other shared libraries. For set-user-ID/set-group-ID ELF binaries, only libraries in the standard search directories that are also set-user-ID will be loaded.
Update:
After the updated question it seems the application is using dlopen to open the library using a absolute path. I don't think you can do anything about it. See man dlopen
Update2:
Maybe there is something you can do: you might be able to LD_PRELOAD your own dlopen function which modifies the path to your own library...
Isn't you app setuid or setgid by chance? In this case LD_LIBRARY_PATH will be ignored.
Put everything on one line:
LD_LIBRARY_PATH=foo binary_app&