O que é o sbuild

Para quê serve o sbuild:

sbuild é fundamentalmente uma ferramenta para fazer e testar pacotes binários (.deb) a partir de um pacote-fonte debian (.dsc). Seus recursos de isolamento ajudam você a testar seus pacotes antes de fazer o upload. Para manter e carregar um pacote, você também usará um construtor de pacotes como o git-buildpackage).

Uma alternativa para sbuild é o pbuilder combinado com o cowbuilder.

Esta parte principal desta página objetiva ser um pequeno guia para o sbuild. Ela documenta como configurar o sbuild e como construir pacotes com ele. Seções posteriores documentam melhorias opcionais para as configurações descritas na primeira seção.

Configuração

Há muitas maneiras de usar o sbuild. Esta seção documenta uma configuração moderna, usando mmdebstrap e `unshare, que permite que você construa e teste pacotes sem ser root. Nesta configuração, pacotes são construídos e testados em um chroot limpo e efêmero, extraído de um tarball. Recomenda-se usar a versão sbuild de bookworm-backports.

1. Instale os pacotes necessários:

sudo apt install sbuild mmdebstrap uidmap

2. Crie um diretório para o tarball do chroot

mkdir -p ~/.cache/sbuild

3. Crie/Atualize o tarball

mmdebstrap --include=ca-certificates --skip=output/dev --variant=buildd unstable ~/.cache/sbuild/unstable-amd64.tar.zst https://deb.debian.org/debian

Modifique deb.debian.org para qualquer espelho que precisar. ca-certificates é necessário para suportar o download de pacotes por https: se você usar http, pode omitir --include=ca-certificates.

Você pode usar quaisquer argumentos mmdebstrap, tais como --include=gnupg,debhelper para personalizar o chroot. O chroot é extraído em um diretório temporário sempre que utilizado, garantindo que construções e testes aconteçam em um ambiente limpo.

Se você está usando apt-cacher-ng, especifique http:// em vez de https://, e habilite o proxy apt-cacher-ng usando --aptopt='Acquire::http { Proxy "http://127.0.0.1:3142"; }'. Você pode usar qualquer extensão de compressão tarball que preferir.

mmdebstrap --skip=output/dev --variant=buildd unstable ~/.cache/sbuild/unstable-amd64.tar.zst http://deb.debian.org/debian --aptopt='Acquire::http { Proxy "http://127.0.0.1:3142"; }'

Você pode escolher o algoritmo de compressão para o tarball especificando a extensão (.tar.xz, .tar.gz ou somente .tar, etc). A partir de maio de 2024, ZST parece fornecer a melhor proporção de tamanho/tempo. É certamente o mais rápido em um Dell Precision 3800M, 16GB de RAM, em uma unidade SSD (um computador do início de 2015):

Formato

Tamanho do tarball

Tempo

.xz

~100MB

179,60s user 7,09s system 75% cpu 4:07,49 total

.gz

~150MB

38,51s user 6,13s system 83% cpu 53,423 total

.zst

~139MB

22,68s user 6,28s system 74% cpu 38,868 total

4. Configure ~/.config/sbuild/config.pl

O comando abaixo criará o arquivo ~/.config/sbuild/config.pl com opções adequadas. Ele substituirá qualquer arquivo já existente, então certifique-se de que já não tem um ~/.config/sbuild/config.pl, ou cria uma cópia de segurança.

Use ~/.sbuildrc com sbuild anteriores

Antes do sbuild versão 0.87.1, você deve usar ~/.sbuildrc em vez de ~/.config/sbuild/config.pl. Veja #1087378 e 0.87.1 changelog.

   1 cat << "EOF" > ~/.config/sbuild/config.pl
   2 # Define o modo chroot (chroot mode) para unshare.
   3 $chroot_mode = 'unshare';
   4 
   5 $external_commands = { "build-failed-commands" => [ [ '%SBUILD_SHELL' ] ] };
   6 
   7 # Remova os comentários abaixo para definir a distribuição; é o mesmo que passar `-d unstable` para o sbuild.
   8 # Definir a distribuição é necessário atualmente para piuparts quando o changelog tem como alvo UNRELEASED. Veja #1088928.
   9 #$distribution = 'experimental';
  10 #$distribution = 'unstable';
  11 #$distribution = 'bookworm-backports';
  12 
  13 # Define um repositório extra; é o mesmo que passar `--extra-repository` para o sbuild.
  14 #$extra_repositories = ['deb http://deb.debian.org/debian bookworm-backports main'];
  15 #$extra_repositories = ['deb http://deb.debian.org/debian experimental main'];
  16 
  17 # Define o resolvedor de dependências de construção; é o mesmo que passar `--build_deps_resolver` para o sbuild.
  18 # Quando construindo com repositórios extras, geralmente o 'aptitude' é melhor que o 'apt' (por padrão).
  19 #$build_dep_resolver = 'aptitude';
  20 
  21 # Arquitetura de construção: todos os pacotes; é o mesmo que passar `-A` para o sbuild.
  22 $build_arch_all = 1;
  23 
  24 # Também construa o pacote-fonte além de outros artefatos de construção requeridos; é o mesmo que passar `-s` para o sbuild.
  25 $build_source = 1;
  26 
  27 # Produz um arquivo .changes adequado para upload exclusivo da fonte (source-only upload); é o mesmo que passar `--source-only-changes` para o sbuild.
  28 $source_only_changes = 1;
  29 
  30 ## Executa lintian após cada construção (no mesmo chroot da construção); use --no-run-lintian para ignorar.
  31 $run_lintian = 1;
  32 # Exibe etiquetas de informações.
  33 $lintian_opts = ['--display-info', '--verbose', '--fail-on', 'error,warning', '--info'];
  34 # Exibe etiquetas de informações e pedantes (pedantic), como também substituições (overrides).
  35 #$lintian_opts = ['--display-info', '--verbose', '--fail-on', 'error,warning', '--info', '--pedantic', '--show-overrides'];
  36 
  37 ## Executa autopkgtest após cada construção (em um chroot novo e limpo); use --no-run-autopkgtest para ignorar.
  38 $run_autopkgtest = 1;
  39 # Define opções do autopkgtest. O exemplo comentado abaixo é o padrão deste trixie.
  40 #$autopkgtest_opts = ['--apt-upgrade', '--', 'unshare', '--release', '%r', '--arch', '%a' ];
  41 
  42 ## Executa piuparts após cada construção (em um chroot novo e temporário); use --no-run-piuparts para ignorar.
  43 # isto não funciona no bookworm
  44 $run_piuparts = 1;
  45 # Constrói um chroot temporário.
  46 $piuparts_opts = ['--no-eatmydata', '--distribution=%r', '--fake-essential-packages=systemd-sysv'];
  47 # Constrói um chroot temporário que usa apt-cacher-ng como um proxy para economizar largura de banda e tempo, e não desabilita eatmydata para acelerar o processamento.
  48 #$piuparts_opts = ['--no-eatmydata', '--distribution=%r', '--warn-on-leftovers-after-purge', '--bootstrapcmd=mmdebstrap --skip=check/empty --variant=minbase --aptopt="Acquire::http { Proxy \"http://127.0.0.1:3142\"; }"'];
  49 
  50 EOF

Certifique-se de configurar aliases se construindo para UNRELEASED ou experimental, a menos que deseje definir manualmente a distribuição.

Ao usar este exemplo ~/.config/sbuild/config.pl, Piuparts gera um chroot temporário e mínimo a cada execução, porque fazendo isso fornece resultados mais completos que usar um chroot construído com --variant=buildd. Há muitas opções para o sbuild: consulte as páginas man sbuild(1) e sbuild.conf(5) para detalhes.

"Atualizando" chroot manualmente (com unshare)

Para manter o chroot atualizado, é recomendável simplesmente excluí-lo e recriá-lo, executando novamente o comando mmdebstrap (veja acima). Isso é rápido e garante que o ambiente de construção permaneça limpo.

sbuild-update não funciona com unshare.

Construindo pacotes

Pacotes independentes

Com um arquivo ~/.config/sbuild/config.pl configurado corretamente como feito acima, você pode construir um pacote executando os comandos a seguir a partir do diretório-fonte do pacote. Isso construirá um pacote-fonte (.dsc) e, em seguida, construirá todos os pacotes binários dele.

sbuild

Se você tem um .dsc (gerado por dpkg-buildpackage, git-buildpackage, etc), pode usá-lo:

sbuild package_*.dsc

Se você tem linhas deb-src configuradas para o apt, você pode construir qualquer pacote sem baixar o código-fonte primeiro:

sbuild -d unstable hello

Integração com git-buildpackage (gbp-buildpackage)

Para construir um pacote de um repositório git gerenciado com git-buildpackage, execute

gbp buildpackage --git-builder=sbuild

ou coloque o seguinte em ~/.gbp.conf:

[buildpackage]
builder = sbuild

Isso cria um pacote-fonte a partir do repositório git (na máquina hospedeira) e em seguida executa sbuild para construir e testar os pacotes binários (em um chroot). Há mais informações sobre empacotamento com git em EmpacotandoComGit.

Acelerando o processo de construção

Use apt-cacher-ng

sudo apt install apt-cacher-ng

Adicione isto às opções do mmdebstrap ao criar o tarball do chroot:

--aptopt='Acquire::http { Proxy "http://127.0.0.1:3142"; }'

Erros de incompatibilidade de soma de hash

Clientes apt-cacher-ng podem (regularmente) encontrou erros sobre incompatibilidades de soma hash (hash sum mismatches) que resultam em assinaturas de chave não válidas. Uma maneira de resolver isso é limpar os arquivos de cache expirados, conforme documentado na página wiki apt-cacher-ng.

Construindo em tmpfs [pré-trixie]

Desde a distribuição trixie, isto não é mais preciso porque /tmp é agora um tmpfs por padrão.

echo "\$unshare_tmpdir_template = '/dev/shm/tmp.sbuild.XXXXXXXXXX';" >> ~/.config/sbuild/config.pl

Isto requer que /dev/shm seja maior o suficiente para desempacotar o chroot e executar o processo de construção: para aumentá-lo temporariamente, faça (como root):

mount -o remount,size=2G /dev/shm

Usando ccache com sbuild

ccache é um wrapper de compilador que armazenará em cache resultados de compilação (arquivos de objeto) de gcc e g++. Se você compilar repetidamente o mesmo código-fonte (ou partes dele), ccache encurtará os tempos de recompilação, evitando a recompilação de arquivos que não mudaram entre as execuções.

Esta é geralmente uma economia significativa durante o desenvolvimento de pacotes, porque apenas alguns arquivos são alterados entre as execuções.

Também é eficaz com pacotes que são frequentemente atualizados, porque muitas vezes apenas alguns arquivos realmente mudam durante as atualizações de um software.

Adicione isso às opções do mmdebstrap ao criar o tarball do chroot:

--include=ccache --customize-hook='chroot "$1" update-ccache-symlinks'

(update-ccache-symlinks é necessário devido ao 632779)

Adicione isto a sua configuração do sbuild:

   1 cat << "EOF" >> ~/.config/sbuild/config.pl
   2 $build_environment = { "CCACHE_DIR" => "/build/ccache" };
   3 $path = "/usr/lib/ccache:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games";
   4 $build_path = "/build/package/";
   5 $dsc_dir = "package";
   6 $unshare_bind_mounts = [ { directory => "$HOME/.cache/ccache", mountpoint => "/build/ccache" } ];
   7 $autopkgtest_opts = [ '--apt-upgrade', '--env=CCACHE_DIR=/build/ccache', '--env=PATH=/usr/lib/ccache:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games', '--', 'unshare', '--release', '%r', '--arch', '%a', '--prefix=/dev/shm/tmp.autopkgtest.', '--bind', "$HOME/.cache/ccache", '/build/ccache' ];
   8 EOF

O usuário sbuild no chroot precisa ter acesso a $HOME/.cache/ccache, que está no host. Você pode fazer chmod a+X "$HOME" "$HOME/.cache" e chmod -R a+rwX "$HOME/.cache/ccache" no host, ou usar outro local de cache (note que os arquivos em /tmp correm o risco de serem apagados na reinicialização ou pela limpeza periódica do systemd).

use eatmydata

Não está claro o quanto isso ajuda se o chroot é extraído para um tmpfs, mas executar eatmydata pode fornecer um ganho de velocidade ao prevenir que os dados sejam gravados no disco com frequência -- isto tem, obviamente, riscos de corrupção de dados. Somente afeta a construção do pacote, não o resto do seu sistema. Para usá-lo:

1. Inclua eatmydata no chroot: adicione --include=eatmydata às opções do mmdebootstrap quando criar o tarball do chroot.

2. Use eatmydata na construção: adicione as seguintes linhas na configuração do sbuild; este chroot é amd64: você pode adaptar o caminho para outras arquiteturas.

   1 # use no chroot
   2 $chroot-setup-commands => [ "export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libeatmydata.so" ];
   3 
   4 # use na construção
   5 $build_environment ={
   6   "LD_PRELOAD" => "/usr/lib/x86_64-linux-gnu/libeatmydata.so"
   7 };
   8 
   9 # adicione LD_PRELOAD para variáveis retidas
  10 $environment_filter=[Dpkg::BuildInfo::get_build_env_allowed(), '^LD_PRELOAD$'];

3. (Você pode adicionar --no-eatmydata em $piuparts_opts já que o piuparts também habilita eatmydata por padrão).

4. Você pode chamar o sbuild normalmente: também pode instalar o eatmydata no host e chamar o sbuild dessa forma

LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libeatmydata.so sbuild

o que pode melhorar a velocidade de desempacotamento do tarball do chroot.

Use schroot em vez de unshare

sbuild pode usar chroots criados por schroot, estes usam overlayfs que pode ser mais rápido do que o unshare. No entanto, isso requer maior uso de root do que unshare: com schroot você pode executar a compilação, lintian e autopkgtests como um(a) usuário(a) (se root tiver acesso concedido), mas piuparts e a criação de um novo chroot requer root (ou permissão para elevar privilégios com sudo ou similar).

Dicas avançadas

Pacotes de compilação cruzada

sbuild também suporta compilação cruzada de um pacote para construí-lo para uma arquitetura de processador diferente. Por exemplo, você pode criar pacotes arm64 ou ppc64el em uma máquina amd64.

Para construir um pacote para arm64 em um chroot amd64 (conforme criado acima), você pode usar:

sbuild --host=arm64

Nota: não há necessidade de compilar pacotes marcados como arch:all, já que são independentes da arquitetura.

Comandos externos

sbuild suporta a execução de comandos externos em vários estágios do processo de construção. Por exemplo, você pode executar um script dentro do chroot depois de ter sido configurado.

Para executar o /usr/local/bin/meuscript, adicione-o ao tarball do chroot e inclua o código a seguir em sua configuração do sbuild:

   1 $external_commands = {
   2                         'chroot-setup-commands' => ['/usr/local/bin/meuscript']
   3                       };

sbuild suporta palavras-chave escapadas com o sinal de porcentagem. Por exemplo, %SBUILD_CHANGES é alterado para o caminho do arquivo '.changes' para um pacote construído com sucesso.

Aqui está um exemplo da adição de um comando de pós-construção para executar /usr/local/bin/postbuildscript com %SBUILD_CHANGES como um argumento.

   1 $external_commands = {
   2                         'post-build-commands' => ['/usr/local/bin/postbuildscript', '%SBUILD_CHANGES'],
   3                         'chroot-setup-commands' => ['/usr/local/bin/myscript'],
   4                         'chroot-cleanup-commands' => [],
   5                         'pre-build-commands' => []
   6                      };

Aqui está como cair em um shell dentro de um chroot efêmero se a construção falhar

   1 $external_commands = {
   2                         "chroot-update-failed-commands" => [ [ '%SBUILD_SHELL' ] ],
   3                         "build-deps-failed-commands" => [ [ '%SBUILD_SHELL' ] ],
   4                         "build-failed-commands" => [ [ '%SBUILD_SHELL' ] ],
   5 };

Consulte a seção 'EXTERNAL COMMANDS' da página man do sbuild para obter mais informações sobre comandos externos.

Habilitando a experimental

Para permitir que a construção use pacotes a partir do repositório experimental do Debian, você pode usar o argumento --extra-repository. Você também pode querer usar o resolvedor aspcud:

sbuild --extra-repository='deb http://deb.debian.org/debian experimental main' --build-dep-resolver=aspcud mypkg.dsc

Para imitar exatamente o resolvedor usado nos buildds oficiais, você precisa adicionar as preferências de aspcud que minimizem o número de pacotes da experimental. Veja o repositório DSA puppet em https://salsa.debian.org/dsa-team/mirror/dsa-puppet/-/blob/production/modules/buildd/templates/sbuild.conf.erb

sbuild --extra-repository='deb http://deb.debian.org/debian experimental main' --build-dep-resolver=aspcud --aspcud-criteria '-count(solution,APT-Release:=/a=experimental/),-removed,-changed,-new' mypkg.dsc

Você também pode usar o resolvedor do aptitude (usado pelo *-backports), que para a maioria dos pacotes deve ter o mesmo efeito.

sbuild --extra-repository='deb http://deb.debian.org/debian experimental main' --build-dep-resolver=aptitude mypkg.dsc

Outra possibilidade é ter um arquivo de configuração ~/.config/sbuild/config.experimental.pl dedicado e executar o sbuild via

SBUILD_CONFIG=~/.config/sbuild/config.experimental.pl sbuild mypkg.dsc

com ~/.config/sbuild/config.experimental.pl contendo, por exemplo:

$extra_repositories = [ 'deb http://deb.debian.org/debian experimental main' ];
$build_dep_resolver = 'aptitude';

Se precisar testar uma compilação contra um Build-Depends versionado da experimental, você pode usar --add-depends:

sbuild --extra-repository='deb http://deb.debian.org/debian experimental main' --build-dep-resolver=aspcud --add-depends='foo-dev (>= 1.2.3-4)' mypkg.dsc

Construção para experimental

Se desejar construir para a unstable, mas fazer upload para a experimental, use por exemplo:

sbuild -d experimental -c unstable-amd64-sbuild mypkg.dsc

Alternativamente, se você sabe que sempre deseja construir seus pacotes para experimental em um chroot da instável, basta adicionar experimental como um alias para seu chroot da instável:

   1 cd ~/.cache/sbuild
   2 ln -s {unstable,experimental}-*.tar*

Habilitando incoming.debian.org

Se desejar construir antes do próximo dinstall, você pode adicionar a fila incoming como um repositório extra:

sbuild --extra-repository='deb http://incoming.debian.org/debian-buildd/ buildd-unstable main' mypkg.dsc

Usando aliases

sbuild escolhe o chroot com base na distribuição em debian/changelog. Você pode alterar isso com a opção -d ou pode usar links simbólicos para configurar aliases de modo que o pacote-fonte com UNRELEASED ou experimental em debian/changelog sejam construídos em um chroot unstable (ou para que -d sid possa ser usado para construir na unstable, etc):

   1 cd ~/.cache/sbuild
   2 for file in unstable-*.tar*; do
   3     ln -s "$file" "${file/unstable/UNRELEASED}"
   4 done
   5 for file in unstable-*.tar*; do
   6     ln -s "$file" "${file/unstable/experimental}"
   7 done

Adicionando pacotes extras packages

Muitas vezes é necessário adicionar pacotes binários extras como dependências de construção para o pacote que você está construindo. Por exemplo, você pode querer fornecer uma dependência de compilação que está esperando na fila NEW e, portanto, não está disponível nos espelhos; ou você está precisamente tentando avaliar se o seu novo pacote quebra qualquer coisa antes de fazer o upload. Para fazer isso, use a opção --extra-package=/path/to/foo.deb para sbuild; e se houver vários desses pacotes, --extra-package=/path/to/ também percorrerá este diretório. O caminho deve ser um caminho absoluto no host, e ~ não é automaticamente expandido para $HOME!.

Você pode achar que a saída do resolvedor não é bom o suficiente para determinar qual pacote extra você precisa disponibilizar. Neste caso, pode ser útil passar --build-dep-resolver=aptitude, a qual tende a fornecer uma saída mais proveitosa (embora você deva removê-la uma vez que descobriu o problema).

Servidores de construção remota

Uma vantagem do cowbuilder sobre o sbuild é que ele suporta o descarregamento de construções para um servidor remoto com cowpoke. Uma maneira de fazer isso com o sbuild é criar um pacote-fonte localmente e transferi-lo para a máquina remota para construção. Este último pode ser feito com dcmd. Por exemplo:

   1 dpkg-buildpackage -S
   2 dcmd scp ../foo-1.0.dsc example.net:build-area
   3 ssh example.net sbuild build-area/foo-1.0.dsc

Validando a limpeza de pacotes

Os pacotes não conseguirão compilar duas vezes seguidas se o alvo `clean do debian/rules não restaurar o diretório-fonte para seu estado inicial. Adicionar o código seguinte à sua configuração do sbuild ajudará a detectar as modificações:

$external_commands = {
    "starting-build-commands" => [
        'bash -c \'find %SBUILD_PKGBUILD_DIR -print0 |
                  sort -z |
                  while read -d $\'\\\'\'\0\'\\\'\' file; do
                      echo -n "$(stat -c "%n %F %%s" "${file}") "
                      if [ -f "${file}" ]; then
                          sha256sum "${file}" |
                              cut -d " " -f 1
                      else
                              echo
                      fi
                  done > /tmp/file-list.pre-build\''
    ],
    "chroot-cleanup-commands" => [
        'cd %SBUILD_PKGBUILD_DIR && ./debian/rules clean',
        'bash -c \'find %SBUILD_PKGBUILD_DIR -print0 |
                  sort -z |
                  while read -d $\'\\\'\'\0\'\\\'\' file; do
                      echo -n "$(stat -c "%n %F %%s" "${file}") "
                      if [ -f "${file}" ]; then
                          sha256sum "${file}" |
                              cut -d " " -f 1
                      else
                              echo
                      fi
                  done > /tmp/file-list.post-build\'',
        'diff /tmp/file-list.pre-build /tmp/file-list.post-build'
    ]
};

Usando podman para autopkgtests

   1 sudo apt install podman passt
   2 mmdebstrap --include=libpam-systemd,systemd-resolved --customize-hook='sed "s/^deb /deb-src /" "$1/etc/apt/sources.list" > "$1/etc/apt/sources.list.d/src.list"' unstable | podman import - debian-unstable
   3 cat << "EOF" >> ~/.config/sbuild/config.pl
   4 $autopkgtest_root_args = 'PATH=/usr/sbin:/usr/bin:/sbin:/bin';
   5 $autopkgtest_opts = ['--shell-fail', '--apt-upgrade', '--', 'podman', '--init', 'debian-%r'];
   6 EOF

Usando qemu para autopkgtests

   1 sudo apt install qemu-system
   2 mmdebstrap-autopkgtest-build-qemu --boot=efi unstable $HOME/.cache/sbuild/unstable-amd64.img
   3 cat << "EOF" >> ~/.config/sbuild/config.pl
   4 $autopkgtest_opts = ['--shell-fail', '--apt-upgrade', '--', 'qemu', '--cpus', '4', '--ram-size', '8096', '--efi', "$HOME/.cache/sbuild/%r-%a.img"];
   5 EOF

Usando /var/cache/apt/archives/ como cache de pacotes

   1 sudo apt -o Dir::State::status=lock build-dep -d <pkg>
   2 sudo apt -o Dir::State::status=lock install -d lintian
   3 cd $(mktemp -d)
   4 ln -s /var/cache/apt/archives/
   5 apt-ftparchive packages . > Packages
   6 apt-ftparchive release . > Release
   7 python3 -m http.server 5678 --bind 127.0.0.1
   8 sbuild --extra-repository="deb [trusted=yes] http://127.0.0.1:5678 ./" --chroot-setup-commands "rm /etc/apt/sources.list"


CategoryPackaging CategoryPackaging