LinuxQuestions.org
Help answer threads with 0 replies.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 07-08-2011, 04:45 AM   #1
d3plot
LQ Newbie
 
Registered: Jul 2011
Location: Devon, UK, on a farm.
Posts: 12

Rep: Reputation: Disabled
Linux: Problems embedding shared library location in executable


We build applications that we ship to users, and historically we have either embedded static libraries (ie xxx.a) or relied on system shared run-time libraries (xxx.so) that the run-time loader can find in standard locations such as /usr/lib. This all worked :-)

However now we want to ship some run-time shared libraries, in order to comply with LGPL licence requirements, and we are having a problem with their locations.

We ship both 32 and 64 bit executables, so we want to organise the distribution as follows:

Executables directory, containing application_32.exe, application_64.exe.

Sub-directory under there, ie executables/lib_32 containing 32 bit .so files.

Another sub-directory executables/lib_64 containing 64 bit .so files.

(This organisation could be changed if necessary)

This all works, but a final twist is that we don't stipulate where the end user must put his installation, so the "executables" directory could be anywhere on his system.


SO here is the question: how do we tell the run-time loader (ld.so) where to find the shared libraries? There are various ways of embedding that path at link time, eg argument "-rpath=xxx" to ld, but the path you set is stored verbatim.

So if you give a relative pathname, say "-rpath=./lib_32", then this only works at run time if the user's current working directory is where the executable is stored, and this will not normally be the case. Alternatively if you give an absolute path then, obviously, the end user must put his libraries in precisely that location.

we could edit LD_LIBRARY_PATH on the target system, but that would make installation more complex and is a clumsy solution.

There must be a simple solution to this problem, but I'm blowed if I can see it! What we need is some way of giving a path relative to where the executable is located on the target system, wherever that may be.

Can anyone help?
 
Old 07-08-2011, 08:01 AM   #2
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 454Reputation: 454Reputation: 454Reputation: 454Reputation: 454
Quote:
Originally Posted by d3plot View Post
...
Can anyone help?
'man ld.so' -> look up 'ORIGIN'. In conjunction with 'man ld'.
 
Old 07-08-2011, 08:22 AM   #3
d3plot
LQ Newbie
 
Registered: Jul 2011
Location: Devon, UK, on a farm.
Posts: 12

Original Poster
Rep: Reputation: Disabled
That sounds exactly like what we need - thanks.
 
Old 07-08-2011, 09:46 AM   #4
d3plot
LQ Newbie
 
Registered: Jul 2011
Location: Devon, UK, on a farm.
Posts: 12

Original Poster
Rep: Reputation: Disabled
[later] That $ORIGIN worked, so thanks for that.

Here's another question. Let's suppose we build our application against shared library mylib.so, but this contains little used functions that may never be invoked by the average user. Now let's also suppose that our average user has grabbed the executable but has forgotten also to pick up the directory with the shared libraries.

We can use "lazy" loading to defer loading of the objects in that library until needed, but what about if the library is not there at all?

Is there any way of telling the run-time loader "if that shared library can't be found just ignore it and run anyway"?

The only way I can see of doing this is not to refer to the functions within the library directly, but rather to use dlopen() to find it ourselves at run-time, and then to use dlsym() to get pointers to the functions we need from within it. Is this the only method, or is there a better way?


Sorry for all the questions, I'm used to static libraries which don't produce all these issues!
 
Old 07-08-2011, 10:01 AM   #5
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 454Reputation: 454Reputation: 454Reputation: 454Reputation: 454
Quote:
Originally Posted by d3plot View Post
[later] That $ORIGIN worked, so thanks for that.

Here's another question. Let's suppose we build our application against shared library mylib.so, but this contains little used functions that may never be invoked by the average user. Now let's also suppose that our average user has grabbed the executable but has forgotten also to pick up the directory with the shared libraries.

We can use "lazy" loading to defer loading of the objects in that library until needed, but what about if the library is not there at all?

Is there any way of telling the run-time loader "if that shared library can't be found just ignore it and run anyway"?

The only way I can see of doing this is not to refer to the functions within the library directly, but rather to use dlopen() to find it ourselves at run-time, and then to use dlsym() to get pointers to the functions we need from within it. Is this the only method, or is there a better way?


Sorry for all the questions, I'm used to static libraries which don't produce all these issues!
Let's (politically correctly) KISS. I think you need an installer (like Firefox has - the version which can installed into any directory - the installed unpacking the tarball and amybe creating yet other needed directory) and I think you better wrap your program in a script which before it does anything else checks the directory structure and existence of needed files in it.

Firefox is too a shell script wrapped calling the actual binary in the end.
 
Old 07-08-2011, 10:16 AM   #6
d3plot
LQ Newbie
 
Registered: Jul 2011
Location: Devon, UK, on a farm.
Posts: 12

Original Poster
Rep: Reputation: Disabled
I agree, having a script to handle initialisation etc would do the trick.

However Keeping It Simple means trying to minimise the number of files in an installation, and hence the scope for cock-ups / version mis-matches, etc

I think we'll try the dlopen/dlsym approach on Linux, and likewise LoadLibrary/GetProcAddress on Windows (am I allowed to mention that on here without getting flamed?) and see what happens.

