Search code examples
linuxgccshared-librarieslddynamic-linking

How to set RPATH and RUNPATH with GCC/LD?


I recently encountered this problem after an upgrade of the system: using the GCC -Wl,-rpath= option works differently than before.

I used it to set the search paths to some shared libraries that were built in a sub-module of my project. At the time I considered it better than setting LD_LIBRARY_PATH system-wide (I didn't want to set it every time I turned on the computer). Everything worked fine, and these two approaches seemed equivalent.

Now it seems that the behavior of -rpath has changed. It still works for directly dependent libraries, but not for those that link other libraries from the same directory set via -rpath=. Exporting LD_LIBRARY_PATH still works as before.

I inspected the output of the compilation using readelf and there is a difference. Before upgrade (Linux Mint 18.2 with GCC 5.4) the Dynamic section had this line:

0x000000000000000f (RPATH)            Library rpath: [submod/lib]

After the upgrade (Linux Mint 19 with GCC 7.3) the line changed to:

0x000000000000001d (RUNPATH)            Library runpath: [submod/lib]

In use RPATH but not RUNPATH? it is suggested that RPATH was replaced by RUNPATH (or that it at least servers a different purpose as it has a lower priority), but it doesn't give an answer as to why this effects indirect linking. The libraries themselves have neither RPATH, or RUNPATH in readelf output.

So my question is this: Why has the linker suddenly started to interpret the -rpath= option differently, and is there a way to force the old behavior? (Or do something different that will yield an equivalent result.)

Another question would be: Is it possible to tell the old version of linker to produce the new output (i.e. RUNPATH instead of RPATH)?


EDIT

This is not a duplicate of How to set RunPath of a binary? -- my question is the opposite: I want the behavior of RPATH. I figured it out (thanks to the tip in the comment), and I will answer my questions here.


Solution

  • 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.