Packaging: criando .deb, .rpm e AppImage
1. Introdução ao Packaging de Aplicações em C
Empacotar uma aplicação escrita em C é o passo final para transformar código-fonte em software distribuível. Usuários finais não compilam programas — eles instalam pacotes. Sem packaging, você entrega um tarball e deixa o usuário lidar com dependências, paths e permissões. Com pacotes .deb, .rpm ou AppImage, você oferece instalação limpa, remoção segura e gerenciamento automático de bibliotecas.
Cada formato atende a um ecossistema: .deb para Debian, Ubuntu e derivados; .rpm para Fedora, RHEL, CentOS e openSUSE; AppImage para qualquer distribuição Linux, sem necessidade de instalação. Este artigo mostra como gerar os três a partir de um mesmo projeto em C.
Pré-requisitos: gcc, make, cmake (opcional), dpkg-deb, rpmbuild, appimagetool e linuxdeploy. Tenha também um projeto C mínimo com estrutura src/ e include/.
2. Estrutura Base do Projeto e Compilação
Organize seu projeto assim:
meu_app/
├── src/
│ └── main.c
├── include/
│ └── utils.h
├── Makefile
└── packaging/
├── deb/
├── rpm/
└── appimage/
Exemplo de Makefile com linkedição dinâmica:
CC = gcc
CFLAGS = -O2 -Wall -Iinclude
LDFLAGS = -lm
TARGET = meu_app
all: $(TARGET)
$(TARGET): src/main.o
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
src/main.o: src/main.c include/utils.h
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f $(TARGET) src/*.o
Compile com make e obtenha o binário meu_app. Para distribuição dinâmica, use -lm para linkedição com a math library. Se quiser estática, adicione -static, mas lembre-se: pacotes .deb e .rpm geralmente preferem linkedição dinâmica para economia de espaço e updates via sistema.
3. Criando Pacotes .deb (Debian/Ubuntu)
Crie a estrutura do pacote em packaging/deb/meu_app_1.0-1_amd64/:
DEBIAN/
├── control
├── postinst
└── prerm
usr/
└── local/
└── bin/
└── meu_app
Arquivo control:
Package: meu-app
Version: 1.0-1
Section: utils
Priority: optional
Architecture: amd64
Depends: libc6 (>= 2.31), libm6
Maintainer: Seu Nome <email@exemplo.com>
Description: Aplicação exemplo em C
Empacotada como .deb para demonstração.
postinst (script pós-instalação):
#!/bin/bash
set -e
ldconfig
echo "meu-app instalado com sucesso!"
prerm (script pré-remoção):
#!/bin/bash
set -e
echo "Removendo meu-app..."
Dê permissão de execução aos scripts:
chmod +x packaging/deb/meu_app_1.0-1_amd64/DEBIAN/postinst
chmod +x packaging/deb/meu_app_1.0-1_amd64/DEBIAN/prerm
Copie o binário:
cp meu_app packaging/deb/meu_app_1.0-1_amd64/usr/local/bin/
Gere o .deb:
dpkg-deb --build packaging/deb/meu_app_1.0-1_amd64
Valide com:
lintian meu_app_1.0-1_amd64.deb
O resultado é um pacote instalável com sudo dpkg -i meu_app_1.0-1_amd64.deb.
4. Criando Pacotes .rpm (Fedora/CentOS)
No diretório packaging/rpm/, crie o arquivo .spec:
Name: meu-app
Version: 1.0
Release: 1%{?dist}
Summary: Aplicação exemplo em C
License: MIT
URL: https://exemplo.com
Source0: %{name}-%{version}.tar.gz
BuildRequires: gcc, make
Requires: glibc >= 2.31
%description
Aplicação exemplo em C empacotada como .rpm para demonstração.
%prep
%setup -q
%build
make
%install
mkdir -p %{buildroot}%{_bindir}
install -m 755 meu_app %{buildroot}%{_bindir}/
%files
%{_bindir}/meu_app
%changelog
* Tue Jan 14 2025 Seu Nome <email@exemplo.com> - 1.0-1
- Versão inicial
Crie o tarball do código-fonte:
tar czf ~/rpmbuild/SOURCES/meu-app-1.0.tar.gz .
Construa o pacote:
rpmbuild -ba packaging/rpm/meu-app.spec
O .rpm será gerado em ~/rpmbuild/RPMS/x86_64/. Verifique com:
rpmlint ~/rpmbuild/RPMS/x86_64/meu-app-1.0-1.x86_64.rpm
Instale com sudo rpm -ivh meu-app-1.0-1.x86_64.rpm.
5. Criando AppImage (Portátil e Autossuficiente)
AppImage é um formato autossuficiente: contém binário e todas as dependências. Comece criando um AppDir em packaging/appimage/meu-app.AppDir/:
meu-app.AppDir/
├── AppRun
├── meu-app.desktop
├── meu-app.png
└── usr/
└── bin/
└── meu_app
AppRun (script de entrada):
#!/bin/bash
HERE="$(dirname "$(readlink -f "${0}")")"
export PATH="${HERE}/usr/bin:${PATH}"
export LD_LIBRARY_PATH="${HERE}/usr/lib:${LD_LIBRARY_PATH}"
exec meu_app "$@"
meu-app.desktop:
[Desktop Entry]
Name=Meu App
Exec=meu_app
Icon=meu-app
Type=Application
Categories=Utility;
Copie o binário:
mkdir -p packaging/appimage/meu-app.AppDir/usr/bin
cp meu_app packaging/appimage/meu-app.AppDir/usr/bin/
Use linuxdeploy para incluir bibliotecas automaticamente:
cd packaging/appimage
linuxdeploy-x86_64.AppImage --appdir meu-app.AppDir --output appimage
Ou, manualmente, copie as bibliotecas detectadas por ldd:
ldd meu_app | grep "=> /" | awk '{print $3}' | xargs -I {} cp {} meu-app.AppDir/usr/lib/
Gere o AppImage final com appimagetool:
appimagetool-x86_64.AppImage meu-app.AppDir
O arquivo Meu_App-x86_64.AppImage é portátil: baixe, dê permissão de execução e rode em qualquer distribuição.
6. Gerenciamento de Dependências e Compatibilidade
Aplicações em C dependem da libc e de outras bibliotecas compartilhadas. No .deb, declare Depends: libc6 (>= 2.31). No .rpm, use Requires: glibc >= 2.31. Para bibliotecas de terceiros (ex.: libcurl), adicione Depends: libcurl4 ou Requires: libcurl.
Use pkg-config no Makefile para localizar flags de compilação:
CFLAGS += $(shell pkg-config --cflags libcurl)
LDFLAGS += $(shell pkg-config --libs libcurl)
No pós-instalação, scripts postinst (.deb) ou %post (.rpm) podem executar ldconfig para atualizar o cache de bibliotecas.
Para compatibilidade de ABI, evite linkedição estática da libc. Prefira linkedição dinâmica e especifique versões mínimas no pacote.
7. Automação com Scripts e CI/CD
Crie um script package.sh que gera os três formatos:
#!/bin/bash
set -e
make clean
make
# .deb
dpkg-deb --build packaging/deb/meu_app_1.0-1_amd64
# .rpm
rpmbuild -ba packaging/rpm/meu-app.spec
# AppImage
cd packaging/appimage
linuxdeploy-x86_64.AppImage --appdir meu-app.AppDir --output appimage
cd ../..
No GitHub Actions, use uma matriz para testar em múltiplas distribuições:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: sudo apt install dpkg-dev rpm lintian rpmlint
- run: make
- run: dpkg-deb --build packaging/deb/meu_app_1.0-1_amd64
- uses: actions/upload-artifact@v4
with:
name: meu-app-deb
path: packaging/deb/*.deb
Para AppImage, use appimagetool disponível via GitHub Releases. Publique os artefatos em GitHub Releases ou em PPAs (Launchpad) e COPR (Fedora).
8. Boas Práticas e Considerações Finais
Teste a instalação e remoção em containers Docker de diferentes distribuições:
docker run --rm -v $(pwd):/pkg ubuntu:22.04 bash -c "dpkg -i /pkg/*.deb && meu_app"
Assine pacotes .deb com GPG:
dpkg-sig --sign builder meu_app_1.0-1_amd64.deb
Para .rpm, use rpm --addsign com chave GPG.
Mantenha um changelog no formato padrão de cada sistema e documente o processo de packaging no README do projeto. Isso facilita contribuições e manutenção futura.
Empacotar uma aplicação C corretamente é sinal de profissionalismo. Com .deb, .rpm e AppImage, você cobre a maioria dos usuários Linux com o mínimo de esforço de manutenção.
Referências
- Debian Policy Manual – Controle de pacotes — Documentação oficial sobre campos obrigatórios e scripts de manutenção em pacotes .deb.
- RPM Packaging Guide – Fedora — Guia completo da comunidade Fedora para criação de arquivos .spec e uso de macros RPM.
- AppImage Documentation – AppImageKit — Documentação oficial sobre estrutura AppDir, AppRun e ferramentas como appimagetool e linuxdeploy.
- LinuxDeploy – GitHub — Repositório oficial da ferramenta que automatiza a inclusão de dependências em AppImages.
- Lintian – Debian Package Checker — Ferramenta de validação de pacotes .deb com descrição de tags e boas práticas.
- rpmlint – RPM Package Checker — Repositório e documentação da ferramenta de verificação de pacotes .rpm.
- pkg-config – freedesktop.org — Documentação sobre a ferramenta para gerenciar flags de compilação e linkedição de bibliotecas.