Slice a package

This guide provides instructions on the slicing of an Ubuntu package for Chisel.

A package slice is represented via a Slice Definitions File (aka SDF), and the creation of said slice definitions is a result of the inspection and design process depicted below.

As an example, this guide will focus on slicing the vim-tiny package from Ubuntu 24.04.

Inspect the package

Your first task is to understand the package to be sliced.

Packages are primarily composed of files for installation and may reference additional packages as dependencies such as libraries or other resources.

During the slicing process, we identify subsets of files in a package which can be installed alone to accomplish one or more tasks. Consequently, the dependencies required for this slice may be a subset of the dependencies indicated by the package.

  1. Is it an Ubuntu package?

    Chisel only supports packages from the Ubuntu (and Ubuntu Pro) archives.

  2. Get the package dependencies

    You can run apt depends vim-tiny or use the Ubuntu Packages Search website.

    Example: vim-tiny pkg dependencies
    ~$ apt depends vim-tiny
    vim-tiny  Depends: vim-common (= 2:9.1.0016-1ubuntu7.8)  Depends: libacl1 (>= 2.2.23)  Depends: libc6 (>= 2.34)  Depends: libselinux1 (>= 3.1~)  Depends: libtinfo6 (>= 6)  Suggests: indent
  3. Inspect the files the package provides

    You can run apt download vim-tiny and then dpkg -c vim-tiny*.deb to check the package data contents. Or check the vim-tiny package contents in the Ubuntu Packages Search website.

    Note

    A package’s contents and dependencies may change depending on the architecture. Make sure to double check any differences and adjust your slices accordingly.

    Example: vim-tiny contents in Ubuntu 24.04, for amd64
    ~$ dpkg -c vim-tiny_2%3a9.1.0016-1ubuntu7.8_amd64.deb
    drwxr-xr-x root/root         0 2025-04-01 20:12 ./drwxr-xr-x root/root         0 2025-04-01 20:12 ./etc/drwxr-xr-x root/root         0 2025-04-01 20:12 ./etc/vim/-rw-r--r-- root/root       662 2025-04-01 20:12 ./etc/vim/vimrc.tinydrwxr-xr-x root/root         0 2025-04-01 20:12 ./usr/drwxr-xr-x root/root         0 2025-04-01 20:12 ./usr/bin/-rwxr-xr-x root/root   1736392 2025-04-01 20:12 ./usr/bin/vim.tinydrwxr-xr-x root/root         0 2025-04-01 20:12 ./usr/share/drwxr-xr-x root/root         0 2025-04-01 20:12 ./usr/share/bug/drwxr-xr-x root/root         0 2025-04-01 20:12 ./usr/share/bug/vim-tiny/-rw-r--r-- root/root       302 2024-08-27 04:05 ./usr/share/bug/vim-tiny/presubj-rwxr-xr-x root/root       204 2024-08-27 04:05 ./usr/share/bug/vim-tiny/scriptdrwxr-xr-x root/root         0 2025-04-01 20:12 ./usr/share/doc/drwxr-xr-x root/root         0 2025-04-01 20:12 ./usr/share/doc/vim-tiny/-rw-r--r-- root/root     14394 2025-04-01 20:12 ./usr/share/doc/vim-tiny/changelog.Debian.gz-rw-r--r-- root/root     28068 2024-08-27 04:05 ./usr/share/doc/vim-tiny/copyrightdrwxr-xr-x root/root         0 2025-04-01 20:12 ./usr/share/lintian/drwxr-xr-x root/root         0 2025-04-01 20:12 ./usr/share/lintian/overrides/-rw-r--r-- root/root       119 2024-08-27 04:05 ./usr/share/lintian/overrides/vim-tinydrwxr-xr-x root/root         0 2025-04-01 20:12 ./usr/share/vim/drwxr-xr-x root/root         0 2025-04-01 20:12 ./usr/share/vim/vim91/drwxr-xr-x root/root         0 2025-04-01 20:12 ./usr/share/vim/vim91/doc/-rw-r--r-- root/root       324 2024-08-27 04:05 ./usr/share/vim/vim91/doc/README.Debian-rw-r--r-- root/root      1350 2024-08-27 04:05 ./usr/share/vim/vim91/doc/help.txt-rw-r--r-- root/root      1935 2025-04-01 20:12 ./usr/share/vim/vim91/doc/tags

    For vim-tiny, we see that there are a few binaries at /usr/bin/, a few configuration files, the copyright files, manpages and so on.

  4. Inspect the package metadata

    The package metadata files include:

    Run dpkg -e vim-tiny*.deb to extract the metadata files into a new DEBIAN/ directory for inspection.

    1. Inspect package conffiles file

      This file lists the configuration files a package provides. This can be useful later, when deciding whether to create a config slice or not.

      Example: vim-tiny conffiles
      ~$ cat DEBIAN/conffiles
      /etc/vim/vimrc.tiny
    2. Inspect package maintainer scripts

      Since Chisel doesn’t remove files (except when until: mutate is used), we can focus only on the preinst and postinst scripts. Whatever these scripts do, you should aim to reproduce when defining the slices. For the simplest cases where the maintainer scripts are creating new contents (e.g. new symlinks), one should simply declare said paths as contents of the slice. Otherwise, if logic is involved, such scripts should be declared as “mutation scripts”, which are written in Starlark.

      Example: vim-tiny maintainer scripts

      From the postinst script, we see:

      #!/bin/sh
      
      set -e
      
      # Automatically added by dh_installalternatives/13.14.1ubuntu5
      
      if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ]; then
              update-alternatives --install /usr/bin/editor editor /usr/bin/vim.tiny 15 \
                  --slave /usr/share/man/man1/editor.1.gz editor.1.gz /usr/share/man/man1/vim.1.gz \
                  --slave /usr/share/man/da/man1/editor.1.gz editor.da.1.gz /usr/share/man/da/man1/vim.1.gz \
                  --slave /usr/share/man/de/man1/editor.1.gz editor.de.1.gz /usr/share/man/de/man1/vim.1.gz \
                  --slave /usr/share/man/fr/man1/editor.1.gz editor.fr.1.gz /usr/share/man/fr/man1/vim.1.gz \
                  --slave /usr/share/man/it/man1/editor.1.gz editor.it.1.gz /usr/share/man/it/man1/vim.1.gz \
                  --slave /usr/share/man/ja/man1/editor.1.gz editor.ja.1.gz /usr/share/man/ja/man1/vim.1.gz \
                  --slave /usr/share/man/pl/man1/editor.1.gz editor.pl.1.gz /usr/share/man/pl/man1/vim.1.gz \
                  --slave /usr/share/man/ru/man1/editor.1.gz editor.ru.1.gz /usr/share/man/ru/man1/vim.1.gz \
                  --slave /usr/share/man/tr/man1/editor.1.gz editor.tr.1.gz /usr/share/man/tr/man1/vim.1.gz
      fi
      
      # End automatically added section
      
      # Automatically added by dh_installalternatives/13.14.1ubuntu5
      
      if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ]; then
              update-alternatives --install /usr/bin/ex ex /usr/bin/vim.tiny 15 \
                  --slave /usr/share/man/man1/ex.1.gz ex.1.gz /usr/share/man/man1/vim.1.gz \
                  --slave /usr/share/man/da/man1/ex.1.gz ex.da.1.gz /usr/share/man/da/man1/vim.1.gz \
                  --slave /usr/share/man/de/man1/ex.1.gz ex.de.1.gz /usr/share/man/de/man1/vim.1.gz \
                  --slave /usr/share/man/fr/man1/ex.1.gz ex.fr.1.gz /usr/share/man/fr/man1/vim.1.gz \
                  --slave /usr/share/man/it/man1/ex.1.gz ex.it.1.gz /usr/share/man/it/man1/vim.1.gz \
                  --slave /usr/share/man/ja/man1/ex.1.gz ex.ja.1.gz /usr/share/man/ja/man1/vim.1.gz \
                  --slave /usr/share/man/pl/man1/ex.1.gz ex.pl.1.gz /usr/share/man/pl/man1/vim.1.gz \
                  --slave /usr/share/man/ru/man1/ex.1.gz ex.ru.1.gz /usr/share/man/ru/man1/vim.1.gz \
                  --slave /usr/share/man/tr/man1/ex.1.gz ex.tr.1.gz /usr/share/man/tr/man1/vim.1.gz
      fi
      
      # End automatically added section
      
      # Automatically added by dh_installalternatives/13.14.1ubuntu5
      
      if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ]; then
              update-alternatives --install /usr/bin/rview rview /usr/bin/vim.tiny 15
      fi
      
      # End automatically added section
      
      # Automatically added by dh_installalternatives/13.14.1ubuntu5
      
      if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ]; then
              update-alternatives --install /usr/bin/vi vi /usr/bin/vim.tiny 15 \
                  --slave /usr/share/man/man1/vi.1.gz vi.1.gz /usr/share/man/man1/vim.1.gz \
                  --slave /usr/share/man/da/man1/vi.1.gz vi.da.1.gz /usr/share/man/da/man1/vim.1.gz \
                  --slave /usr/share/man/de/man1/vi.1.gz vi.de.1.gz /usr/share/man/de/man1/vim.1.gz \
                  --slave /usr/share/man/fr/man1/vi.1.gz vi.fr.1.gz /usr/share/man/fr/man1/vim.1.gz \
                  --slave /usr/share/man/it/man1/vi.1.gz vi.it.1.gz /usr/share/man/it/man1/vim.1.gz \
                  --slave /usr/share/man/ja/man1/vi.1.gz vi.ja.1.gz /usr/share/man/ja/man1/vim.1.gz \
                  --slave /usr/share/man/pl/man1/vi.1.gz vi.pl.1.gz /usr/share/man/pl/man1/vim.1.gz \
                  --slave /usr/share/man/ru/man1/vi.1.gz vi.ru.1.gz /usr/share/man/ru/man1/vim.1.gz \
                  --slave /usr/share/man/tr/man1/vi.1.gz vi.tr.1.gz /usr/share/man/tr/man1/vim.1.gz
      fi
      
      # End automatically added section
      
      # Automatically added by dh_installalternatives/13.14.1ubuntu5
      
      if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ]; then
              update-alternatives --install /usr/bin/view view /usr/bin/vim.tiny 15 \
                  --slave /usr/share/man/man1/view.1.gz view.1.gz /usr/share/man/man1/vim.1.gz \
                  --slave /usr/share/man/da/man1/view.1.gz view.da.1.gz /usr/share/man/da/man1/vim.1.gz \
                  --slave /usr/share/man/de/man1/view.1.gz view.de.1.gz /usr/share/man/de/man1/vim.1.gz \
                  --slave /usr/share/man/fr/man1/view.1.gz view.fr.1.gz /usr/share/man/fr/man1/vim.1.gz \
                  --slave /usr/share/man/it/man1/view.1.gz view.it.1.gz /usr/share/man/it/man1/vim.1.gz \
                  --slave /usr/share/man/ja/man1/view.1.gz view.ja.1.gz /usr/share/man/ja/man1/vim.1.gz \
                  --slave /usr/share/man/pl/man1/view.1.gz view.pl.1.gz /usr/share/man/pl/man1/vim.1.gz \
                  --slave /usr/share/man/ru/man1/view.1.gz view.ru.1.gz /usr/share/man/ru/man1/vim.1.gz \
                  --slave /usr/share/man/tr/man1/view.1.gz view.tr.1.gz /usr/share/man/tr/man1/vim.1.gz
      fi
      
      # End automatically added section
      

      The vim-tiny maintainer scripts register /usr/bin/vim.tiny as an alternative implementation for various standard editor commands like vi, view, editor, etc. This is done by the update-alternatives command, and if necessary, we can reproduce this in our slice definitions.

  5. Repeat the above for all dependencies

    Slices must also exist for every other package that vim-tiny depends on. So if these dependencies aren’t yet sliced upstream in chisel-releases, you must do the same inspection for them, and create their slices too.

Design the slices

Your second task is to design the slices. There are a few considerations to be made, such as figuring out what slices we need and the contents of those slices.

There are two schools of thought when designing slices:

Group by type

Group by function

This means putting all the binaries together in one slice, all the libraries together in another slice, and so on. A good example is the dpkg slice definitions file.

Tip

In this case, the best practice is to create:

  • a bins slice which contains all the binaries,

  • a libs slice which contains all the libraries,

  • a config slice which contains all configuration files,

  • a scripts slice which contains ASCII executable scripts, e.g. Python, Perl scripts,

  • and others analogously (e.g. data, modules, services, etc).

You may split the above slices into more granular ones, but you should reserve the above as a catch-all for their respective types.

This means grouping the contents into slices that deliver a specific functionality. For example, the python3 slice definitions file has a core slice providing a very minimal python3 runtime, but also a standard slice with the additional libraries on top of core.

Tip

In this case, the most common is to create:

  • a core slice which contains the very minimal, core set of files supporting a minimal yet functional operation of the application,

  • a standard slice which contains a standard set of files supporting the full operation of the application,

  • and other slices which are scoped and named after the functionality they provide (e.g. see the libpython3.12-stdlib slices).

  1. Choose the design approach that aligns best with your package

    Given the above package inspection, the vim-tiny package can be sliced by type of content:

    • a bins slice for the /usr/bin/vim.tiny binary,

    • a config slice for the configuration files, and

    • a copyright slice for the copyright file.

    Important

    Every slice must install the package’s copyright file(s).

    It is therefore recommended to create a copyright slice for every package, that other slices can depend on.

  2. Prepare to write the slice definitions

    Note

    There is one Slice Definitions File per package!

    Slice definitions live in the slices/ directory of the chisel-releases repository . Fork and clone this repo, creating a new branch for the packages you are slicing.

  3. Create the YAML Slice Definitions File

    Create a new file in the slices/ directory, named after the package you are slicing. For example, vim-tiny.yaml.

  4. Specify package name

    The first thing to do is to write the package name in the package field. For example, open slices/vim-tiny.yaml and write:

    package: vim-tiny
    
  5. Write the copyright slice

    Write the copyright slice first and pin it as an essential for every other package slice.

    essential:
      - vim-tiny_copyright
    
    slices:
      copyright:
        contents:
          # This path is taken from the package contents inspected above.
          /usr/share/doc/vim-tiny/copyright:
    

    Although we are writing the copyright slice first, we typically list the slice at the bottom of the slice definition file.

  6. Write the config slice

    Now write the config slice, based on the list from the conffiles.

    slices:
      config:
        contents:
          /etc/vim/vimrc.tiny:
    
    1. Are there any other files of the same type?

      The conffiles may not list everything that can be considered as a configuration file. These can sometimes be different from regular files, live outside /etc/, be created by a maintainer script, etc. So, based on the package files, you should also identify any other config files.

  7. Write the bins slice

    /usr/bin/vim.tiny is this slice’s only content. We know it will need the internal slices vim-tiny_config. But given the above package dependency inspection, we should confirm whether this binary also needs all of those package dependencies, or just a subset.

    Let’s closely look at the /usr/bin/vim.tiny file. Let’s use the file command to determine the type.

    ~$ file /usr/bin/vim.tiny
    /usr/bin/vim.tiny: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=244c06f7943459e771bbf3279ef507ad64f477b5, for GNU/Linux 3.2.0, stripped

    Since this is a dynamically linked ELF binary, let’s use a tool (like ldd, strings, objdump, readelf, etc.) to analyze it and figure out what libraries it depends on.

    ~$ ldd /usr/bin/vim.tiny
          linux-vdso.so.1 (0x00007ffcdfecd000)      libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x0000744edc6ac000)      libtinfo.so.6 => /lib/x86_64-linux-gnu/libtinfo.so.6 (0x0000744edc678000)      libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x0000744edc64b000)      libacl.so.1 => /lib/x86_64-linux-gnu/libacl.so.1 (0x0000744edc641000)      libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x0000744edc42f000)      /lib64/ld-linux-x86-64.so.2 (0x0000744edc948000)      libpcre2-8.so.0 => /lib/x86_64-linux-gnu/libpcre2-8.so.0 (0x0000744edc393000)

    Note

    Note that some times, libraries may be used on a “per need basis” (e.g. only when a certain feature is enabled) and thus may not show up when doing a basic inspection of your binary.

    Now, what packages own these objects? Using dpkg -S, we can find out:

    • libc6

    • libtinfo6

    • libselinux1

    • libacl1

    • libpcre2-8-0

    Note that libpcre2-8-0 is not listed as a dependency of vim-tiny, but if we recursively check vim-tiny’s dependencies (via apt-rdepends vim-tiny), we can see that it is a dependency of libselinux1, which is an original dependency of vim-tiny.

    So it matches with what we expected in the initial dependency analysis.

    By running chisel info --release ubuntu-24.04 libc6 libtinfo6 libselinux1 libacl1 vim-common we can confirm that all the vim-tiny’s package dependencies are already sliced. So the final bins slice will look like this:

    slices:
      bins:
        essential:
          - libacl1_libs
          - libc6_libs
          - libselinux1_libs
          - libtinfo6_libs
          - vim-common_addons
          - vim-common_config
          - vim-tiny_config
        contents:
          /usr/bin/vim.tiny:
    

    Tip

    Sometimes, a package (and thus its slices) may have “essential” dependencies that are not explicitly listed in the package’s control file. E.g. OpenSSL’s c_rehash requires Perl to run, but the OpenSSL package does not mention it. The same happens frequently for Bash scripts that may assume certain packages (like coreutils) are installed.

  8. Format your slice definitions files

    Every slice definition file will be checked with linters.

    1. Required: sort all slices’ contents

      The slice contents entries (i.e. the paths) must be sorted in lexicographical order.

    2. Recommended: consistent YAML placement

      Keep the top-level essential at the top, and the copyright slice at the bottom.

  9. Review your slice definitions

    Assemble your slice definitions file, and review it. Make sure you have included all the necessary slices, contents, dependencies and mutation scripts, and that you have followed the best practices:

    • keep the slice names meaningful and consistent with existing slices

    • ensure slices are functional by themselves, or as a dependency of other slices

    • be cautious with broad globs. A good glob simplifies the writing of a slice while keeping the resulting paths specific to the package. See Example: good vs bad slice definitions.

    The complete slices/vim-tiny.yaml file should look something like this:

    package: vim-tiny
    
    essential:
      - vim-tiny_copyright
    
    slices:
      bins:
        essential:
          - libacl1_libs
          - libc6_libs
          - libselinux1_libs
          - libtinfo6_libs
          - vim-common_addons
          - vim-common_config
          - vim-tiny_config
        contents:
          /usr/bin/vim.tiny:
    
      config:
        contents:
          /etc/vim/vimrc.tiny:
    
      copyright:
        contents:
          /usr/share/doc/vim-tiny/copyright:
    

    Important

    If any of your slices’ paths are architecture-specific, you must add the arch field. For example:

    /usr/lib/*-linux-*/libmvec.so.*: {arch: [amd64, arm64]}

  10. Repeat for nonexistent package slices

    If any of the dependencies are not sliced yet, repeat the above design process for them too.

