RPath Packaging Draft

From FedoraProject

Revision as of 15:29, 15 September 2009 by Toshio (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
Warning (medium size).png
This page is a draft only
It is still under construction and content may change. Do not rely on the information on this page.

Contents

Rationale

Update rpath guidelines. There's no reason to forbid rpath for internal libraries so allow that usage.

Beware of Rpath

Sometimes, code will hardcode specific library paths when linking binaries (using the -rpath or -R flag). This is commonly referred to as an rpath. Normally, the dynamic linker and loader (ld.so) resolve the executable's dependencies on shared libraries and load what is required. However, when -rpath or -R is used, the location information is then hardcoded into the binary and is examined by ld.so in the beginning of the execution. Since the Linux dynamic linker is usually smarter than a hardcoded path, we usually do not permit the use of rpath in Fedora.

There is a tool called check-rpaths which is included in the rpmdevtools package. It is a good idea to add it to the %__arch_install_post macro in your ~/.rpmmacros config file:

%__arch_install_post            \
/usr/lib/rpm/check-rpaths     \
/usr/lib/rpm/check-buildroot

When check-rpaths is run, you might see output like this:

ERROR   0001: file '/usr/bin/xapian-tcpsrv' contains a standard rpath '/usr/lib64' in [/usr/lib64] 

Any rpath flagged by check-rpaths MUST be removed.

Rpath for Internal Libraries

When a program installs internal libraries they are often not installed in the system path. These internal libraries are only used for the programs that are present in the package (for example, to factor out code that's common to the executables). These libraries are not intended for use outside of the package. When this occurs, it is acceptable for the programs within the package to use an rpath to find these libraries.

Example:

# Internal libraries for myapp are present in:
%{_libdir}/myapp/
%{_libdir}/myapp/libmyapp.so.0.3.4
%{_libdir}/myapp/libmyapp.so

# myapp has an rpath to %{_libdir}/myapp/
readelf -d /usr/bin/myapp | grep RPATH
 0x0000000f (RPATH)                      Library rpath: [/usr/lib/myapp]
Idea.png
Non-Internal Libraries
When programs outside of the package are supposed to link against the library, it is better to use the Alternative to Rpath or simply move the libraries into %{_libdir} instead. That way the dynamic linker can find the libraries without having to link all the programs with an rpath.

Alternatives to Rpath

Often, rpath is used because a binary is looking for libraries in a non-standard location (standard locations are /lib, /usr/lib, /lib64, /usr/lib64). If you are storing a library in a non-standard location (e.g. /usr/lib/foo/), you should include a custom config file in /etc/ld.so.conf.d/. For example, if I was putting 32 bit libraries of libfoo in /usr/lib/foo, I would want to make a file called "foo32.conf" in /etc/ld.so.conf.d/, which contained the following:

/usr/lib/foo

Make sure that you also make a 64bit version of this file (e.g. foo64.conf) as well (unless the package is disabled for 64bit architectures, of course).

Removing Rpath

There are several different ways to fix the rpath issue:

  • If the application uses configure, try passing the --disable-rpath flag to configure.
  • If the application uses a local copy of libtool, add the following lines to the spec after %configure:
%configure
sed -i 's|^hardcode_libdir_flag_spec=.*|hardcode_libdir_flag_spec=""|g' libtool
sed -i 's|^runpath_var=LD_RUN_PATH|runpath_var=DIE_RPATH_DIE|g' libtool
  • Sometimes, the code/Makefiles can be patched to remove the -rpath or -R flag from being called. This is not always easy or sane to do, however.
  • As a last resort, Fedora has a package called chrpath. When this package is installed, you can run chrpath --delete on the files which contain rpaths. So, in our earlier example, we'd run:
chrpath --delete $RPM_BUILD_ROOT%{_bindir}/xapian-tcpsrv

Make sure that you remember to add a BuildRequires: chrpath if you end up using this method.