Cookutils: receipts v2

SliTaz receipts v2

Version 2 was developed as an extension of the receipts in order to facilitate the maintenance of packages by small forces. Back to the Cookutils documentation.

Main and split packages

In order to switch to version 2, you must specify 'v2' in the first line of the receipt:

# SliTaz package receipt v2.

You can write a single receipt v2 to compile, for example the attr sources and then make two packages: attr and attr-dev using the compiled files. Next we will call attr the main package, while attr-dev the split package.

You must specify all the names of split packages that must be created after the compilation in the SPLIT variable. Example for our attr receipt:

SPLIT="attr-dev"

You must specify rules to generate each package inside genpkg_rules(). Example for package attr:

genpkg_rules() {
    case $PACKAGE in
        attr) copy @std ;;
        attr-dev) copy @dev ;;
    esac
}

Here, in every rule you can:

Long descriptions

You may provide a description.txt for the main package and/or description.package-name.txt for any of the split packages.

Converting a v1 receipt: checklist

A v1 package with splits has one directory per package (foo/, foo-dev/ with WANTED="foo"...). Merging them into one v2 receipt went wrong in the same few ways many times (September 2026), check each point:

  1. Line 1 is # SliTaz package receipt v2. -- without v2, cook ignores SPLIT and only the main package is built (pan, sylpheed, gpxe).
  2. Every split is listed in SPLIT (not twice) and has its branch in the case "$PACKAGE" in of genpkg_rules(); the main package branch has the exact main package name (a foo-dev) branch written twice left xfprint empty).
  3. Every branch ends with ;;, and run sh -n receipt before committing. One receipt with a syntax error kills the cooker's architecture database: every package after it in alphabetical order is silently skipped on marmite ("Cooker arch : skip ..." in log/commits.log).
  4. Each new branch copies everything the old split receipt copied. copy @dev does not take extra dirs such as /usr/share/apr-1 (build rules), /usr/share/idl or tools in bin/: add them (copy @dev idl/). Read the Changes since ...: files : +N -M block of the cook log, every - line is a file no package ships any more.
  5. The main package keeps what it shipped before: a copy *.so* or cook_copy_files *.so.* line is easy to lose (net-snmp shipped no library).
  6. DEPENDS, CONFIG_FILES, TAGS... are set in the split rule that needs them (splits do not inherit them, see above).
  7. Install/remove functions of the main package get the _<main> suffix (see below).
  8. Paths to annex files use $stuff, not stuff/: in v2 all the packages share the main package stuff/ directory (cp -a stuff/* shipped the patches into QtDesigner).
  9. Remove the old split directories in the same commit.

post_install() and friends

You may define one of the following functions:

These functions may be defined for every one of main or split packages, so you need to extend function names with an underscore (_) and the package name. Like this for the cookutils package:

post_install_cookutils()

Attention! You should know that some characters that are valid in package names are not allowed in function names. Please, substitute each symbol that doesn't belong to the intervals A-Z, a-z, 0-9 by yet another underscore (_). Example for coreutils-disk:

post_install_coreutils_disk()

Cook copies post_install_cookutils() into the cookutils package only, renamed post_install(): tazpkg and spk only ever see the standard names.

Attention! A function WITHOUT the suffix (plain post_install()) is copied into EVERY package of the receipt, -dev, -lang and -doc included, with $PACKAGE set to that split. When converting a v1 receipt, rename the old install/remove functions of the main package with its suffix, or else:

A typo in the name (post_removel_...) is silently ignored: the function is never copied.

To keep the plain function out of one package, add a line starting with no_post_install_<name> (or no_pre_install_, no_post_remove_, no_pre_remove_) to the receipt, for example no_post_install_linux_libre_source="no modules are installed": cook then copies no such function into that package.

Function copy()

It's the flexible tool allowing you to copy files and folders from $install to $fs using patterns. All files are copied with the folder structure preserved:

  $install/my/folder/       ->   $fs/my/folder/
  $install/my/system/file   ->   $fs/my/system/file

copy() understands 4 main forms of patterns:

Both patterns @std and @dev are meta-patterns making the most common actions extremely simple. Here all files are divided into three types: standard, development and all the others (documentation, translations, etc). You may put @std into the "standard" package, @dev into the "developer" package, not packaging any documentation, man pages, translations, BASH completion, etc...

In the folder/ and file forms of the patterns you can use the asterisk (*) symbol meaning any number of any characters.

Some examples (executed in the chroot with the "busybox" package installed):

PatternResult
bin/ /bin
/usr/bin
*bin/ /bin
/sbin
/usr/bin
/usr/sbin
/var/www/cgi-bin
/usr/bin/ /usr/bin
usr/bin/ /usr/bin
r/bin/ (nothing)
cat /bin/cat
*.sh /lib/libtaz.sh
/sbin/mktazdevs.sh
/usr/bin/gettext.sh
/usr/bin/httpd_helper.sh
/usr/lib/slitaz/httphelper.sh
/usr/lib/slitaz/libpkg.sh
/var/www/cgi-bin/cgi-env.sh
pt* /dev/pts
/usr/share/locale/pt_BR
/usr/share/locale/pt_BR/LC_MESSAGES
/bin/*.sh /usr/bin/gettext.sh
/usr/bin/httpd_helper.sh
/lib/*.sh /lib/libtaz.sh
/usr/lib/slitaz/httphelper.sh
/usr/lib/slitaz/libpkg.sh

Additional patterns for copy():

Some more examples of using copy()

If your packages are used only for development purposes (like automake, flex, vala and some others), you may use the next command to put all the files you want to pack into one package:

copy @std @dev

In most cases, the package breaks up into "main" and "dev" packages. In this case, your code might look like this:

PACKAGE="my-package"
SPLIT="my-package-dev"

genpkg_rules() {
    case $PACKAGE in
        my-package)
            copy @std
            DEPENDS="your-package"
            ;;
        *-dev)
            copy @dev
            ;;
    esac
}

In the following example, a package can contain libraries (which can be used by other programs) and executables that use these libraries. We need to split @std into two parts: libraries and executable files. This can be done in a few ways.

PACKAGE="my-pkg"
# We omit "my-pkg" in the $SPLIT, then it is implicit in the first place
SPLIT="my-pkg-bin my-pkg-dev"
genpkg_rules() {
    case $PACKAGE in
        my-pkg) copy *.so*;; # (1) copy all the libs
        *-bin)  copy bin/;;  # (2) copy all the execs from /usr/bin/
        *-dev)  copy @dev;;  # (3) copy development files
    esac
}
# If a package contains some more files outside of the /bin/ (for example,
# configs), that we want to pack with the "bin" package:
PACKAGE="my-pkg"
SPLIT="my-pkg-bin my-pkg-dev"
genpkg_rules() {
    case $PACKAGE in
        my-pkg) copy *.so*;;    # (1) copy all the libs
        *-bin)  copy @std @rm;; # (2) copy standard (binaries and configs, etc),
                                #     then remove already packed (libs)
        *-dev)  copy @dev;;     # (3) copy development files
    esac
}
# Pack two different libraries into two packages, and the rest into a third
# package:
PACKAGE="my-pkg"
# We explicitly specify all the packages, therefore they will be processed
# in the specified order
SPLIT="my-pkg-lib1 my-pkg-lib2 my-pkg my-pkg-dev"
genpkg_rules() {
    case $PACKAGE in
        *-lib1) copy lib-cli.so*;; # (1) copy first libraries
        *-lib2) copy lib-gui.so*;; # (2) copy second libraries
        my-pkg) copy @std @rm;;    # (3) copy all the standard files,
                                   #     then remove already packed (libs)
        *-dev)  copy @dev;;        # (4) copy development files
    esac
}

Compiling sets

Sometimes you may need to compile the same source code of the same version, but with different options. For example, without PAM support and with PAM support. Or with support for GTK+2 or GTK+3. Or a complete package with all the rich features and a small limited package. You can not limit yourself in the number of options.

A compiling set is a pair of separate $src and $install folders. You can still compile the sources using the $src variable and install compiled files into the folder defined by the $install variable, but these values will be different for the different compiling sets.

A set is defined by its name, which is a simple mnemonic made up of one or more letters or numbers. It may be "1", "2", "z", or something more meaningful like "pam", "gtk2", or "gtk3".

Also you should know that the default set with the empty name always exists for backward compatibility and for the cases when you don't want to use the sets.

How to use the sets?

First, you should define which set you want to use for each package appending package names in the $SPLIT variable. You don't have to do it for the default set with the empty name. A few examples:

PACKAGE="fuse-emulator"
SPLIT="fuse-emulator-gtk3:gtk3"
PACKAGE="yad"
SPLIT="yad-html:html yad-gtk3:gtk3"
PACKAGE="urxvt"
SPLIT="urxvt-full:full"

Second, the function compile_rules() will be executed sequentially for the default set and then for all the sets you mention in the $SPLIT variable on the previous step. You should put the business logic inside the compile_rules() function to compile and install different variants based on the value of the $SET variable. This variable has an empty value for the default set and the set name in other cases. A few examples of how you do the job:

PACKAGE="fuse-emulator"
SPLIT="fuse-emulator-gtk3:gtk3"

compile_rules() {
    SET_ARGS=''; [ -z "$SET" ] && SET_ARGS='--disable-gtk3'

    ./configure \
        --enable-desktop-integration \
        $SET_ARGS \
        $CONFIGURE_ARGS &&
    make && make install
}
PACKAGE="urxvt"
SPLIT="urxvt-full:full"

compile_rules() {
    case $SET in
        '')
            ./configure \
                --disable-everything \
                $CONFIGURE_ARGS &&
            make && make install
            ;;
        full)
            ./configure \
                --enable-everything \
                --enable-256-color \
                --with-terminfo=/usr/share/terminfo \
                $CONFIGURE_ARGS &&
            make && make install || return 1

            R="$install/usr/share/terminfo"
            mkdir -p $R
            tic -s -o $R $src/doc/etc/rxvt-unicode.terminfo
            ;;
    esac
}
PACKAGE="yad"
SPLIT="yad-html:html yad-gtk3:gtk3"

compile_rules() {
    case $SET in
        '')   Gtk=gtk2; Html=disable;;
        html) Gtk=gtk2; Html=enable ;;
        gtk3) Gtk=gtk3; Html=disable;;
    esac

    ./configure \
        --enable-icon-browser \
        --with-gtk=$Gtk \
        --$Html-html \
        $CONFIGURE_ARGS &&
    make &&
    make install
}

Thirdly, write genpkg_rules() as usual. Cook will switch to the required set automatically based on the conformity between packages and sets that you described in the $SPLIT variable on the first step. That's all.

Dependency tracking

Many packages use libtool, created during the configure processing. This libtool contains one old and well-known (in narrow circles) "feature" that is expressed in the fact that unnecessary dependencies are added to libraries and executable files. Read about it:

The links above recommend adding -Wl,--as-needed to the LDFLAGS variable (the default cook.conf already does it). You can use the short statement fix ld at the beginning (to add -Wl,--as-needed to the LDFLAGS) and fix libtool just after the configure invocation (to additionally fix the just created libtool). Example of use:

compile_rules() {
    fix ld
    ./configure \
        --sysconfdir=/etc \
        $CONFIGURE_ARGS &&
    fix libtool &&
    make && make install
}

You should not use fix libtool if you do not see a file named libtool in the root of the sources tree after the configure is done. It will not lead to an error, although there will be no sense in it.

You can check dependencies of separate files using one of the next methods:

ldd /path/to/file

readelf -d /path/to/file | grep NEEDED

You can check dependencies of an entire package using the command (cook package_name --deps is a shortcut for it):

cook-deps package_name

You can note a significant decrease in the number of dependencies. For example:

For some packages nothing will change.

Dependency tracking for development packages

This is a separate and complex issue.

Dependency info may be extracted from .pc, .la and .h files. Extracting dependencies from the header files (.h) is a non-trivial task due to conditional branching and can not be realized using simple tools.

As for .la files, Gentoo recommends to remove them in most cases. As they state, .la files may be useful only for static libraries (.a files). Currently, the dependency tracking tool doesn't use .la files unless you provide the special argument --la:

cook-deps fontconfig --la

It turns out that .pc files are the only development files that describe dependencies of development packages. Usually the configure script checks dependencies using something like this:

pkg-config --exists --print-errors "gtk-doc >= 1.15"
pkg-config --exists --print-errors "xrender >= 0.6"

Dependency tracking tools try to find the package that contains the required libraries, then determine a *-dev package that corresponds to the found package.

For example, the file /usr/lib/pkgconfig/cairo.pc contains the line:

Requires.private:   gobject-2.0   glib-2.0 >= 2.14   pixman-1 >= 0.30.0
    fontconfig >= 2.2.95   freetype2 >= 9.7.3   libpng    xcb-shm    x11-xcb
    xcb >= 1.6   xcb-render >= 1.6   xrender >= 0.6   x11   xext

Finding the next files shows the dependencies:

gobject-2.0.pc   glib-2.0.pc   pixman-1.pc   fontconfig.pc   freetype2.pc
    libpng.pc   xcb-shm.pc   x11-xcb.pc   xcb.pc   xcb-render.pc   xrender.pc
    x11.pc   xext.pc

Next example using the file /usr/lib/pkgconfig/apr-1.pc:

prefix=/usr
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
APR_MAJOR_VERSION=1

Libs: -L${libdir} -lapr-${APR_MAJOR_VERSION} -luuid -lrt -lcrypt  -lpthread -ldl

Finding the next files shows the runtime dependencies and then the full dependencies; *-dev packages are the full packages.

libapr-1.so    libuuid.so      librt.so   libcrypt.so   libpthread.so   libdl.so
     |             |               |           |              |            |
     v             v               v           v              v            v
    apr     util-linux-uuid   glibc-base  glibc-base     glibc-base   glibc-base
     |             |               |           |              |            |
     v             v               v           v              v            v
  apr-dev  util-linux-uuid-dev glibc-dev   glibc-dev      glibc-dev    glibc-dev

Note, sometimes the required files may be found in two or more packages, for example, libdl.so exists within packages: