Dando sequência à nossa série de posts sobre como fazer uma distribuição Linux baseada no openSUSE, hoje eu vou mostrar pra você como criar um pacote RPM no Open Build Service (OBS). Lembrando que eu uso o openSUSE Build Service (build.opensuse.org), que é o servidor de referência público e gratuito do OBS.
Na verdade, já criamos um pacote no primeiro post, mas eu “coloquei o carro na frente dos bois” e expliquei como criar um pacote usando o conjunto completo de Git mais OBS. Você deve se lembrar que eu disse que o OBS pode ser usado para todo o processo de armazenar e gerenciar o código-fonte, mas também compilar e empacotar. Ou seja, o OBS não é apenas uma ferramenta que cria pacotes, ele também tem um sistema de controle de versões próprio. Hoje vamos ver como um pacote pode nascer no OBS.
Se você ainda não leu o post anterior, recomendo que comece por ele:
Para o que vamos fazer hoje, o ideal seria já termos noções sobre empacotamento RPM com rpmbuild, que podem ser adquiridas lendo o Fedora RPM Guide e outras referências. Mas vou tentar mostrar uma visão mais “mão na massa” (hands on) de como fazer um pacote RPM usando o OBS. Caso você tenha alguma dúvida, pode comentar ou consultar as referências no final da página. Além da documentação do openSUSE, eu costumo consultar também a documentação do Fedora, porque é outra distribuição que usa o formato RPM.
Aliás, o Fedora é a versão comunitária do Red Hat Enterprise Linux (assim como o openSUSE é a versão comunitária do SUSE Linux Enterprise) e o Red Hat é o “pai” do RPM (já viu o que significa a sigla RPM?) Portanto, a documentação do Fedora é uma fonte valiosa de informação.
O que vamos empacotar
Dentre os pacotes que criei para a versão atual da distribuição, a 15.2, selecionei um pacote com um arquivo spec pequeno, básico e que ilustre bem o básico que deve vir nesse arquivo. Sendo assim, vamos recriar para a versão 15.3 o pacote sound-theme-materia.
Esse pacote permite a fácil instalação nas distribuições do openSUSE (Leap e Tumbleweed) e no Linux Kamarada do tema de som Materia (na verdade, no Linux Kamarada, ele já vem instalado por padrão). Esse tema de som acompanha o tema GTK Materia, que visa trazer a experiência do Material Design do Google (o mesmo design do Android) para a área de trabalho GNOME e outras áreas de trabalho baseadas na biblioteca GTK.
O código-fonte do tema de som Materia, assim como as instruções para instalá-lo a partir desse código-fonte, estão disponíveis no GitHub:
Antes de criar propriamente o pacote, geralmente é uma boa ideia tentar compilá-lo e instalá-lo na própria máquina ou em uma máquina virtual, até para descobrir as dependências e se familiarizar com o processo de compilação e instalação do programa.
Embora os desenvolvedores tenham chamado o repositório original de materia-sound-theme, e geralmente é uma boa ideia dar o mesmo nome ao pacote (na verdade, você pode nomear o pacote como quiser), eu preferi chamar o pacote de sound-theme-materia para seguir um padrão que eu percebi no openSUSE. Veja como são chamados outros pacotes de temas de sons: sound-theme-freedesktop, sound-theme-yaru…
Criando o pacote no OBS
Uma vez logado no OBS, acesse o projeto onde deseja criar o pacote (no meu caso, o projeto de desenvolvimento da distribuição, o home:kamarada:15.3:dev).
Mude para a aba Overview (visão geral) e clique em Create Package (criar pacote):
Dê pelo menos um nome (Name) para o pacote (no meu caso, sound-theme-materia
) e clique em Create (criar):
O pacote é criado no OBS. Por enquanto, não possui arquivos:
Fazendo checkout do pacote
Criado o pacote no OBS, até poderíamos trabalhar nele usando apenas a interface web. Mas vamos trazê-lo para o computador para trabalhar nele localmente, de modo análogo ao que fazemos ao clonar um repositório do Git.
Como vimos no post anterior, podemos criar uma cópia local (“fazer checkout”) do projeto inteiro, caso ainda não tenhamos feito isso:
1
$ osc checkout home:kamarada:15.3:dev
Se já temos uma cópia local do projeto (e esse é o caso), para baixar esse novo pacote, temos duas opções.
Uma delas é entrar na pasta do projeto e fazer checkout apenas do pacote:
1
2
$ cd home:kamarada:15.3:dev
$ osc co sound-theme-materia
(você pode abreviar a opção checkout do comando osc como apenas co)
A outra é entrar na pasta do projeto e atualizar (update) a cópia local, o que vai baixar não apenas o pacote novo, como também quaisquer alterações feitas em outros pacotes e que ainda não tenham sido sincronizadas para a cópia local:
1
2
$ cd home:kamarada:15.3:dev
$ osc up
(aqui também você pode usar update ou a abreviação up)
Seja qual for a opção escolhida, depois entre na pasta do pacote:
1
$ cd sound-theme-materia
Baixando o código-fonte do upstream
A palavra upstream poderia ser traduzida, em uma tradução literal, como “rio acima” ou “fluxo acima”. No desenvolvimento de software, chamamos de upstream o autor original do software. Esse termo é comumente usado por empacotadores ou desenvolvedores que fazem forks no Git.
Por exemplo, pode acontecer de o Projeto openSUSE identificar um bug no LibreOffice e corrigir esse bug primeiro no seu pacote, para depois enviar a correção para o upstream (o Projeto LibreOffice). Ou – o que acredito ser mais comum – o bug ser corrigido primeiro no upstream para então a atualização ser baixada pela distribuição. De uma forma ou de outra, quando a correção é liberada pelo upstream, todas as distribuições que empacotam aquele programa são beneficiadas, todos saem ganhando.
Outro exemplo é o que o Projeto openSUSE está fazendo ao tentar introduzir o suporte ao Raspberry Pi 4 primeiro no upstream (o kernel Linux), como já expliquei em outro texto.
Voltando ao nosso pacote… como eu disse, seu código-fonte é hospedado no GitHub. Então, vamos acessar a página do projeto no GitHub e clicar em Releases (lançamentos, versões):
Só houve uma versão lançada, a v0.1
. Baixe o código-fonte dessa versão clicando no link Source code, e dê preferência ao formato .tar.gz
, por ser mais amigável ao Linux:
Quando o download terminar, mova o arquivo materia-sound-theme-0.1.tar.gz
para a pasta do projeto.
Escrevendo o arquivo spec
O arquivo spec (do inglês spec file, abreviação de specification file, arquivo de especificação) contém informações sobre o pacote (como nome, descrição, versão, autor, site, licença de uso, etc), os comandos necessários para compilá-lo e instalá-lo, sua lista de arquivos, histórico de alterações (changelog) e possivelmente outras informações.
Todo pacote RPM tem um arquivo spec correspondente. O arquivo spec é um arquivo de texto e normalmente é nomeado com o nome do pacote.
Para o nosso pacote sound-theme-materia, vamos criar um arquivo de texto vazio chamado sound-theme-materia.spec
:
1
$ touch sound-theme-materia.spec
Abra esse arquivo com seu editor de texto preferido. Pode ser o Editor de texto padrão do GNOME (o Gedit), ou, se você é mais sinistro e prefere editar o arquivo no terminal mesmo, o nano, o joe ou o vim. O Linux Kamarada vem “de fábrica” com essas quatro opções.
Como veremos, o arquivo spec tem uma sintaxe própria, que deve ser obedecida para que as informações possam ser entendidas pelo RPM, pelo OBS e por outros programas.
Seção introdutória do arquivo spec
Comece copiando e colando para o arquivo spec sua seção introdutória:
1
2
3
4
5
6
7
8
9
10
11
12
Name: sound-theme-materia
Version: 0.1
Release: 0
Summary: Materia Sound Theme
License: GPL-3.0
Group: System/Libraries
Url: https://github.com/nana-4/materia-sound-theme
Source: https://github.com/nana-4/materia-sound-theme/archive/v%{version}.tar.gz#/materia-sound-theme-%{version}.tar.gz
BuildRequires: fdupes
BuildRequires: meson
BuildRequires: ninja
BuildArch: noarch
Essa seção contém informações gerais sobre o pacote. Explico cada linha a seguir.
- Name: o nome do pacote. Não deve conter espaços ou outros caracteres de espaço em branco, como tabulações ou novas linhas. Use caracteres válidos para nomes de arquivo. Sugiro não usar muita criatividade aqui. Pense em quem vai digitar um comando como este para instalar seu pacote:
1
# zypper in sound-theme-materia
Você também pode pesquisar pacotes semelhantes já existentes na distribuição e nomear o seu de acordo. Fiz assim no exemplo: sound-theme-freedesktop, sound-theme-yaru…
-
Version: versão do pacote, de preferência no formato de números separados por pontos (x.y.z). Aqui usamos a versão informada pelo próprio upstream (
0.1
). Tenha em mente que esse número de versão será usado pelo sistema para comparar a versão instalada com a versão disponível no repositório, para determinar se o pacote deve ser atualizado. No nosso exemplo, a próxima versão desse pacote pode ser0.1.1
ou0.2
, mas não0.0.1
. Procure se informar sobre versionamento semântico. -
Release: poderíamos traduzir para “lançamento”. É uma espécie de versão do próprio pacote. Se esse número mudou, mas o da versão permaneceu, indica que o pacote mudou, ainda que o programa empacotado não tenha mudado. Uma boa prática é começar com
0
ou1
e incrementar esse número a cada modificação do arquivo spec. Então, por exemplo, estamos criando agora o pacote 0 da versão 0.1. Suponhamos que eu lancei o pacote, mas depois percebi um erro de digitação no arquivo spec. Então eu corrijo esse erro, incremento o release para 1 e lanço a atualização. -
Summary: resumo. Uma breve descrição do pacote em uma linha. Procure não usar muito mais que 50 caracteres.
-
License: licença de uso do software. Essa informação também deve ser obtida do upstream. A licença deve ser declarada usando o formato de nome curto SPDX. Exemplos:
GPL-3.0
,MIT
,LGPL-2.1-or-later
,GPL-2.0+
,GPL-2.0-only
,Apache-2.0
, etc. -
Group: grupo ao qual pertence o pacote. Permite uma espécie de classificação dos pacotes. Exemplos:
System/Libraries
,Productivity/Office/Suite
,Hardware/Printing
, veja mais aqui e aqui. Vale observar que esse campo não é obrigatório e está caindo em desuso. A documentação do Fedora explicitamente desaconselha o seu uso. Caso você queira usá-lo (por enquanto, eu tenho usado), dê preferência a informar um nome de grupo listado em um dos links anteriores. -
Url: o site oficial do pacote ou uma página na qual pode-se obter mais informações sobre ele. Por exemplo, a
Url
do pacote chromium éhttps://www.chromium.org/
. No caso do pacote que estou criando, como aparentemente ele não tem um site oficial, informei a página do projeto no GitHub. -
Source: código-fonte. A maioria dos pacotes tem um ou mais arquivos de código-fonte, que devem ser listados no arquivo spec. Muitas vezes (e esse é o caso aqui), há um arquivo
.tar.gz
que contém os arquivos do código-fonte compactados. Se o arquivo foi baixado da Internet, você deve fornecer o link para download. Isso é apenas para documentação e conveniência, o arquivo não será baixado na hora de criar o pacote. Nós já baixamos esse arquivo antes.
Se você precisa referenciar mais de um arquivo de código-fonte, use uma tag Source
para cada arquivo, numerando todas as tags a partir do zero: Source0
, Source1
, Source2
… isso é útil para separar o código fornecido pelo upstream, que deve ser mantido intacto, como veio, e personalizações feitas pela distribuição, que podem ser listadas como patches.
Também é comum o arquivo ser obtido de um sistema de controle de versão, como o Git (e esse também é o caso aqui). Nesses casos, as URLs de alguns serviços já são conhecidas, há modelos que você pode reutilizar na documentação do Fedora.
É oportuno falar sobre as macros do RPM, que podem ser entendidas como variáveis, funções e em alguns casos até mesmo scripts providos pelo sistema de empacotamento RPM para facilitar a escrita do arquivo spec e torná-lo mais legível. Aqui usamos a macro %{version}
, que será substituída pela versão do pacote, declarada em Version
.
Você pode consultar listas de macros predefinidas, e também como definir suas próprias macros, nos links a seguir:
- openSUSE:Packaging Conventions RPM Macros - openSUSE Wiki
- RPM Macros - Fedora Packaging Guidelines
- 9.7. Defining Spec File Macros - Fedora RPM Guide
-
rpm.org - Documentation - Packager Documentation - Macro syntax
- BuildRequires: dependência para compilar o pacote. Comumente, você precisa que outros programas estejam previamente instalados no sistema até para que você consiga compilar o código-fonte do programa. Essa informação é fornecida pelo upstream, normalmente nas instruções de compilação. Nesse exemplo, precisamos dos pacotes fdupes, meson e ninja para compilar o tema de som. Você pode listar todas as dependências em uma única linha, separadas por espaço ou vírgula, ou pode usar uma linha para cada dependência (o que é mais legível e também mais comum).
O tema de som que estamos empacotando não tem dependências adicionais. Mas os pacotes também podem declarar dependências para funcionar (Requires) e dependências para instalar (PreReq), além de outros tipos de dependências e/ou conflitos com outros pacotes (Conflicts). Para mais informações, consulte as referências no final dessa página.
- BuildArch: arquitetura a que se destina o pacote. Se você estiver empacotando arquivos que são independentes da arquitetura do computador (por exemplo, shell scripts, arquivos de dados ou temas de som, como esse exemplo), informe
noarch
. Exemplos de arquiteturas comuns incluem:i586
,i686
,x86_64
eaarch64
.
Caso você não saiba a arquitetura do seu computador, use o comando uname -m
para descobrir. No meu notebook (PC de 64 bits), esse comando retorna x86_64
. No meu Raspberry Pi 4, esse comando retorna aarch64
.
Note que na verdade o campo BuildArch
se refere ao computador onde o pacote será instalado, que não necessariamente é da mesma arquitetura que o seu próprio computador. Por meio do OBS, você pode, por exemplo, usar seu PC para criar um pacote que será instalado em um Raspberry Pi. Nesse caso, você deve usar BuildArch: aarch64
.
Demais seções do arquivo spec
A seguir, apresento as demais seções do arquivo spec. Copie e cole os trechos a seguir no seu arquivo spec.
1
2
3
%description
Materia Sound Theme is a freedesktop sound theme using Google's Material sound
resources. It follows the Material sound guidelines.
Na seção %description
, você deve fornecer uma descrição mais longa do pacote. Aqui você pode usar uma linha ou mais, tantas quantas necessárias, mas todas devem ter no máximo 80 caracteres (como se fosse a margem de uma página). Linhas em branco separam parágrafos.
1
2
%prep
%autosetup -n materia-sound-theme-%{version}
A seção %prep
lista comandos, em formato de script, para preparar o pacote para compilação. Normalmente o código-fonte vem compactado dentro de um arquivo .tar.gz
e é na seção %prep
que ele é extraído. Nessa seção também podem ser aplicados patches, seja para corrigir erros nos programas, seja para aplicar personalizações da distribuição.
Nesse exemplo, é usada a macro %autosetup
, que faz essas duas tarefas: descompactar o código-fonte (nesse caso, somente um arquivo .tar.gz
) e aplicar eventuais patches (nesse caso, nenhum). A opção -n
informa a pasta que é criada quando o conteúdo do arquivo compactado é extraído. Outras macros comuns na seção %prep
são %setup
e %patch
.
1
2
3
%build
%meson
%meson_build
A seção %build
lista comandos, também em formato de script, para compilar o pacote, ou seja, deixá-lo pronto para instalação. Nessa seção, são comuns a macro %configure
e o comando make.
Nesse exemplo, são usadas as macros %meson
e %meson_build
, relacionadas ao sistema de compilação Meson, usado para compilar o tema de som que estamos empacotando.
1
2
3
%install
%meson_install
%fdupes %{buildroot}%{_datadir}/sounds/
A seção %install
lista comandos, também em formato de script, para instalar o pacote. Esses comandos são executados no computador do empacotador, simulando a instalação. Comumente essa seção é responsável por copiar os arquivos compilados do diretório de compilação (representado pela macro %{_builddir}
) para o diretório que simula a raiz do computador onde o pacote será instalado (macro %{buildroot}
).
É preferível, sempre que possível, usar macros em vez de caminhos fixos. Por exemplo, a macro %{_datadir}
por padrão equivale ao caminho /usr/share
. Para uma lista de macros para caminhos, consulte a página RPM Macros na documentação do Fedora.
No nosso arquivo spec de exemplo, aparece a macro %fdupes
, que é relativamente comum e é usada para substituir eventuais arquivos duplicados por links simbólicos.
1
2
3
%files
%defattr(-,root,root)
%{_datadir}/sounds/*
A seção %files
contém uma lista de todos os arquivos do pacote, um arquivo por linha. Você pode usar o caractere curinga (*
) para se referir a vários arquivos. Além de caminhos para arquivos, você também pode informar caminhos para pastas, declarando que todo o conteúdo dessas pastas pertence ao pacote.
1
%changelog
A seção %changelog
normalmente listaria um histórico de mudanças do pacote. Mas o Open Build Service requer que declaremos essa seção, mas a deixemos em branco, e façamos o histórico de mudanças em um arquivo à parte, que é o que veremos a seguir.
Terminamos de analisar o arquivo spec de exemplo. Aqui, foquei no necessário para entender esse exemplo de arquivo spec, mas muitas outras coisas podem aparecer em um arquivo spec. Para mais informações, consulte as referências no final da página.
Escrevendo o arquivo changes
Cada vez que fizer mudanças no pacote, você deve adicionar uma entrada no changelog (histórico de mudanças) descrevendo essa mudança. Isso é importante não apenas para ter uma ideia sobre a história de um pacote, mas também para permitir que usuários, outros empacotadores e testadores identifiquem facilmente as alterações feitas.
O Open Build Service usa um arquivo separado para o changelog. Esse arquivo tem o mesmo nome do arquivo spec, mas a extensão é .changes
em vez de .spec
.
Para adicionar uma entrada ao changelog, use o comando:
1
$ osc vc
(o arquivo changes será criado, caso ainda não exista)
O editor de texto padrão é usado para abrir o arquivo changes. A data atual é sugerida:
1
2
3
4
-------------------------------------------------------------------
Sun Aug 15 01:30:00 UTC 2021 - Antônio Vinícius Menezes Medeiros Medeiros <linuxkamarada@gmail.com>
-
Como não fiz nenhuma alteração nesse pacote do Linux Kamarada 15.2 para o 15.3, em vez de criar um novo arquivo changes, vou copiar e colar o anterior. Veja o exemplo:
1
2
3
4
-------------------------------------------------------------------
Sun Jul 5 01:25:41 UTC 2020 - Antônio Vinícius Menezes Medeiros Medeiros <linuxkamarada@gmail.com> - 0.1
- First packaging, initial release (v0.1)
Para mais informações sobre o arquivo changes, consulte:
Compilando o pacote localmente
Caso o pacote não seja de uma arquitetura diferente do seu computador, pode ser uma boa ideia compilar o pacote antes de enviá-lo para o OBS. Com isso, se houver algo errado, você pode corrigir o erro antes do envio. Para compilar seu pacote localmente, execute:
1
$ osc build
Se houver ambiguidade, pode ser necessário informar a distribuição e a arquitetura:
1
$ osc build openSUSE_Leap_15.3 x86_64
O osc vai precisar baixar pacotes e pergunta se pode confiar no repositório:
1
2
3
4
5
6
7
8
9
Updating cache of required packages
The build root needs packages from project 'SUSE:SLE-15:Update'.
Note that malicious packages can compromise the build result or even your system.
Would you like to ...
0 - quit (default)
1 - always trust packages from 'SUSE:SLE-15:Update'
2 - trust packages just this time
?
Digite 1
para sempre confiar nesse repositório e tecle Enter.
Note que o OBS (e o osc) não compila o pacote diretamente no sistema do computador. Ele baixa todos os pacotes necessários e faz uma instalação mínima do Linux “enjaulada” (chroot), para então compilar o pacote nessa instalação. Com isso, o OBS garante que o arquivo spec foi escrito corretamente e que o pacote não está sendo compilado com sucesso apenas porque é no seu computador. Isso garante que a compilação do pacote pode ser reproduzida (reproducible build) por qualquer um, em qualquer computador.
Quando terminar de baixar os pacotes, o osc vai exigir a senha do root para criar o ambiente chroot e começar a compilação do pacote.
Ao final, se tudo der certo, você terá uma saída parecida com esta:
1
2
3
4
5
6
7
8
9
10
11
[ 28s] RPMLINT report:
[ 28s] ===============
[ 28s] 2 packages and 0 specfiles checked; 0 errors, 0 warnings.
[ 28s]
[ 28s]
[ 28s] kamarada-pc finished "build sound-theme-materia.spec" at Sun Aug 15 01:53:33 UTC 2021.
[ 28s]
/var/tmp/build-root/openSUSE_Leap_15.3-x86_64/home/abuild/rpmbuild/SRPMS/sound-theme-materia-0.1-0.src.rpm
/var/tmp/build-root/openSUSE_Leap_15.3-x86_64/home/abuild/rpmbuild/RPMS/noarch/sound-theme-materia-0.1-0.noarch.rpm
As últimas linhas indicam onde você pode encontrar o pacote RPM fonte (.src.rpm
) e o pacote RPM em si (.rpm
). Como mais um teste, você pode instalá-lo no seu computador ou máquina virtual (dica: para copiar e colar no terminal, use Ctrl + Shift + C e Ctrl + Shift + V):
1
$ sudo rpm -Uvh /var/tmp/build-root/openSUSE_Leap_15.3-x86_64/home/abuild/rpmbuild/RPMS/noarch/sound-theme-materia-0.1-0.noarch.rpm
Enviando o pacote para o OBS
Assim que o pacote estiver como deseja, use os comandos a seguir para enviar seu trabalho para o OBS (se você já tiver familiaridade com algum sistema de controle de versões, como o Git, verá que a lógica é parecida).
Confira o status da pasta:
1
2
3
4
$ osc status
? materia-sound-theme-0.1.tar.gz
? sound-theme-materia.changes
? sound-theme-materia.spec
Nesse caso, nenhum dos 3 arquivos está no controle de versões do OBS. Para adicioná-los, use:
1
2
3
4
$ osc add *
A materia-sound-theme-0.1.tar.gz
A sound-theme-materia.changes
A sound-theme-materia.spec
Por fim, para enviar as alterações para o OBS, execute:
1
$ osc commit
Tal como no Git, o editor de texto é aberto para que você forneça uma mensagem para o commit (alteração). A entrada mais recente do changelog é sugerida. Você pode só salvar o arquivo e fechar o editor de texto.
1
2
3
4
5
Sending materia-sound-theme-0.1.tar.gz
Sending sound-theme-materia.changes
Sending sound-theme-materia.spec
Transmitting file data ..
Committed revision 1.
Se você abrir a página do seu pacote no OBS, verá que está sendo compilado (building):
Como a compilação local deu certo, é provável que a compilação pelo OBS também dê certo:
Você pode clicar no resultado (succeeded, “com sucesso”) para visualizar o relatório da compilação:
Esse relatório é útil quando algo dá errado na compilação.
Voltando à página do pacote, você pode usar o link Download package para baixar o pacote RPM para o seu computador.
Note que também é possível encontrá-lo e instalá-lo a partir de software.opensuse.org.
Conclusão
Espero que esse tutorial possa ter te ajudado caso você esteja procurando como fazer pacotes RPM com o auxílio do Open Build Service. Aqui, mostrei uma visão “mão na massa” a partir de um exemplo de pacote RPM, mas não esgotei o assunto. Você pode encontrar mais informações sobre o OBS e sobre empacotamento RPM nos links a seguir.