PackagingDrafts/MultilibTricks

= Multi lib tricks =

File conflicts
For architecture independent files conflicts should be avoided, so the files should be identical among arches. It may involve some work with upstream when header files include architecture specific files, for example header files which contains autoconf conditionals like HAVE_INT32.

Another problem that sometimes appears is with gzipped files. Normally gzip will embed the timestamp of the file in its output, and this can cause a multilib conflict. The way to avoid this is to use gzip's '-n' option whenever files are gzipped at build time.

If you are not sure what the reason for a particular conflict is, fetch the packages from two multilibbed architectures (e.g. i386 and x86_64) and unpack them like this:

mkdir i386 x86_64 rpm2cpio blah-1.2-3.i386.rpm | (cd i386; cpio -idv) rpm2cpio blah-1.2-3.x86_64.rpm | (cd x86_64; cpio -idv)

Then you can use the diff or cmp utilities to discover exactly what is different between the conflicting files.

myautoconf.h files with a size in them
Some packages install myautoconf.h type files which will have something in them relating to the byte size of (size_t) or (void *) at compile time, the possible way to get around this problem is to change from myautoconfig.h to myautoconfig-32.h and myautoconfig-64.h (depending on the platform) and have myautoconfig.h containing just the following on all platforms:


 * 1) include 


 * 1) if __WORDSIZE == 32
 * 2) include "myautoconfig-32.h"
 * 3) elif __WORDSIZE == 64
 * 4) include "myautoconfig-64.h"
 * 5) else
 * 6) error "Unknown word size"
 * 7) endif

This kind of API specification is bad in most cases, however, since an API should be completely platform independent.

If what is needed are integer of a length independent from the platform, integers like  from inttypes.h can be used.

Doxygen footers
Doxygen default footers include the date. This leads to conflict since doc files are not generated at the exact same time. To use a custom footer without the date, it is possible to modify the dox file used to drive the documentation generation, and set, for example:

HTML_FOOTER           = no_date_footer.html

The  file could be along:

 Generated for $projectname by  $doxygenversion

PNG images
PNG images generated for example by doxygen can include the date as part of the PNG format. This leads to conflicts since the *.png files are not generated at the exact same time. To solve this, you can set the internal timestamps of PNG images to a reference timestamp which can be achieved by using the python script png-mtime.

Put this command into your spec file so that it applies to the PNG files where the reference date/file shall be used.

Timestamps
Files should also have the same timestamps. For most of the files this means taking care to keep the timestamps (which should be done in every package). For autoconf based packages this is in general achieved by doing something along:

make install DESTDIR=$RPM_BUILD_ROOT INSTALL="%{__install} -p"

For the architecture independent files generated at build time it is possible to use the timestamp of a reference file. For example:

touch -r ../cernlib.in src/scripts/cernlib

or

touch -r NEWS $RPM_BUILD_ROOT%{_includedir}/Xbae/patchlevel.h

Multiarch, binaries and compilation scripts
In multilib environments there is a preferred architecture, 64 bit over 32 bit in x86_64, 32 bit over 64 bit in ppc64 and sparc64. When a conflict is found between two packages corresponding with different arches, the installed file is the one from the preferred arch. This is very common for executables in /usr/bin, for example. If the file /usr/bin/foo is found in an x86_64 package and in an i386 package, the executable from x86_64 will be installed.

These implicit conflicts are accepted in Fedora, though they are considered bad by some contributors. There may be some long-term solution for these issues, but before that there are some tricks that may allow to avoid those conflicts that are presented below. Once again they are optional.


 * In compilation scripts (in general named along mylib-config) it should be advisable to remove  when $libdir is the default library directory on this platform. Indeed this is automatically added when linking with the gcc compiler (it may be needed when linking with ld, but using ld is wrong in general, so a user linking with ld should add the flag by himself).


 * binaries may be put outside of the packages selected to be included in multilib repositories. In general the devel subpackages and their dependencies are included in multilib repositories. A typical split of a package is:


 * foo for the binaries


 * foo-libs for the libraries


 * foo-devel for the development headers, and development symlinks

foo-devel and foo both requires foo-libs, and foo isn't present in multilib repository.


 * wrapper scripts may be used to run a binaries based on which one is present. Here is a script example (adapted from firefox)

ARCH=$(uname -m)

case $ARCH in x86_64 | sparc64 | s390x | ppc64) LIB_DIR=/usr/lib64 SECONDARY_LIB_DIR=/usr/lib LIB_DIR=/usr/lib SECONDARY_LIB_DIR=/usr/lib64 esac

if [ ! -x $LIB_DIR/package-0.0.1/foo ] ; then if [ ! -x $SECONDARY_LIB_DIR/package-0.0.1/foo ] ; then echo "Error: $LIB_DIR/package-0.0.1/foo not found" if [ -d $SECONDARY_LIB_DIR ] ; then echo "      $SECONDARY_LIB_DIR/package-0.0.1/foo not found" fi exit 1 fi LIB_DIR=$SECONDARY_LIB_DIR fi

Another way to handle those conflicts could be to have a different directory for each architecture, even for executables, enabling Fedora to be multiarch and not only multilib.

Splitting libraries into separate packages
If you have binaries, libraries, configuration, and data files all in the same package, conflicts can also arise. One way to fix this is to split libraries off into a separate lib or -libs package. However, some care must be done when doing this in order to ensure proper upgrades.

For example, if you previously had:

foo-1.1-1

that had binaries, libraries, etc. and had file conflcits, and you split the package into: into:

foo-1.1-2 foo-libs-1.1-2

you should add:

Obsoletes: foo < 1.1-2

in the %package section for foo-libs. This ensures that an upgrade with yum will remove the older foo for any alternative architecture.