[CMake] Best way to handle application data path for local run vs. installation

Alexander Neundorf a.neundorf-work at gmx.net
Wed Dec 2 16:34:25 EST 2015


On Wednesday, December 02, 2015 12:27:42 Ruslan Baratov wrote:
> On 02-Dec-15 05:13, Alexander Neundorf wrote:
...
> > well, the RPATH entry was not designed to be patched,
> 
> RPATH designed to be patched. And since it's a third time I'm making
> this statement please provide any arguments if you don't agree.
> 
> Here is mine (comes from wikipedia, 
https://en.wikipedia.org/wiki/Rpath):
> 
>      The rpath of an executable or shared library is an optional entry
> in the
>      .dynamic section of the ELF executable or shared libraries, with
> the type
>      DT_RPATH, called the DT_RPATH attribute. It can be stored there at
> link time by
>      the linker. Tools such as chrpath and patchelf can create or MODIFY
> the entry
>      later.
> 
> Man chrpath (http://linux.die.net/man/1/chrpath):
> 
>          -r <path> | --replace <path>
>              Replace current rpath or runpath setting with the path given


It doesn't matter and it is nitpicking: the RPATH entry has some size, and 
its content cannot simply be changed. I.e. it could be replaced with a 
string of the same length or a shorter one, but not a longer one.
CMake works around this by extending the build RPATH artificially with 
":" at the end I think, patchelf works around this by making the whole 
executable one page bigger if the new entry is longer.
If RPATH was _designed_ to be patchable, tools could just do it, instead 
of having to implement workarounds for longer strings. E.g. the linker 
would support a command line argument how much space it should 
reserve for the RPATH entry, or something like that.

> > any other string in an executable could be patched too:
> RPATH and C++ string literals have not the same nature. E.g. on my 
Linux
> machine RPATH string goes to ".dynstr" section and C++ literal to
> ".rodata" section.
> The difference is quite huge. By parsing ELF headers you can figure 
out
> RPATH offset and be 100% sure that patching is totally correct and
> doesn't affect other binary or general executable logic. RPATH is just a
> hint for linker.
> Changing bytes in .rodata is much trickier. E.g. how do you distinguish
> two strings:
> 
> void print_some_info() {
>    const char* path = "/usr/local"; // must not be changed
>    std::cout << "General note: user specific packages usually installed
> to " << path << std::endl;
> }
> 
> void parse_resources() {
>    const char* resources_path = "/usr/local"; // want to change it in 
future
> std::string myresource = resources_path + "/foo/some.file";
> }
> 
> What if compiler merge them?


By using a very special string which is very unlikely to be used by 
something else, like e.g. "$$$_CMAKE_I_AM_NOT_INSTALLED_$$$".
Maybe it could even be put into a custom ELF section, and then tools 
could just look at that section (... but then it's ELF-only).

I would actually (despite it being hacky) trust the uniqueness of a string 
like the one above.
Probably the string could be made even more unique by embedding the 
target name or something using cmake functionality.

> (Just a general note, not related to how you want to implement 
resources
> trick)
> 
> > const char* my_builddir_flag = "$$$$_I_M_NOT_INSTALLED_$$$$";
> > 
> > ...
> > 
> > if (*my_builddir_flag)
> > 
> > {
> > 
> > ... code when not installed
> > 
> > }
> > 
> > else
> > 
> > {
> > 
> > ... code for the installed version
> > 
> > }
> > 
> > Just search for that string in the executable and replace the first
> > byte with a '\0'.
> 
> Still can violates logic. What if I want to print string to resources in
> next format:
> 1. "-" x size of path to resources (compiler can figure out it at
> compile time!)
> 2. path to resources
> 3. "-" x size of path to resources
> 
> If you pass "/usr/local" output will be (nice):
> 
> --------------
> /usr/local
> --------------
> 
> If you pass "/home/username", output will be (nice):
> 
> ------------------------
> /home/username
> ------------------------
> 
> If you pass "$$$$_I_M_NOT_INSTALLED_$$$$" then change string to
> "/usr/local" after install (ugly, not what I expect!):
> 
> ---------------------------
> /usr/local
> ---------------------------

Sorry, I don't understand.
The idea above was only for solving the question "am I installed ?" 
yes/no, not "where am I installed ?".

 
> > Not sure there is a simple tool to do that, but writing one shouldn't
> > be hard.
> 
> sed? :)

I have never used sed on binary files. Does that work ?

Alex
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://public.kitware.com/pipermail/cmake/attachments/20151202/51f02432/attachment-0001.html>


More information about the CMake mailing list