Test the slices

A slice definition is only complete when it has been tested.

As a manual test, you can just install your slices into an empty folder, and test your application with chroot.

But for upstream contributions, you must also add integration tests in the form of Spread tasks.

Important

All slices that deliver “functionality” must be tested!

While it might be redundant to test that a specific path has been properly installed by Chisel, it is paramount to test slices that should offer a specific function. Examples:

  1. Install the vim-tiny_bins locally

    Create a new rootfs directory, and pointing Chisel to your “chisel-releases” clone, cut your packages locally.

    mkdir rootfs/
    # Cut the vim-tiny package, to get the vim.tiny binary only
    chisel cut --release ./ --root rootfs/ vim-tiny_bins
    

    Test the bins binary:

    ~$ sudo chroot rootfs/ vim.tiny --version
    VIM - Vi IMproved 9.1 (2024 Jan 02, compiled Apr 01 2025 15:29:41)Included patches: 1-16, 647-648, 678, 697, 689, 17-496, 707Modified by <team+vim@tracker.debian.org>Compiled by <team+vim@tracker.debian.org>Tiny version without GUI.  Features included (+) or not (-):...
  2. Create the Spread test

    In your clone of the chisel-releases repository , create the new folder tests/spread/integration/vim-tiny.

    1. Create the task.yaml file

      Create a file named tests/spread/integration/vim-tiny/task.yaml and write your test in the format of a Spread task.

      Example: Spread test for vim-tiny
      summary: Integration tests for vim-tiny
      
      execute: |
        rootfs="$(install-slices vim-tiny_bins)"
        chroot "${rootfs}/" vim.tiny --version
        echo "hello world" > "$rootfs/test"
        chroot "$rootfs" vim.tiny -c ":s/hello/bye/" -c ":wq" test
        test "$(cat "$rootfs/test")" = "bye world"
      
    2. Run your Spread test

      Run the test with spread:

      ~$ spread lxd:tests/spread/integration/vim-tiny
      ...2025-04-14 18:29:40 Preparing lxd:ubuntu-noble:tests/spread/integration/vim-tiny (lxd:ubuntu-noble)...2025-04-14 18:29:40 Executing lxd:ubuntu-noble:tests/spread/integration/vim-tiny (lxd:ubuntu-noble) (1/1)...2025-04-14 18:29:50 Discarding lxd:ubuntu-noble...2025-04-14 18:29:52 Successful tasks: 12025-04-14 18:29:52 Aborted tasks: 0
  3. Contribute!

    New slice definitions are welcome! Please contribute your new slices to the chisel-releases repository . See the contributing guide.

