From Fedora Project Wiki
m (1 revision(s))
(→‎Doxygen footers: Use HTML_TIMESTAMP)
 
(7 intermediate revisions by 5 users not shown)
Line 24: Line 24:
Then you can use the diff or cmp utilities to discover exactly what is different between the conflicting files.
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 ====
==== Architecture dependent header files ====


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:
Some packages install header files (typically named <code>*config.h</code>, usually generated by build system) which will have something in them relating to the byte size of some types at compile time.
 
Such files then have different contents on multilib-counterpart architectures (e.g. x86_64 vs. i386) while those still share the same installation path. This kind of API specification is bad in most cases, however, since an API should be completely platform independent.
 
The best believed solution for this issue is to have it fixed once and forever upstream – for example use integer types of a length independent from the platform (integers like int32_t from inttypes.h can be used). For many projects this is infeasible.
 
One possible way to get around this problem downstream is (considering that the architecture-dependent file is named <code>config.h</code> and we build on x86_64 platform) to move the <code>config.h</code> file into <code>config-64.h</code> and install architecture-independent "stub" header file <code>config.h</code>:


<pre>
<pre>
#include <bits/wordsize.h>


#if __WORDSIZE == 32
#include "config-32.h"
#elif __WORDSIZE == 64
#include "config-64.h"
#else
#else
#error "Unknown word size"
#endif
#endif
</pre>
</pre>


This kind of API specification is bad in most cases, however, since an API should be completely platform independent.
There is convenient RPM macro '%multilib_fix_c_header' in multilib-rpm-config package that allows you to automatize this, typically you can use this pattern:
 
<pre>
BuildRequires: multilib-rpm-config
...
%install
...
make install DESTDIR=%{buildroot}
...
# Replace arch-dependent header file with arch-independent stub (when needed).
%multilib_fix_c_header --file %{_includedir}/package/config.h


If what is needed are integer of a length independent from the platform, integers like <code>int32_t</code> from inttypes.h can be used.
%files
%{_includedir}/package
</pre>


==== Doxygen footers ====
==== Doxygen footers ====


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


<pre>
<pre>
HTML_FOOTER           = no_date_footer.html
HTML_TIMESTAMP           = NO
</pre>
</pre>


The <code>no_date_footer.html</code> file could be along:
This is the default setting in current Doxygen, but some projects may supply their own config file with this set to YES.
 
<pre>
<hr size="1"><address style="text-align: right;"><small>
Generated for $projectname by&nbsp;<a href="http://www.doxygen.org/
index.html"><img src="doxygen.png" alt="doxygen" align="middle" border="0"></a>
$doxygenversion</small></address>
</body>
</html>
</pre>


==== PNG images ====
==== PNG images ====
Line 94: Line 108:


In multilib environments there is a preferred architecture, 64
In multilib environments there is a preferred architecture, 64
bit over 32 bit in x86_64, 32 bit over 64 bit in ppc64. When a conflict
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
is found between two packages corresponding with different arches, the
installed file is the one from the preferred arch. This is very common
installed file is the one from the preferred arch. This is very common
Line 129: Line 143:


case $ARCH in
case $ARCH in
x86_64 | ia64 | s390 )
x86_64 | sparc64 | s390x | ppc64)
LIB_DIR=/usr/lib64
LIB_DIR=/usr/lib64
SECONDARY_LIB_DIR=/usr/lib
SECONDARY_LIB_DIR=/usr/lib
Line 180: Line 194:


in the %package section for foo-libs. This ensures that an upgrade with yum will remove the older foo for any alternative architecture.
in the %package section for foo-libs. This ensures that an upgrade with yum will remove the older foo for any alternative architecture.
[[Category:Packaging guidelines drafts]]

Latest revision as of 17:49, 2 January 2017

Multi lib tricks

Architecture independent files

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.

Architecture dependent header files

Some packages install header files (typically named *config.h, usually generated by build system) which will have something in them relating to the byte size of some types at compile time.

Such files then have different contents on multilib-counterpart architectures (e.g. x86_64 vs. i386) while those still share the same installation path. This kind of API specification is bad in most cases, however, since an API should be completely platform independent.

The best believed solution for this issue is to have it fixed once and forever upstream – for example use integer types of a length independent from the platform (integers like int32_t from inttypes.h can be used). For many projects this is infeasible.

One possible way to get around this problem downstream is (considering that the architecture-dependent file is named config.h and we build on x86_64 platform) to move the config.h file into config-64.h and install architecture-independent "stub" header file config.h:

#include <bits/wordsize.h>

#if __WORDSIZE == 32
#include "config-32.h"
#elif __WORDSIZE == 64
#include "config-64.h"
#else
#error "Unknown word size"
#endif

There is convenient RPM macro '%multilib_fix_c_header' in multilib-rpm-config package that allows you to automatize this, typically you can use this pattern:

BuildRequires: multilib-rpm-config
...
%install
...
make install DESTDIR=%{buildroot}
...
# Replace arch-dependent header file with arch-independent stub (when needed).
%multilib_fix_c_header --file %{_includedir}/package/config.h

%files
%{_includedir}/package

Doxygen footers

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

HTML_TIMESTAMP            = NO

This is the default setting in current Doxygen, but some projects may supply their own config file with this set to YES.

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 -L$libdir 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<foo> or <foo>-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.