Solaris/FOSS specfiles

From KDE Community Wiki

Currently, solaris.bionicmutton.org/SRC contains some tarballs that originate from Stefan Teleman's KDE4 on Solaris porting effort. The tarballs are almost always a relative directory starting with Solaris/, and contain patch, configure, build, and install scripts, as well as patches, and any custom files needed to build a module.

However, they are difficult to deal with, and regenerating them is a bit of a PITA, and pretty much makes working on KDE4 an exclusive club with secret handshake, because unless you have a full Dude checkout (like 7GB) it can be a real hassle.

Starting in the kde4-specs-440 tree, there is an effort going on to convert all those modules from the DUDE tarball, to a purely spec format. Due to the fact that the FOSS modules are built for both 32-bit and 64-bit, there are two components minimum to each module.

1) FOSS<modulename>.spec - this contains all the high level information, with package name, version, description, license, package dependencies, and a package list. Any new modules or updated modules should include a explicit package list, so that changes between versions of packages can be tracked. Globals in the plist is just sloppy. Unless you know what should pop out, generate a complete plist. How do you do that? Use a global plist, and then convert it using this little gem with the pkg name.

ie: ./extract_plist.sh FOSSexpat

This need correction since /opt/foss was folded to /opt/kde

#!/bin/bash
if [ -z "$1" ]; then
echo "no package"
exit
fi
pkginfo -q $1
if [ $? -ne 0 ]; then
echo "pkg $1 not found"
exit 1
fi
egrep "${1}$|${1} " /var/sadm/install/contents | \
cut -f1-2 -d\ | egrep -v d$ |\ awk '{print $1}' | \
cut -f1 -d= | sed -e 's,/opt/kde4/include,%{_includedir},' \
-e 's,/opt/kde4/lib/amd64,%{_libdir}/%{_arch64},' \
-e 's,/opt/kde4/lib/,%{_libdir}/,'\
-e 's,/opt/kde4/bin/amd64,%{_bindir}/%{_arch64},' \
-e 's,/opt/kde4/sbin/amd64,%{_sbindir}/%{_arch64},' \
-e 's,/opt/kde4/sbin/,%{_sbindir}/,' -e 's,/opt/kde4/bin/,%{_bindir}/,' \
-e 's,/opt/kde4/share/locale,%{_localedir},' \
-e 's,/opt/kde4/share/man,%{_mandir},' \
-e 's,/opt/kde4/share/aclocal,%{_datadir}/aclocal,' \
-e 's,/opt/kde4/share/doc,%{_docdir},' \
-e 's,/opt/kde4/qt4/include,%{foss_qt4_inc},'

Basically, it looks for the pkg in the contents file, extracts the files (and not the dirs, since most high level ones we've already defined, and the lower ones can become really tedious to document, *especially* locale), and then converts it to a appropriate plist format. then glue in the pieces.

2) base-specs/base-<module>.spec - this contains pretty much what was found in the DUDE Solaris tarball (typically Solaris-PGKNAME-REVISION,MINORREV.tar.gz). Decomposing a Solaris tarball should go something like this:

a) extract all the patches. prefix them with the packagename-version, postfixed with an index starting at 01, and ending in .diff

typically, an apply_patches script has something like:

#!/bin/sh
for file in \
     configure.diff \
     config.h.diff \
     Makefile.diff \
     somecfile.c.diff \
     somecfile.h.diff
do
     gpatch -p1 Solaris/diffs/$file
done

I convert it to read:

#!/bin/sh
N=0
   for file in \
     configure.diff \
     config.h.diff \
     Makefile.diff \
     somecfile.c.diff \
     somecfile.h.diff
do
# Strip off the trailing ".diff"
NM=`echo $file | sed 's\.diff$,,'`
#
# in case there's a trailing index value we want to remove...
# so if the file was configure.01.diff, NM sees configure.01,
# and what we really want is "configure".
NM=`echo ${NM} | sed 's,\.[0-9]*$,,'`
#
# just a counter so we can build the patchlist for the spec file,
# and we match it to the patch, so it's really clear which patch
# it should be
#
N=`echo ${N} | awk '{printf "%.02d",$1+1}'`
#
# strip off preceding 0 for the %patch and Patch${Y} commands
Y=`echo ${N} | sed 's,^0,,'`
#
# rename the file to something more "unique"
#
mv $file Mypkg-1.0.1-${NM}.${N}.diff
#
# Create the patchlist entry for this patch.
#
echo "Patch${Y}:\t\t%{patchprefix}-${NM}.${N}.diff" >> patchlist
#
# Create the patching entry for this patch (%prep area)
#
echo "%patch${Y} -p1" >> patching
done

what this does is move all the files into a more "orderly" list with a created patchlist that can be imported into the base-spec file, as well as the patching order.

b) the section above %prep, is where you will insert "patchlist" Above patchlist, you put

%define patchprefix %{src_name}-%{src_ver}

so we don't have to care about changing the stupid patch file names every time we uprev a package. The down side to this is having up copy a new set of patches into the uprev directory, if we're really following this method.

There are a couple of reasons we do this: 1) patches must have unique names because they are copied to packages/SOURCES 2) when we up rev a package, we don't lose the ability to build a previous revision of the package, without some "mecurial" magic. 3) a patch has been submitted the pkgbuild repo to allow the patch mechanism to use relative paths to patches, which means that patches/<PKG_NAME>/<SRC_VER>/patchname.diff. Eventually, this means that spec/patches won't have to be a dumping ground for all patches.

It also makes it dead simple to copy existing patches from a previous revision for a new one and tune those patches for the next revision. To understand this value, I was able to use this method to uprev gstreamer-0.10.17 to gstreamer-0.10.22 iteratively in less that 2 hours. I got stuck at 0.10.23 since that wanted glib2-2.14 and FOSS at that time only had glib2-2.12.12

c) in the %prep section, include "patching" file from above. Additionally, include the configure.sh, converting most ${} variables to %{} variables, unless they are truly shell variables.

d) in the %build section, import build.sh. clean it up

e) in the %install section, import install.sh, clean it up. This section is usually trickiest because of the way 32 and 64 bit binaries get made, and how some packages have a hard time honoring the configured paths.

All your new patches should go in spec/patches/%{src_name}/%{src_ver}.

Using a very simple %if clause, a spec file can now support multiple revisions, with all the behavior customized off that specific version to include package requirements, explicit plists, patches, applying patches, configure changes, etc. It takes a little bit more effort than just chopping up a spec file because a bunch of stuff changed.