Fink

Packaging Tutorial - 2. Example - the Maxwell Package

2.1 Basics

First Maxwell. Lets open our editor and get started. We know the package name, its version and where to grab the source tar ball from. So we'll type this into our editor window:

Package: maxwell
Version: 0.5.1
Revision: 1
Source: mirror:sourceforge:%n/%n-%v.tar.gz

So we have the name and version which are easy to understand, but what of these other two fields? Revision is the "version" of the Fink package, Version, on the other hand is the upstream source version. Since this is the first time we have attempted to make a maxwell-0.5.1 package, it is revision 1.

The Source field is where fink will grab the source tarball from. Because Sourceforge has a system where packages are mirrored around the world, and since fink knows about it, we use mirror:sourceforge:. %n expands to the package name, maxwell, and %v expands to the package version, 0.5.1.

Now we can save this as maxwell.info in /opt/sw/fink/dists/local/main/finkinfo/. That done, we can see how we are doing by using fink validate.

finkdev% fink validate maxwell.info 
Validating package file maxwell.info...
Error: Required field "Maintainer" missing. (maxwell.info)

Oops, looks like we missed a couple of fields. Lets add some more:

Maintainer: John Doe <jdoe@example.com>
HomePage: http://maxwell.sourceforge.net
License: MIT

We add ourselves as the maintainer of the Fink maxwell package and add it's homepage, looking at the sourceforge project page, we see that it is MIT Licensed, so we add that too. Now lets try again:

finkdev% fink validate maxwell.info
Validating package file maxwell.info...
Warning: Unknown license "MIT". (maxwell.info)
Error: No MD5 checksum specified for "source". (maxwell.info)
Error: No package description supplied. (maxwell.info)

Aaargh! We seem to be getting worse, not better, never mind, head off over to the Packaging Manual to see what is allowed for License, and we see that we can just change MIT to OSI-Approved, as the MIT license is, indeed, approved by the OSI. We can also grab a one line description of the package from the homepage. So we change those:

License: OSI-Approved
Description: Mac OS X S.M.A.R.T. Tool

But what to do about that warning about MD5 checksums? Well, why don't we just ask fink to fetch the source?

finkdev% fink fetch maxwell
/usr/bin/sudo /opt/sw/bin/fink  fetch maxwell
Reading package info...
Updating package index... done.
Information about 3377 packages read in 30 seconds.
WARNING: No MD5 specified for Source of package maxwell-0.5.1-1 \
Maintainer: John Doe <jdoe@example.com>
curl -f -L -O http://distfiles.opendarwin.org/maxwell-0.5.1.tar.gz
  % Total    % Received % Xferd  Average Speed          Time             Curr.
                                 Dload  Upload Total    Current  Left    Speed
  0     0    0     0    0     0      0      0 --:--:--  0:00:00 --:--:--     0
curl: (22) The requested URL returned error: 404
### execution of curl failed, exit code 22
Downloading the file "maxwell-0.5.1.tar.gz" failed.

(1)      Give up
(2)      Retry the same mirror
(3)      Retry another mirror from your continent
(4)      Retry another mirror
(5)      Retry using next mirror set "sourceforge"

How do you want to proceed? [3] 5
curl -f -L -O http://west.dl.sourceforge.net/sourceforge/maxwell/maxwell-0.5.1.tar.gz
  % Total    % Received % Xferd  Average Speed          Time             Curr.
                                 Dload  Upload Total    Current  Left    Speed
100  7856  100  7856    0     0  19838      0  0:00:00  0:00:00  0:00:00 6511k

The tarball couldn't be downloaded from the Fink mirrors (distfiles) since your package is not added to the distribution yet. That's why you need to change to the next mirror set. More information about this problem is in the FAQ.

So we can now get the md5 by running md5sum /opt/sw/src/maxwell-0.5.1.tar.gz, and add it to the .info file:

Source-MD5: ce5c354b2fed4e237524ad0bc59997a3

And now we find that fink validate passes, yippee!

2.2 Build

Now we can build the package, let's just try it:

finkdev% fink -m --build-as-nobody rebuild maxwell
/usr/bin/sudo /opt/sw/bin/fink  build maxwell
Reading package info...
Updating package index... done.
Information about 3498 packages read in 32 seconds.
The following package will be built:
 maxwell
gzip -dc /opt/sw/src/maxwell-0.5.1.tar.gz | /opt/sw/bin/tar -xvf -  \
--no-same-owner --no-same-permissions 
maxwell-0.5.1/
maxwell-0.5.1/LICENSE
maxwell-0.5.1/Makefile
maxwell-0.5.1/maxwell.8
maxwell-0.5.1/maxwell.c
maxwell-0.5.1/README
./configure --prefix=/opt/sw 
Can't exec "./configure": No such file or directory at \
/opt/sw/lib/perl5/Fink/Services.pm line 403.