Not yet sure what to do about the various other Unices ... I think we'll drop support for them this year anyway so it's not worth much effort.

Thanks for the help and suggestions anyway.
 
Old 07-08-2011, 10:25 AM   #7
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by d3plot View Post
SO here is the question: how do we tell the run-time loader (ld.so) where to find the shared libraries? There are various ways of embedding that path at link time, eg argument "-rpath=xxx" to ld, but the path you set is stored verbatim.
Doesn't -rpath allow relative paths? If the libraries are always in the same place relative to the executables, you should just be able to link to e.g. lib_64/libmy.so rather than -Llib_64 -lmy, if that's what was causing the problem.
Kevin Barry
 
Old 07-08-2011, 10:37 AM   #8
d3plot
LQ Newbie
 
Registered: Jul 2011
Location: Devon, UK, on a farm.
Posts: 12

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by ta0kira View Post
Doesn't -rpath allow relative paths? If the libraries are always in the same place relative to the executables, you should just be able to link to e.g. lib_64/libmy.so rather than -Llib_64 -lmy, if that's what was causing the problem.
Kevin Barry
Kevin

That's the first thing we tried, but it turned out that the path was relative to $cwd so if you are sitting in /local/kevin and you try to run an executable in /usr/local/somewhere it ends up looking for libraries in /local/kevin/<library directory> ... not too good!

The $ORIGIN argument to -rpath, see the earlier posts, solves that problem by making the path relative to the "origin" of the executable (big thanks to Sergei for that).


Then we got fussy and decided to try to tell at run-time whether the library was there at all, which effectively gets us into taking over the loader's job by looking for libraries at run-time and extracting symbols from them. The advantage of this is, obviously, that we can yield gracefully to "library not there" and give a sensible warning message rather than just crashing or refusing to run in the first place.


And all this to try to simplify matters for the end-users ... bitter experience has taught us that if they can cock it up they will, hence our normal practice of binding in libraries statically where possible even though it makes the executable larger. It also greatly simplifies our task when sending out updates.

Christopher Bell
 
Old 07-08-2011, 05:49 PM   #9
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by d3plot View Post
That's the first thing we tried, but it turned out that the path was relative to $cwd so if you are sitting in /local/kevin and you try to run an executable in /usr/local/somewhere it ends up looking for libraries in /local/kevin/<library directory> ... not too good!
I actually remember that happening to me in the past, and I even pointed it out to someone else a while ago on this board, but it seems like the last time I tried it that wasn't the case. Now that I've tried it again, it is indeed the case.

What about a wrapper script, in the same directory, that sets LD_LIBRARY_PATH:
Code:
#!/bin/bash

location="$( dirname "$0" )"

append="$location/lib_32:$location/lib_64"

if [ -n "$LD_LIBRARY_PATH" ]; then
  export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$append"
else
  export LD_LIBRARY_PATH="$append"
fi

"$location/yourprog" "$@"
I've assumed the target is Linux; it might not work on everything. I think my FreeBSD boot ignores LD_LIBRARY_PATH by default. You'd also have to make some changes to infer the path of the actual executable when symlinks or relative paths to the script are used, but I left those out for clarity (readlink -f "$0" is helpful on Linux for both.)

Kevin Barry
 
Old 07-09-2011, 01:16 PM   #10
d3plot
LQ Newbie
 
Registered: Jul 2011
Location: Devon, UK, on a farm.
Posts: 12

Original Poster
Rep: Reputation: Disabled
Kevin

You're right, we could write a script that adds the directory to LD_LIBRARY_PATH as in your example, but I don't want to go down that route because it's an extra file to get lost or perhaps muddled up during version changes.

We do in fact provide a script for launching our stuff on Unix/Linux, but not all our clients use it since some prefer desktop icons, or batch scripts, or whatever, of their own creation and these will refer directly to the .exe files. So I don't want to have to ask them all to change those.

I suppose we could make the current .exe a small wrapper programme that does a getenv() on LD_LIBRARY_PATH, adds to it, does a putenv() and then forks off the "true" executable; but it seems a bit of a faff!

You're right, in this instance we are targeting Linux; but we also port to AIX, Irix, Solaris and HP-UX, and of course Windows.

I'm hoping the dlopen/dlsym route will work since it seems far and away the best solution. However I'm leaving it in the capable hands of a colleague to try since I'm pushing off to La Belle France tomorrow for 10 days on hols, so I'm afraid there won't be any replies from me to this thread for a bit.

I'm hoping that when I come back to the grindstone it will all be working perfectly ... :-}
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
how to create an executable shared library (like libc-x.x.so or ld-x.x.so) JazzItSelf Programming 2 11-07-2009 07:47 AM
Linking an executable to a shared library (C++) lennyk Programming 4 06-25-2009 04:45 AM
LXer: Embedding a File in an Executable, aka Hello World, Version 5967 LXer Syndicated Linux News 0 06-12-2008 10:11 PM
LINUX - linking archive (static library) with shared (dynamic) library gurkama Programming 5 03-04-2007 11:11 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 11:30 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration