How to set RPATH and RUNPATH with GCC/LD?
Is there a way to force the old behavior?
Yes. You can use this option -Wl,--disable-new-dtags
to tell the new linker to use the old behavior, i.e. RPATH.
Is it possible to tell the old version of linker to produce the new output (i.e. RUNPATH instead of RPATH)?
Yes. Use -Wl,--enable-new-dtags
to tell the old linker to use the new behavior, i.e. RUNPATH.
I verified the executable with readelf
and these two options seem to control what will be written in the ELF Dynamic section. I think the problem was caused by a change in the defaults for the new version, although, interestingly, the manual page for ld
would suggest that it should still be the same:
--enable-new-dtags
--disable-new-dtags
This linker can create the new dynamic tags in ELF. But the older ELF systems may not understand them. If you specify
--enable-new-dtags, the new dynamic tags will be created as needed and
older dynamic tags will be omitted. If you specify --disable-new-dtags, no new dynamic tags will be created. By default, the new dynamic tags are not created. Note that those options are
only available for ELF systems.
Can I change 'rpath' in an already compiled binary?
There is a tool called chrpath
which can do this - it's probably available in your distribution's packages.
How do I set DT_RPATH or DT_RUNPATH?
When you are compiling a program, you create object files and then link them together. You may use GNU ld(1) to link them, there are also other linkers, LLVM linker. A linker combines object files into executable. GNU ld(1) is part of binutils with documentation available here.
When you execute an already compiled ready to use executable then the dynamic linker ld.so(8) finds the libraries on the system that the executable depends on, loads them and executes the executable. ld.so(8) is a shared library usually distributed as part of C standard library, usually on linux that's glibc, but there are also other, like musl.
I think it's confusing that both these programs are named "linker". One is like "compiling linker" and the other is "executable linker".
How do I set DT_RPATH or DT_RUNPATH?
Edit the elf file to include specific section.
When creating the elf file with GNU ld, nowadays you set RUNPATH section with -rpath=something
. You can set RPATH
section with --disable-new-dtags -rpath=something
. RPATH is deprecated, so normally -rpath
sets RUNPATH. https://www.javaer101.com/en/article/1127068.html *This does not check out on my system and I have to compile with gcc -Wl,--enable-new-dtags -Wl,-rpath=/tmp
to set RUNPATH...
You can also set sections in any ELF file after compilation. See Can I change 'rpath' in an already compiled binary?
whether they are the same as -rpath and -rpath-link?
From ld documentation:
The difference between -rpath and -rpath-link is that directories specified by -rpath options are included in the executable and used at runtime, whereas the -rpath-link option is only effective at link time.
And the documentation also explains how -rpath-link
works. It's to specify directories for searching dependent shared libraries.
Finally there is an LD_RUN_PATH environment variable
When compiling an executable GNU ld(1) also searches libraries in directories specified in this variable.
Xcode does not set Runpath Search Paths to binary
I found the solution meanwhile.
I did not add it to Debug or Release in the "Runpath Search Paths" settings. I added it to the "Any architecture" setting which obviously was ignored. After setting it to Debug / Release it worked fine. Maybe it helps someone.
use RPATH but not RUNPATH?
When you ship a binary, it's good to provide means for the users to accommodate the binary to the specifics of their own system, among other things, adjusting library search paths.
A user can generally tweak LD_LIBRARY_PATH
and /etc/ld.so.conf
, both of which are with lower precedence than DT_RPATH
, i.e. you can't override what is hardcoded in the binary, whereas if you use DT_RUNPATH
instead, a user can override it with LD_LIBRARY_PATH
.
(FWIW, I think ld.so.conf
should also take precedence over DT_RUNPATH
, but, anyway, at least we've got LD_LIBRARY_PATH
).
Also, I strongly disagree with the suggestion above to use DT_RPATH
. IMO, its best to use nether DT_RPATH
not DT_RUNPATH
in shipped binaries.
unless
you ship all your dependent libraries with your executables and wish to ensure that things JustWork(tm) after installation, in this case use DT_RPATH
.
How can I set an executable's rpath and check its value after building it?
If I didnt miss something here, you are not linking any libs in your build command.
Lets say you want to link libusb.so shared library, which is located in libusb sub-folder of your current folder where is main.cpp.
I will not take any details here, about soname, linkname of lib etc, just to make clear about rpath.
rpath will provide runtime linker path to library, not for linktime, cause even shared library need to be present(accessible) in compile/link time. So, to provide your application loader with possibility to look for needed library in start time, relatively to your app folder, there is $ORIGIN variable, you can see it with readelf but only if you link some library with $ORIGIN in rpath.
Here is example based on your question:
g++ main.cpp -o main -L./libusb -Wl,-rpath,'$ORIGIN/libusb' -lusb
As you see, you need to provide -L directory for compile/link time search, and rpath for runtime linker. Now you will be able to examin all needed libs for your app using readelf and location for search.
libraries which exist in a binary's elf RUNPATH are not being used?
The problem is that one of the prerequisites (libppl.so
) also imports libstdc++
. That prerequisite was built using the system gcc, and therefore finds /usr/lib64/libstdc++.so.6
$ ldd /sdk/x86_64/2.11.1/gcc-4.7.2/lib/libppl.so
linux-vdso.so.1 => (0x00007fffd10db000)
libgmpxx.so.4 => /sdk/x86_64/2.11.1/gcc-4.7.2/lib/libgmpxx.so.4 (0x00007f4716f92000)
libgmp.so.10 => /sdk/x86_64/2.11.1/gcc-4.7.2/lib/libgmp.so.10 (0x00007f4716d26000)
--> libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007f4716a25000)
libm.so.6 => /lib64/libm.so.6 (0x00007f47167a0000)
libc.so.6 => /lib64/libc.so.6 (0x00007f4716441000)
libgcc_s.so.1 => /usr/lib64/libgcc_s.so.1 (0x00007f471622c000)
/lib64/ld-linux-x86-64.so.2 (0x00007f47174b4000)
Once a library has been located by the dynamic linker once, it will no longer be searched for; that location will be used for any subsequent requirements.
I resolved this by rebuilding the prerequisites with the new gcc.
$ ldd /sdk/x86_64/2.11.1/gcc-4.7.2/lib/libppl.so
linux-vdso.so.1 => (0x00007fffd10db000)
libgmpxx.so.4 => /sdk/x86_64/2.11.1/gcc-4.7.2/lib/libgmpxx.so.4 (0x00007f4716f92000)
libgmp.so.10 => /sdk/x86_64/2.11.1/gcc-4.7.2/lib/libgmp.so.10 (0x00007f4716d26000)
--> libstdc++.so.6 => /sdk/x86_64/2.11.1/gcc-4.7.2/lib/../lib64/libstdc++.so.6 (0x00007f4716a25000)
libm.so.6 => /lib64/libm.so.6 (0x00007f47167a0000)
libc.so.6 => /lib64/libc.so.6 (0x00007f4716441000)
libgcc_s.so.1 => /sdk/x86_64/2.11.1/gcc-4.7.2/lib/../lib64/libgcc_s.so.1 (0x00007f471622c000)
/lib64/ld-linux-x86-64.so.2 (0x00007f47174b4000)
I'm thinking the final step is to now rebuild gcc with the newly build prerequisites.
- build prerequisites with system gcc
- build new gcc
- rebuild prerequisites with new gcc
- rebuild gcc with rebuilt prerequisites
Whether the final step is necessary I'm not sure.
Related Topics
Bash: /Bin/Myscript: Permission Denied
Does Not Work to Execute Command in Double Brackets in Bash
How to Run a Linux Command That Still Runs After I Close My Putty Ssh Session
Permission Issues, Not Able to Run Script as Root
Printing Grep Results to File and Terminal
If Adding a Command That Repeats Every 10 Minutes to Crontab, When Does the First Job Run
How to Export a Modified Kernel Header
How Many Instructions Does Linux Kernel Need in Order to Handle an Interrupt on an Arm Cortex A9
Fatal: Git Was Built Without Support for Git-Add--Interactive (No_Perl=1)
Why /Lib32/Libc.So.6 Has Two "Fopen" Symbol in It
Getting Current Working Directory Within Kernel Code
Sync Two Computers Going Through a Bridge with Rsync
What Is the Meaning of !#:* !#:1- in a Bash Command
Cannot Make Bash Script Work from Cloud-Init
Is There Way to Delete Duplicate Header in a File in Unix
Fixing the Line-Endings in a Git Repository Using the '.Gitattributes' File