Example: good vs bad slice definitions

package: libpython3.12-stdlib

essential:
  - libpython3.12-stdlib_copyright

slices:
  # File Formats
  # https://docs.python.org/3.12/library/fileformats.html
  file-formats:
    essential:
      - libpython3.12-stdlib_core
      - libpython3.12-stdlib_frameworks
      - libpython3.12-stdlib_markup-tools
    contents:
      /usr/lib/python3.12/netrc.py:
      /usr/lib/python3.12/plistlib.py:
      /usr/lib/python3.12/tomllib/**:
      /usr/lib/python3.12/xdrlib.py:

  ...
package: libpython3.12-stdlib

# Missing a global "essential" dependency on the "copyright" slice, thus
# forcing it to be an "essential" in every slice below, making the file
# less readable and more prone to missing that dependency.

slices:
  # Controversial grouping by type. Makes more sense to group Python by function.
  modules:
    # Possibly missing the dependencies on ".so" files and other contents.

    # No sorting of contents
    contents:
      # No need to define this symlink. It is already defined in the deb
      /usr/share/doc/libpython3.12-stdlib: {symlink: /usr/share/doc/libpython3.12-minimal}

      # Chose to group by type, but still mixing types within the same slice
      /usr/lib/python3.12/netrc.py:
      /usr/lib/python3.12/pydoc_data/_pydoc.css:

      # Bad glob, possibly conflicting with other python packages
      /usr/lib/python3.*/tomllib/**:

  ...