Library Path When Dynamically Loaded

library path when dynamically loaded?

The dynamic linker actually searches several places to find each dynamic library. These include (from man ld.so):

  • Paths given by the environment variable LD_LIBRARY_PATH
  • Paths baked into the binary load the library under the DT_RUNPATH entry
  • The cache file /etc/ld.so.cache
  • /lib and /usr/lib

If you want to get the path for a specific shared library, I would recommend the dladdr function. From the man page:

The function dladdr() takes a function pointer and tries to resolve
name and file where it is located. Information is stored in the
Dl_info structure:

typedef struct {
const char *dli_fname; /* Pathname of shared object that
contains address */
void *dli_fbase; /* Address at which shared object
is loaded */
const char *dli_sname; /* Name of nearest symbol with address
lower than addr */
void *dli_saddr; /* Exact address of symbol named
in dli_sname */
} Dl_info;

If no symbol matching addr could be found, then dli_sname and
dli_saddr are set to NULL.

dladdr() returns 0 on error, and non-zero on success.

So you just give it a function pointer, and it will give you the name of the file which supplies it and a bunch of other information. So for instance, you could have a constructor in a library call this on itself to find out the full path of the library:

#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>

__attribute__((constructor))
void on_load(void) {
Dl_info dl_info;
dladdr((void *)on_load, &dl_info);
fprintf(stderr, "module %s loaded\n", dl_info.dli_fname);
}

This function also works on OS X with the same semantics.

How to specify (non-R) library path for dynamic library loading in R?

Normally, the iconv method is picked up from glibc, which is linked to during build of the R packages in question. For whatever reason, however, iconv is getting resolved to libiconv in this case, but it is not linked by the R packages during build.

Original Workaround

One can make the linking to libiconv explicit by adding the following line to the haven/src/Makevars source file

PKG_LIBS=-liconv

which then let's you install from source R CMD INSTALL haven. However, editing packages feels hacky, plus this is something that will need to be done every upgrade, which sounds like a hassle.

Cleaner Workaround

Another option is to use withr::with_makevars, which allows one to temporarily control Makevars content. With this technique, one can install directly from the repo:

withr::with_makevars(c(PKG_LIBS="-liconv"), install.packages("haven"), assignment="+=")

Credit: @knb suggested that I inspect the readxl.so with ldd and this turned out to be super useful because it showed that the shared object wasn't even trying to link to libiconv. Knowing that, I realized I could manually add the reference via the -liconv flag. Thanks @knb!

Additional Info

On the package side of things, relevant details about connecting libraries to R packages can be found in the guide for building libraries. On the system configuration side, the R-admin guide has some useful sections.

How program interpreter locates the full path of dynamic libraries to be loaded?

The dynamic library loader have a fixed set of paths that it uses to search for libraries. If you have a custom library which isn't in that set then the library won't be found and you get an error.

Unfortunately the linker doesn't automatically add the path to the libraries it links with by default to the finished executable. Instead you must specify a special option to add the path: -rpath.

You can't use -rpath directly with the gcc front-end program, it's a linker-specific option. You need to use the -Wl option:

$ gcc prog.c -L. -l dtest -Wl,-rpath=$PWD

If the library is or will be installed in some directory other than $PWD, then you need to provide the actual (full) path to the installation directory.


Other possible solution includes adding the path to the set the dynamic loader uses (not recommended for uncommon paths), or setting the LD_LIBRARY_PATH environment variable (which is not recommended at all).

How to use a dynamically linked library from relative path

I was able to solve the issue adding the -Wl,-rpath=\$ORIGIN/lib linker flag to LDFLAGS options in the main.go file:

package main
/*
#cgo CFLAGS: -I${SRCDIR}/lib
#cgo LDFLAGS: -L${SRCDIR}/lib -Wl,-rpath=\$ORIGIN/lib -luiohook
#include <uiohook.h>
*/
import "C"

func main() {
C.hook_run()
}

Now when the application is executed, it uses also the CURRENT_FOLDER/lib to search for dynamic libraries (CURRENT_FOLDER is the directory where the application executable is executed).

For linux users only:
If the error is still thrown, you need to create a symlink or to rename the XXX.so library to XXX.so.0. In my case it was:

src/ctest/
|- lib/
| |- libmylib.so
| |- libmylib.so.0 <- symlink to ./libmylib.so
| |- libmylib.h
|- main.go


Related Topics



Leave a reply



Submit