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 toNULL
.
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
Splitting a File in Linux Based on Content
Why Is Rcx Not Used for Passing Parameters to System Calls, Being Replaced with R10
How to Script a "Yes" Response for Installing Programs
How Find Out Which Process Is Using a File in Linux
How to Determine If a Detached Pthread Is Alive
Init Function Invocation of Drivers Compiled into Kernel
How to Run Crontab Job Every Week on Sunday
Converting Serial Port Data to Tcp/Ip in a Linux Environment
How to Get Amount of Queued Data for Udp Socket
Changing Environment Variable of a Running Process
Bash: Integer Expression Expected
Unix - Create Path of Folders and File
Difference Between Arm-Eabi Arm-Gnueabi and Gnueabi-Hf Compilers