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.
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.
Joe downloads the BinReloc SDK from the Developer Tools section of the download page. He extracts the archive in his home folder. A folder called binreloc-2.0 appears.
Joe's Hello World program doesn't use glib, so he wants the plain C version of BinReloc. Joe runs the following commands to generate the BinReloc source files:
Now that Joe has generated the BinReloc source files, he continues with writing a Hello World program:
Now it is time to compile & run the program:
Yes, it's this easy!
The -DENABLE_BINRELOC argument enables BinReloc support. BinReloc is only enabled if this macro is defined. Let's take a look at what happens if the macro is not defined:
If you're using BinReloc in an application, then call br_init()
. The definition is:
This function returns 1 on success, and 0 if BinReloc failed to initialize.
If BinReloc failed to initialize, then the error code will be stored in error
.
The following error codes are available:
If you're using BinReloc in a library, then call br_init_lib()
. The definition is:
This function returns 1 on success, and 0 if BinReloc failed to initialize.
If you don't initialize BinReloc, or if initialization failed, then all BinReloc functions will return
the fallback paths, so even if initialization failed, it's not fatal. Initialization will fail
if BinReloc is disabled (because ENABLE_BINRELOC
is not defined), or because the application
is running on a platform which doesn't support relocating executables (non-Linux platforms).
There are more functions besides br_find_exe()
. Here is a list of all relocation functions:
Function | Returns |
---|---|
br_find_exe() | The full path of your application or library. |
br_find_exe_dir() | The folder in which your application or library is located. |
br_find_prefix() | The prefix in which your application or library is located.
This function assumes that your binary is located
inside an FHS-compatible directory structure ($prefix/bin/ or $prefix/lib/). Examples:
|
br_find_bin_dir() | prefix + "/bin" |
br_find_sbin_dir() | prefix + "/sbin" |
br_find_data_dir() | PREFIX + "/share" |
br_find_locale_dir() | PREFIX + "/locale" |
br_find_lib_dir() | PREFIX + "/lib" |
br_find_libexec_dir() | PREFIX + "/libexec" |
br_find_etc_dir() | PREFIX + "/etc" |
All functions in the above table are declared like this:
default_path
is used as fallback: if the BinReloc isn't initialized, or failed to initialize,
then a copy of default_path will be returned. Or if the default_path is NULL, NULL will be returned.
Note that the return values of all of the above functions must be freed when no longer necessary, except if the return value is NULL.
There's also a BinReloc version with a glib-style API. Generating this version is just like generating the normal version:
The API is almost identical to the plain C version, except that it uses glib-style names and glib data types, such as GError. See the full API reference.
The plain C version of BinReloc provides some utility functions for modifying strings and paths, because many applications will need such functionality. The glib version doesn't contain these utility functions because glib already has its own utility functions. Note that these utility functions are fully portable, and can be used even when BinReloc is not enabled/initialized.
- 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.
char *datafile; datafile = br_strcat ("/usr", "/foo/mydata.txt"); load_data_file (datafile); free (datafile);
In Makefile.am:
In main.c:
Use the special BinReloc Autoconf Macro (binreloc.m4). This file can be found in the BinReloc SDK.
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.
Add BINRELOC_CFLAGS
and binreloc.c/binreloc.h to Makefile.am:
At the beginning of main.c, add:
Somewhere in main.c:
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(br_find_prefix(DEFAULT_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(br_find_data_dir(DEFAULT_DATA_DIR));
The tests folder in the BinReloc source tarball contains more examples about how to use BinReloc.
The guide for BinReloc version 1.x is still available for those who need it.