Discussion:
[CMake] RPATH and $ORIGIN
Iker Arizmendi
2008-01-16 21:02:32 UTC
Permalink
I've run into some trouble with how CMake 2.4.2 (and perhaps
later) handles the string "$ORIGIN" when it appears as part of
an RPATH. I've gotten around the trouble (see below), but would
appreciate any pointers on the correct way to use "$ORIGIN".

Regards,
Iker

Briefly, the problem seems to be that CMake inconsistently
carries out the expansion of the "$ORIGIN" string. If one
extends the install rpath like so:

SET(CMAKE_INSTALL_RPATH
"${CMAKE_INSTALL_RPATH}:$ORIGIN/../xxx")

the rpath for an installed executable or shared library ends up
like this (using readelf -d):

0x0000000f (RPATH)
Library rpath: [/home/iker/tmp/rpath_test/xxx]
0x0000001d (RUNPATH)
Library runpath: [/home/iker/tmp/rpath_test/xxx]

where "/home/iker/tmp/rpath_test" is the path to my build tree.
The "$ORIGIN" token disappears.

If the above test is changed so that the ".." is removed:

SET(CMAKE_INSTALL_RPATH
"${CMAKE_INSTALL_RPATH}:$ORIGIN/xxx")

the rpath handling differs. The rpath for an installed
executable now looks like this:

0x0000000f (RPATH)
Library rpath: [/home/iker/tmp/rpath_test/:RIGIN/xxx]
0x0000001d (RUNPATH)
Library runpath: [/home/iker/tmp/rpath_test/:RIGIN/xxx]

Note that "$ORIGIN" has been truncated to "RIGIN". The rpath
for an installed shared library seems to do the right thing:

0x0000000f (RPATH)
Library rpath: [/home/iker/tmp/rpath_test/:$ORIGIN/xxx]
0x0000001d (RUNPATH)
Library runpath: [/home/iker/tmp/rpath_test/:$ORIGIN/xxx]

To get around the two problems above I tried setting the linker
flag variables directly:

