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

Ruslan Baratov ruslan_baratov at yahoo.com
Wed Dec 2 21:27:29 EST 2015


On 03-Dec-15 04:34, Alexander Neundorf wrote:
>
> 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.
>
Still see no arguments, it's just your personal opinion.

> 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.
>
Just an implementation notes, doesn't change the fact that it can be 
done and it's designed to be modifiable.

> 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.
>
I think it's not possible. As far as I know there is no limitation for 
path size on Linux for example. Hence it's not possible to predict what 
size for path to library user want to use by setting RPATH.

> > > 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_$$$".
>
Just like I said it was a general note to show that C++ literal strings 
is not the same as RPATH entry and can't be changed correctly/easily 
after code already compiled.

> 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 ?".
>
Then I don't understand how it's planned to be used. I thought that in 
build directory you changing "$$$$_I_M_NOT_INSTALLED_$$$$" to 
"/path/to/build/directory" so resources can be found there, and on 
install you change it to "/path/to/install/directory". So my guess is 
not correct?

> > > 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 ?
>
Yes, why not.

 > cat bar.cpp
#include <iostream>

int main() {
   std::cout << "Bar say: " << "11111abc22222" << std::endl;
}
 > g++ -O3 bar.cpp -o bar
 > ./bar
Bar say: 11111abc22222
 > sed -i 's,11111abc22222,11111XYZ22222,' ./bar
 > ./bar
Bar say: 11111XYZ22222

Ruslo

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://public.kitware.com/pipermail/cmake/attachments/20151203/e484d85b/attachment-0001.html>


More information about the CMake mailing list