17

I'm trying to link an RPATH containing the special string $ORIGIN into an executable built using GCC with the Code::Blocks IDE. I've specified

-Wl,-R$ORIGIN

in the linker options for the project, but the command line output to GCC is wrong (stripped for clarity):

g++ -Wl,-R

What is the correct way to specify this argument for Code::Blocks?

kbluck
  • 11,530
  • 4
  • 25
  • 25

3 Answers3

36

Whoever decided to make the token $ORIGIN is an evil bastard who deserves a special place in programmer hell. Since '$' is a special character for bash and other scripting languages like make, it screws everything up unless carefully escaped. Even worse, depending on which build environment you're using, the specifics of how to escape properly will likely change.

In bash, you need to stick a backslash in front of the $:

-Wl,-R\$ORIGIN

Code::Blocks apparently also treats the $ as special. Then, whatever subprocess controller Code::Blocks sends the command to treats the backslash as special. So, both the backslash and the $ need to be doubled up to get escaped properly. Therefore, in Code::Blocks linker settings, you need to specify:

-Wl,-R\\$$ORIGIN

...which outputs:

-Wl,-R\\$ORIGIN

...to the build log, but the shell actually gets sent:

-Wl,-R\$ORIGIN

...which as mentioned above produces the desired result.

What a pain.

kbluck
  • 11,530
  • 4
  • 25
  • 25
  • 7
    +1 just for the evil bastard comment... this issue has caused me tons of pain – chotchki Jul 14 '10 at 20:39
  • Perfect comment , he should rot in hell.. with 40 succubus probing him lol. – Phyo Arkar Lwin Jan 14 '13 at 17:44
  • Is there a way, given a built executable, to change its RPATH? Since this is just a string in the ELF tables, it doesn't seem unreasonable. Setting rpath to $ORIGIN/yada/yada seems to me to be something that you'd want to add to some existing (possibly horrifically complex) build script, and if they provided a way to send options to the linker, then great, but, as discussed, you have to deal with escape hell (may be easier to make your own 'ld' wrapper to sneak it in). OTOH modifying the rpaths on the results after the smoke clears? Not so hard. If, that is, there's a utility that can do it... – greggo Jan 16 '13 at 22:37
  • aah, not so easy as I thought, since the rpath is actually in a loadable segment, so growing it post-link could be impossible. Nonetheless there is a 'patchelf' utility out there which may be able to do it. – greggo Jan 16 '13 at 23:04
  • 2
    export ORIGIN='$ORIGIN' and fight fire with fire? – George Phillips Apr 04 '13 at 18:36
  • Oh wow, I have been trying to solve this for more than an hour and all I left out is a slash! Ugh, I hate problems like these. – daxvena Jul 30 '13 at 01:55
  • 1
    I had to write `-Wl,-R\\$$$$ORIGIN` in linker settings to make it output `-Wl,-R\\$ORIGIN` in build log and work correctly. – Fabio Iotti Apr 25 '15 at 08:24
  • Not specific to Code::Blocks, I use `LDFLAGS=-Wl,-rpath,'\$\$ORIGIN'` – kevinarpe Nov 22 '15 at 10:05
15

In addition to kblucks answer that addresses the question for Code:Blocks.... For those like me who stumbled across this page looking for how to do this with Make. The trick is to use an extra $ sign as an escape character and to enclose it with quotes:

-Wl,-R,'$$ORIGIN/../lib'

Full explanation can be had here: Using ORIGIN for a dynamic runtime library search path

Uyghur Lives Matter
  • 18,820
  • 42
  • 108
  • 144
user44538
  • 355
  • 3
  • 9
1

If your executable is being built by a huge complex script environment not created by you, and you don't want to delve into with that, trying running with setenv LD_RUN_PATH='$ORIGIN/../lib'; if that doesn't work, a pragmatic approach is to create a wrapper for ld:

#!/bin/sh
exec /usr/bin/ld -R '$ORIGIN/../lib' "$@"

... then do the build with that stub on the path. In practice it may be called to build .so files, or other executables, so you may need to make this a more complex script that decides whether to insert the RPATH. OR, run build without this, and with, and cherry pick.

(here "/usr/bin/ld" is the ld that would normally have been run, which may be somewhere else. gcc may not pick up ld from the path, see gcc environment variables to override that. Mileage may vary. Single use only. Not warranted to be less awful than any other approach).

greggo
  • 3,009
  • 2
  • 23
  • 22