SET (CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,'$ORIGIN/../xxx/'" )

SET (CMAKE_SHARED_LINKER_FLAGS
"${CMAKE_SHARED_LINKER_FLAGS} -Wl,-rpath,'$ORIGIN/../xxx'" )

For installed shared libraries we get the right behavior:

0x0000000f (RPATH)
Library rpath: [$ORIGIN/../xxx]
0x0000001d (RUNPATH)
Library runpath: [$ORIGIN/../xxx]

But not for installed executables:

0x0000000f (RPATH)
Library rpath: [RIGIN/../xxx/]
0x0000001d (RUNPATH)
Library runpath: [RIGIN/../xxx/]

To fix the problem with executables I tried adding an extra "$"
character like this:

SET (CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,'$$ORIGIN/../xxx/'" )

And, on my system (Gentoo 1.2, Intel x86), this solves the
problem for exes:

0x0000000f (RPATH)
Library rpath: [$ORIGIN/../xxx/]
0x0000001d (RUNPATH)
Library runpath: [$ORIGIN/../xxx/]

Unfortunately, on CentOS 4.6 systems using the same CMake
release (2.4.2) the behavior with respect to shared libs
and exes is the opposite of what it is on my system. That is,
the shared library flags require the special "$$ORIGIN" string
and exes work fine with "$ORIGIN".

To get the right behavior and ensure that my CMake files work
across all of our machines I resorted to using both forms:

$ORIGIN/../xxx/:$$ORIGIN/../

which clutters the resulting rpaths but gets the job done.
--
Iker Arizmendi
AT&T Labs - Research
Speech and Image Processing Lab
e: ***@research.att.com
w: http://research.att.com
p: 973-360-8516
James Bigler
2008-01-16 22:18:02 UTC
Permalink
Post by Iker Arizmendi
I've run into some trouble with how CMake 2.4.2 (and perhaps
later) handles the string "$ORIGIN" when it appears as part of
an RPATH. I've gotten around the trouble (see below), but would
appreciate any pointers on the correct way to use "$ORIGIN".
...
Post by Iker Arizmendi
SET(CMAKE_INSTALL_RPATH
"${CMAKE_INSTALL_RPATH}:$ORIGIN/../xxx")
CMake expands variables with curly braces. Try ${ORIGIN} instead of $ORIGIN and see if that helps.

James
Iker Arizmendi
2008-01-17 15:39:55 UTC
Permalink
James,

The lack of braces was deliberate - the $ORIGIN string is not a
CMake variable but a special token that should be passed to the
linker without any expansion (the Linux linker provides special
handling for rpath components that use $ORIGIN).

Regards,
Iker
Post by James Bigler
CMake expands variables with curly braces. Try ${ORIGIN} instead
of $ORIGIN and see if that helps.
James
--
Iker Arizmendi
AT&T Labs - Research
Speech and Image Processing Lab
e: ***@research.att.com
w: http://research.att.com
p: 973-360-8516
James Bigler
2008-01-17 16:06:32 UTC
Permalink
Oh, sorry. Rereading your mail message more closely, you want a "$"
character to pass through properly.

Did you try "$$" in the original code (not the one with the single quotes)?

SET(CMAKE_INSTALL_RPATH
"${CMAKE_INSTALL_RPATH}:$$ORIGIN/../xxx")

Or perhaps other stuff like on this recent wiki addition?

http://www.cmake.org/Wiki/CMake:VariablesListsStrings#Escaping

There was a recent thread called "how to escape the $ dollar sign?"

James
Post by Iker Arizmendi
James,
The lack of braces was deliberate - the $ORIGIN string is not a
CMake variable but a special token that should be passed to the
linker without any expansion (the Linux linker provides special
handling for rpath components that use $ORIGIN).
Regards,
Iker
Post by James Bigler
CMake expands variables with curly braces. Try ${ORIGIN} instead
of $ORIGIN and see if that helps.
James
Iker Arizmendi
2008-01-17 17:22:57 UTC
Permalink
I did try $$ and it helps, but not always (see the end of
the original post). The problem is that $ symbols that are
part of the _value_ of the CMake *_LINKER_FLAGS variables
are treated using rules that aren't clear at all (at least
to me). On my system, a single $ is all that's needed for
shared library linker flags but $$ is required for exe
linker flags. But on another system the situation is the
opposite (shared libs get $$, exes get $).

For the time being, I'm using the macro below to paper over
the differences (on Linux, at least).

Iker

# =========================================================
MACRO (APPEND_CMAKE_INSTALL_RPATH RPATH_DIRS)
IF (NOT ${ARGC} EQUAL 1)
MESSAGE(SEND_ERROR "APPEND_CMAKE_INSTALL_RPATH takes 1 argument")
ENDIF (NOT ${ARGC} EQUAL 1)
FOREACH ( RPATH_DIR ${RPATH_DIRS} )
IF ( NOT ${RPATH_DIR} STREQUAL "" )
FILE( TO_CMAKE_PATH ${RPATH_DIR} RPATH_DIR )
STRING( SUBSTRING ${RPATH_DIR} 0 1 RPATH_FIRST_CHAR )
IF ( NOT ${RPATH_FIRST_CHAR} STREQUAL "/" )
# relative path; CMake handling for these is unclear,
# add them directly to the linker line. Add both $ORIGIN
# and $$ORIGIN to ensure correct behavior for exes and
# shared libraries.
SET ( RPATH_DIR "$ORIGIN/${RPATH_DIR}:$$ORIGIN/${RPATH_DIR}" )
SET ( CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,'${RPATH_DIR}'" )
SET ( CMAKE_SHARED_LINKER_FLAGS
"${CMAKE_SHARED_LINKER_FLAGS} -Wl,-rpath,'${RPATH_DIR}'" )
ELSE ( NOT ${RPATH_FIRST_CHAR} STREQUAL "/" )
# absolute path
SET ( CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH}:${RPATH_DIR}" )
ENDIF ( NOT ${RPATH_FIRST_CHAR} STREQUAL "/" )
ENDIF ( NOT ${RPATH_DIR} STREQUAL "" )
ENDFOREACH ( RPATH_DIR )
ENDMACRO ( APPEND_CMAKE_INSTALL_RPATH )

The macro takes a list of paths and can be used like this:

APPEND_CMAKE_INSTALL_RPATH(".;../../;/usr/local/lib")
Post by James Bigler
Oh, sorry. Rereading your mail message more closely, you want a "$"
character to pass through properly.
Did you try "$$" in the original code (not the one with the single quotes)?
SET(CMAKE_INSTALL_RPATH
"${CMAKE_INSTALL_RPATH}:$$ORIGIN/../xxx")
Or perhaps other stuff like on this recent wiki addition?
http://www.cmake.org/Wiki/CMake:VariablesListsStrings#Escaping
There was a recent thread called "how to escape the $ dollar sign?"
James
--
Iker Arizmendi
AT&T Labs - Research
Speech and Image Processing Lab
e: ***@research.att.com
w: http://research.att.com
p: 973-360-8516
James Bigler
2008-01-17 17:54:24 UTC
Permalink
Post by Iker Arizmendi
I did try $$ and it helps, but not always (see the end of
the original post). The problem is that $ symbols that are
I asked if you had tried various permutations of escapes with the
original command [SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH}:
$ORIGIN/../xxx")] not the ones with the hard coded -Wl,-rpath.
Iker Arizmendi
2008-01-17 20:16:15 UTC
Permalink
Sorry, I should have been clearer in my last post. I also
tried escaping the value I put into CMAKE_INSTALL_RPATH but
CMake successfully fought me off. Below are some of the
results for an installed executable. Each "SET" is followed
by the rpath that actually made it to the executable:

SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH}:\$ORIGIN/xxx")
Library rpath: [/home/iker/tmp/rpath_test/:RIGIN/xxx]

SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH}:$$ORIGIN/xxx")
Library rpath: [/home/iker/tmp/rpath_test/:/xxx]

SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH}:\\$ORIGIN/xxx")
Library rpath: [/home/iker/tmp/rpath_test/:/RIGIN/xxx]

SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH}:\\$$ORIGIN/xxx")
Library rpath: [/home/iker/tmp/rpath_test/://xxx]

Iker
Post by James Bigler
I asked if you had tried various permutations of escapes with the
original command [SET(CMAKE_INSTALL_RPATH
"${CMAKE_INSTALL_RPATH}:$ORIGIN/../xxx")] not the ones with the hard
coded -Wl,-rpath.
David Cole
2008-01-17 20:55:19 UTC
Permalink
Did you try "\\\$"?

Both $ and \ need escaping inside the CMake set statement so that you end up
with "\$" in the variable's value...

And if it goes through another round of CMake substitution, you may even
need something crazy like:
"\\\\\\\$"


HTH,
David
Post by Iker Arizmendi
Sorry, I should have been clearer in my last post. I also
tried escaping the value I put into CMAKE_INSTALL_RPATH but
CMake successfully fought me off. Below are some of the
results for an installed executable. Each "SET" is followed
SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH}:\$ORIGIN/xxx")
Library rpath: [/home/iker/tmp/rpath_test/:RIGIN/xxx]
SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH}:$$ORIGIN/xxx")
Library rpath: [/home/iker/tmp/rpath_test/:/xxx]
SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH}:\\$ORIGIN/xxx")
Library rpath: [/home/iker/tmp/rpath_test/:/RIGIN/xxx]
SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH}:\\$$ORIGIN/xxx")
Library rpath: [/home/iker/tmp/rpath_test/://xxx]
Iker
Post by James Bigler
I asked if you had tried various permutations of escapes with the
original command [SET(CMAKE_INSTALL_RPATH
"${CMAKE_INSTALL_RPATH}:$ORIGIN/../xxx")] not the ones with the hard
Brad King
2008-08-05 13:59:24 UTC
Permalink
Post by Iker Arizmendi
I've run into some trouble with how CMake 2.4.2 (and perhaps
later) handles the string "$ORIGIN" when it appears as part of
an RPATH. I've gotten around the trouble (see below), but would
appreciate any pointers on the correct way to use "$ORIGIN".
This will work with CMake 2.6.0 and 2.6.1 if you accept default behavior
(don't use -DCMAKE_NO_BUILTIN_CHRPATH=ON). I've just commited fixes to
CMake HEAD in CVS to make it always work. We'll include them in 2.6.2.

-Brad

Loading...