On Win32, applications and libraries are easily relocatable because
applications and DLLs can use GetModuleFilename()
to obtain
their full path.
On Linux however, no easy mechanisms exist. There is no function
equivalent to GetModuleFilename()
.
For executables, you can still find your full location by resolving the symlink /proc/self/exe, but that won't work for libraries.
Historical note: BinReloc is the successor of libprefixdb, Autopackage's previous solution to the relocation problem. BinReloc is more automatic and easier to use.
KStandardDirs
class. If your application uses KStandardDirs
to lookup data files, your application will be automatically relocatable, so using BinReloc is not necessary.
Libraries however will not benefit from this, and must use BinReloc directly.
Step 1:Download BinReloc from the Developer Tools section of the download page. Extract the archive, and you will find the following files:
|
![]() |
Step 2:Create the folder ~/helloworld. Copy prefix.c and prefix.h to that folder. Open a terminal and change to that folder. |
|
Step 3:Open your favorite text editor and save the following code to ~/helloworld/hello.c:#include <stdio.h> #include "prefix.h" int main () { printf ("The full path of this application is: %s\n", SELFPATH); return 0; } |
![]() |
Step 4:Compile the program and run it:[bash ~/helloworld]$ gcc -DENABLE_BINRELOC hello.c prefix.c -o hello -lpthread [bash ~/helloworld]$ ./hello The full path of this application is: /home/example/helloworld/hello |
Yes, it's this easy! Now let's take a look at what the code does:
SELFPATH
is a macro which returns the filename of the application or the library that has called it.
If you call SELFPATH
in hello, it will return "/home/example/helloworld/hello".
If you call SELFPATH
in libfoo, it will return (for example) "/usr/lib/libfoo.so.0.0.0".
PREFIX
.Other similar macros are:
Macro | Value |
---|---|
BINDIR | PREFIX + "/bin" |
SBINDIR | PREFIX + "/sbin" |
DATADIR | PREFIX + "/share" |
LIBDIR | PREFIX + "/lib" |
LIBEXECDIR | PREFIX + "/libexec" |
ETCDIR | PREFIX + "/etc" |
SYSCONFDIR | Alias for ETCDIR. |
CONFDIR | Alias for ETCDIR. |
LOCALEDIR | DATADIR + "/locale" |
There are also a set of macros that are named exactly the same as the
above macros, but are prepended with BR_. For example, BR_SELFPATH
and
BR_DATADIR
.
These macros are convenience macros for contatenating paths.
BR_SELFPATH("/lib")
is like SELFPATH + "/lib", BR_DATADIR("/data.png")
is like DATADIR + "/data.png", etc.
Note: The return values must not be freed. See Implementation details for information about why.
All of the afore mentioned macros (including SELFPATH
, and PREFIX
) can be disabled by defining BR_NO_MACROS
.
br_strcat
. Most applications that deal with paths will probably need
to concatenate strings somewhere in the source code. For that reason, this function is provided by BinReloc as a utility function.br_strcat
is 100% portable across all operating systems! You can use it even when ENABLE_BINRELOC
isn't defined.
char *br_strcat (const char *str1, const char *str2); - str1: A string. - str2: Another string. - Returns: A newly-allocated string. This string should be freed when no longer needed. Concatenate str1 and str2 to a newly allocated string. This is a convenience function since many applications need to concatenate DATADIR with another path.
char *datafile;
/* Note: this is kind of redundant because you can also just do
BR_DATADIR("/foo/mydata.txt") but this is just an example ;) */
datafile = br_strcat (DATADIR, "/foo/mydata.txt");
load_data_file (datafile);
free (datafile);
br_thread_local_store()
internally, so that you don't have
to worry about freeing the string returned by those macros.
It's defined as follows: const char *br_thread_local_store (char *str);
The first time you call br_thread_local_store()
, str
is saved in an thread
local internal variable (refer to the pthreads manual for more information about
this), or a normal internal variable if pthread support is disabled. str
remains unmodified and is returned as const char *
.
The next times you call this function, the previous value of str
(that was
saved in the internal variable) is freed. Then the current str
is
stored in that variable again, and str is returned as const char *
.
The internal variable is also freed on application exit.
This means that you should not free a string once it is passed to
br_thread_local_store()
, it already does that for you. You also cannot
pass static strings to br_thread_local_store()
.
So what does this mean for all the macros?
Example:
char *foo, *bar, *saved; /* => "/usr/share/mydata.txt" */ foo = BR_DATADIR("mydata.txt"); saved = strdup(foo); /* => "/usr/share/moredata.png"; "/usr/share/mydata.txt" is now freed */ bar = BR_DATADIR("moredata.png"); /* This is wrong! You can't do this because the value of foo is freed by the 2nd BR_DATADIR call */ printf("%s\n", foo); /* This is good; by calling strdup() the value is saved. But you have to free this variable yourself. */ printf("%s\n", saved);
In Makefile.am:
INCLUDES = $(LIBGLADE_CFLAGS) \ -DDATADIR=\"$(datadir)\" bin_PROGRAMS = foo foo_SOURCES = main.cIn main.c:
xml = glade_xml_new (DATADIR "/foobar/glade/main.glade", NULL, NULL);
How to use BinReloc:
Append the contents of binreloc.m4 to acinclude.m4 (which is in the same folder as configure.in). Create acinclude.m4 if it doesn't exist.
In configure.in, put the command AM_BINRELOC
somewhere.
The AM_BINRELOC macro checks whether BinReloc should be enabled (whether the system supports the feature,
whether the user explicitly disabled it, etc). The variable $br_cv_binreloc
will be set to 'yes' if BinReloc is enabled, or 'no' otherwise.
BINRELOC_CFLAGS
and prefix.c/prefix.h to Makefile.am, as well as additional linker flags:
AM_CPPFLAGS = $(BINRELOC_CFLAGS)
...
foo_SOURCES = main.c \
prefix.h \
prefix.c
foo_LDFLAGS = -lpthread
If the pthread dependancy is unacceptable, then you can disable pthread support by
defining BR_PTHREAD=0
:
AM_CPPFLAGS = $(BINRELOC_CFLAGS) -DBR_PTHREAD=0
#include "prefix.h"
Somewhere in main.c:
xml = glade_xml_new (BR_DATADIR("/foobar/glade/main.glade"), NULL, NULL);
And that was it! Your configure script will now have a --enable-binreloc=[yes/no/auto] option. The default value for this option is --enable-binreloc=auto, which will automatically check whether BinReloc support is desired. It does so by checking for the following things:
KStandardDirs
class. If your application uses KStandardDirs
to lookup data files, your application will be automatically relocatable, so using BinReloc is not necessary.
Libraries however will not benefit from this, and must use BinReloc directly.
KGlobal::dirs()->addPrefix(strdup(PREFIX));Make sure you use
KGlobal::dirs()
to lookup data files througout your entire program.
If you create new instances of KStandardDirs
, you need the re-add the prefix.
If you want to use KIconLoader
to load icons from whever your program is installed, add this:
KGlobal::iconLoader()->addAppDir(strdup(DATADIR));