Hmm, well that did not go all that well. Let's read the README (which you can find at /opt/sw/src/maxwell-0.5.1-1/maxwell-0.5.1/README) and see what it says...

To build type 'make'.

To install in /usr/local type 'sudo make install', to install elsewhere, type 
'sudo make install prefix=/elsewhere'

Ah hah, so we can't use the default CompileScript and InstallScript here, we need our own, that's easily resolved:

CompileScript: make
InstallScript: <<
#! /bin/sh -ev
make install prefix=%i
<<

We need to use prefix=%i since fink builds the binary deb file from the files in %i. These files are later installed into %p (which is /opt/sw by default) when you use fink install maxwell. For more details about %p and %i please consult the Packaging Manual.

Normally the lines in the Script fields are passed line by line to the shell. But the #! /bin/sh -ev line makes fink run it as a separate script. The parameter -e means "die on error" and -v means "verbose".

So, let's validate the package again and try to rebuild it:

finkdev% fink validate maxwell.info 
Validating package file maxwell.info...
Package looks good!
finkdev% fink -m --build-as-nobody rebuild maxwell
/usr/bin/sudo /opt/sw/bin/fink  build maxwell
Reading package info...
Updating package index... done.
Information about 3498 packages read in 32 seconds.
The following package will be built:
 maxwell
gzip -dc /opt/sw/src/maxwell-0.5.1.tar.gz | /opt/sw/bin/tar -xvf -  \
--no-same-owner --no-same-permissions 
maxwell-0.5.1/
maxwell-0.5.1/LICENSE
maxwell-0.5.1/Makefile
maxwell-0.5.1/maxwell.8
maxwell-0.5.1/maxwell.c
maxwell-0.5.1/README
make
cc  -L/opt/sw/lib -c -o maxwell.o maxwell.c
cc  -I/opt/sw/include -o maxwell -framework IOKit -framework CoreFoundation maxwell.o
/bin/rm -rf /opt/sw/src/root-maxwell-0.5.1-1
/bin/mkdir -p /opt/sw/src/root-maxwell-0.5.1-1/opt/sw
/bin/mkdir -p /opt/sw/src/root-maxwell-0.5.1-1/DEBIAN
/var/tmp/tmp.1.A3sRc2
#! /bin/sh -ev
make install prefix=/opt/sw/src/root-maxwell-0.5.1-1/opt/sw
/usr/bin/install -d -m 755 /opt/sw/src/root-maxwell-0.5.1-1/opt/sw/doc/maxwell
/usr/bin/install -m 644 LICENSE /opt/sw/src/root-maxwell-0.5.1-1/opt/sw/doc/maxwell/LICENSE
/usr/bin/install -m 644 README /opt/sw/src/root-maxwell-0.5.1-1/opt/sw/doc/maxwell/README
/usr/bin/install -d -m 755 /opt/sw/src/root-maxwell-0.5.1-1/opt/sw/bin
/usr/bin/install -m 755 maxwell /opt/sw/src/root-maxwell-0.5.1-1/opt/sw/bin/maxwell
/usr/bin/install -d -m 755 /opt/sw/src/root-maxwell-0.5.1-1/opt/sw/man/man8
/usr/bin/install -m 644 maxwell.8 /opt/sw/src/root-maxwell-0.5.1-1/opt/sw/man/man8/maxwell.8
/bin/rm -f /opt/sw/src/root-maxwell-0.5.1-1/opt/sw/info/dir \
/opt/sw/src/root-maxwell-0.5.1-1/opt/sw/info/dir.old \
/opt/sw/src/root-maxwell-0.5.1-1/opt/sw/share/info/dir \
/opt/sw/src/root-maxwell-0.5.1-1/opt/sw/share/info/dir.old
Writing control file...
Finding prebound objects...
Writing dependencies...
Writing package script postinst...
dpkg-deb -b root-maxwell-0.5.1-1 /opt/sw/fink/dists/local/main/binary-darwin-powerpc
dpkg-deb: building package `maxwell' in \
`/opt/sw/fink/dists/local/main/binary-darwin-powerpc/maxwell_0.5.1-1_darwin-powerpc.deb'.

Fink seems to have installed everything into the correct place: /opt/sw/src/root-maxwell-0.5.1-1 from where the binary package maxwell_0.5.1-1_darwin-powerpc.deb was built.

Also note how fink automatically included some compiler flags to enable it to access other Fink packages (e.g. -I/opt/sw/include).

Let's have a look at what is in the binary package:

finkdev% dpkg -c \
/opt/sw/fink/dists/local/main/binary-darwin-powerpc/maxwell_0.5.1-1_darwin-powerpc.deb
drwxr-xr-x root/admin        0 2004-07-15 09:40:38 ./
drwxr-xr-x root/admin        0 2004-07-15 09:40:39 ./opt/sw/
drwxr-xr-x root/admin        0 2004-07-15 09:40:39 ./opt/sw/bin/
-rwxr-xr-x root/admin    29508 2004-07-15 09:40:39 ./opt/sw/bin/maxwell
drwxr-xr-x root/admin        0 2004-07-15 09:40:39 ./opt/sw/doc/
drwxr-xr-x root/admin        0 2004-07-15 09:40:39 ./opt/sw/doc/maxwell/
-rw-r--r-- root/admin     1076 2004-07-15 09:40:39 ./opt/sw/doc/maxwell/LICENSE
-rw-r--r-- root/admin     1236 2004-07-15 09:40:39 ./opt/sw/doc/maxwell/README
drwxr-xr-x root/admin        0 2004-07-15 09:40:39 ./opt/sw/man/
drwxr-xr-x root/admin        0 2004-07-15 09:40:39 ./opt/sw/man/man8/
-rw-r--r-- root/admin     1759 2004-07-15 09:40:39 ./opt/sw/man/man8/maxwell.8
drwxr-xr-x root/admin        0 2004-07-15 09:40:39 ./opt/sw/var/
drwxr-xr-x root/admin        0 2004-07-15 09:40:39 ./opt/sw/var/lib/
drwxr-xr-x root/admin        0 2004-07-15 09:40:39 ./opt/sw/var/lib/fink/
drwxr-xr-x root/admin        0 2004-07-15 09:40:39 ./opt/sw/var/lib/fink/prebound/
drwxr-xr-x root/admin        0 2004-07-15 09:40:39 ./opt/sw/var/lib/fink/prebound/files/
-rw-r--r-- root/admin       16 2004-07-15 09:40:39 ./opt/sw/var/lib/fink/prebound/files/maxwell.pblist

Seems ok, right? But we have to verify that it complies with the Fink packaging policy. So let's validate it with:

finkdev% fink validate \
/opt/sw/fink/dists/local/main/binary-darwin-powerpc/maxwell_0.5.1-1_darwin-powerpc.deb 
Validating .deb file \
/opt/sw/fink/dists/local/main/binary-darwin-powerpc/maxwell_0.5.1-1_darwin-powerpc.deb...
Warning: File installed into deprecated directory /opt/sw/doc/
                                        Offender is /opt/sw/doc/
Warning: File installed into deprecated directory /opt/sw/doc/
                                        Offender is /opt/sw/doc/maxwell/
Warning: File installed into deprecated directory /opt/sw/doc/
                                        Offender is /opt/sw/doc/maxwell/LICENSE
Warning: File installed into deprecated directory /opt/sw/doc/
                                        Offender is /opt/sw/doc/maxwell/README
Warning: File installed into deprecated directory /opt/sw/man/
                                        Offender is /opt/sw/man/
Warning: File installed into deprecated directory /opt/sw/man/
                                        Offender is /opt/sw/man/man8/
Warning: File installed into deprecated directory /opt/sw/man/
                                        Offender is /opt/sw/man/man8/maxwell.8

Oops... something is wrong. Let's consult the Packaging Manual again. It tells us to install man pages into /opt/sw/share/man and files such as README into /opt/sw/share/doc/%n. If we look into the Makefile of maxwell we see that the mandir and datadir can be set:

prefix = /usr/local
mandir = ${prefix}/man
man8dir = ${mandir}/man8
bindir = ${prefix}/bin
datadir = ${prefix}/doc/maxwell

One easy way to fix that is to change the InstallScript to

make install prefix=%i mandir=%i/share/man datadir=%i/share/doc/%n

and rebuild the package with

finkdev% fink -m --build-as-nobody rebuild maxwell

(We used fink rebuild because fink build would not do anything since the package was already built successfully.)

Review the contents of your deb file (with dpkg -c) to see where the files got installed now. Then validate the deb file again with fink validate. If all is well you can install the new package with:

finkdev% fink install maxwell
/usr/bin/sudo /opt/sw/bin/fink  install maxwell
Information about 3377 packages read in 30 seconds.
The following package will be installed or updated:
 maxwell
dpkg -i /opt/sw/fink/dists/local/main/binary-darwin-powerpc/maxwell_0.5.1-1_darwin-powerpc.deb
Selecting previously deselected package maxwell.
(Reading database ... 56046 files and directories currently installed.)
Unpacking maxwell (from .../maxwell_0.5.1-1_darwin-powerpc.deb) ...
Setting up maxwell (0.5.1-1) ...

You can now run the software by typing

finkdev% maxwell

Congratulations, you just finished your first Fink package! Now try to package something yourself by following the Packaging tutorial from the beginning.

We are looking forward to your contributions to Fink!