GNU Guix, parte 3/3 – Definição de novos pacotes
Neste terceiro e último post da série, será apresentado como o utilizador pode definir seus próprios pacotes Guix, publicá-los em um canal público, compartilhar e submeter suas mudanças ao projeto.
Atualização 2021-06-13: Correções mínimas.
Criando novos pacotes
Agora que você já sabe o básico da utilização do Guix, como definir e distribuir seus próprios pacotes que não estão no canal oficial? A primeira coisa a se saber é a linguagem a ser utilizada: o Guix é implementado em e utiliza para a definição de pacotes a linguagem Guile Scheme. Ela é a linguagem oficial de extensão do projeto GNU. Não é necessário saber Scheme para empacotamento, mas é necessário saber para implementar recursos no Guix, ou para empacotar projetos muito específicos ou complexos que não seguem um padrão de construção.
Vamos ao exemplo do GNU Hello já empacotado no Guix, onde criaremos um novo pacote chamado myhello
em um canal privado. Crie uma nova pasta e um arquivo em algum lugar com a seguinte estrutura: mychannel/hello.scm
. Copie e cole o seguinte código no arquivo hello.scm
:
(define-module (hello)
#:use-module ((guix licenses) #:prefix license:)
#:use-module (guix packages)
#:use-module (guix download)
#:use-module (guix build-system gnu))
(define-public myhello
(package
(name "myhello")
(version "2.10")
(source
(origin
(method url-fetch)
(uri (string-append "mirror://gnu/hello/hello-" version
".tar.gz"))
(sha256
(base32 "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i"))))
(build-system gnu-build-system)
(synopsis "Hello, GNU world: An example GNU package")
(description
"GNU Hello prints the message \"Hello, world!\" and then exits. It
serves as an example of standard GNU coding practices. As such, it supports
command-line arguments, multiple languages, and so on.")
(home-page "https://www.gnu.org/software/hello/")
(license license:gpl3+)))
Dentro da pasta mychannel
tente construir esse pacote dando precedência à pasta atual ao passar a variável de ambiente GUIX_PACKAGE_PATH
: $ GUIX_PACKAGE_PATH=. guix build myhello
. A execução retornará um caminho para este pacote na store. Instale-o com $ GUIX_PACKAGE_PATH=. guix install myhello
.
Observação: $ guix install
é um apelido para $ guix package --install
. Muitos comandos do Guix são apelidos.
Vamos analisar a forma geral da definição de um pacote:
(define-module (...)
#:use-module ...)
(define-public ... ;nome, opcionalmente com -versao
(package
(name ...) ;nome
(version ...) ;versão
(source ...) ;procedência
(build-system ...) ;qual build system usa
(arguments ...) ;opcional, modificações
(native-inputs ...) ;opcional, entradas nativas
(inputs ...) ;opcional, entradas
(propagated-inputs ...) ;opcional, entradas propagadas
(home-page ...) ;endereço eletrônico
(synopsis ...) ;sinopse
(description ...) ;descrição
(license ...))) ;licença
A primeira coisa a se saber é quais módulos contém o que será usado na definição. Por exemplo, o download por git está no módulo (guix git-download)
. O nome do módulo é o nome das pastas e arquivos que compõe o caminho de onde será executado o comando guix
. Por exemplo, se o pacote tivesse sido construído em um diretório dentro de mychannel
chamado mypkgs
, o módulo seria (mypkgs hello)
. Crie uma pasta chamada mypkgs
dentro de mychannel
e mova o arquivo hello.scm
para esta pasta, altere o nome do módulo e construa o pacote novamente, ainda no diretório raiz mychannel
.
O pacote é definido em termos dos seus dados de identificação (nome, versão), dados de construção (fonte, build-system, entradas), e dados de descrição (sinopse, descrição, endereço, licença). Frequentemente é necessário adicionar argumentos que modificam o processo de construção, para isso utiliza-se (arguments ...)
, mas este processo é mais avançado e tem opções específicas para cada tipo de construção (CMake, Python, …).
A construção é realizada em fases: extrair código fonte, configurar, compilar, testar, instalar, etc. O empacotador pode definir suas próprias fases adicionando a mais ou modificando as existentes pelo (arguments ...)
. Vamos modificar o pacote Hello ignorando e fase de testes e adicionando uma fase de aviso ao final da construção:
(arguments
`(#:tests? #f ;ignora a fase de testes
#:phases
(modify-phases %standard-phases
(add-after 'compress-documentation 'aviso ;adiciona uma fase chamada aviso após a fase compress-documentation
(lambda _
(display "Terminei! :)"))))))
Assim como (add-after 'a 'b)
, há (add-before 'a 'b)
, (replace 'c)
e (delete 'c)
.
Existem três tipos de dependências (entradas): native-inputs
, inputs
e propagated-inputs.
. A primeira são dependências apenas em tempo de construção, a segunda dependências em tempo de execução, e a terceira dependências em tempo de execução e que ainda precisam ser instaladas no perfil do usuário. Essa terceira situação acontece com bibliotecas Python e pacotes do Emacs. A recomendação é propagar as entradas somente se for necessário (para evitar conflito de versão).
Vamos adicionar algumas dependências [desnecessárias] no pacote myhello
, apenas para ilustração:
(native-inputs
`(("pkg-config" ,pkg-config)
("python" ,python-wrapper)))
A melhor forma de aprender a empacotar é, claro, através da prática! Veja outros exemplos de pacotes definidos utilizando guix edit {nomedopacote}
. Estude, reproduza, modifique e reconstrua as definições na sua pasta de pacotes pessoal.
Publicando seu canal
Para publicar seu pacote em um canal próprio, crie um repositório git na pasta mychannel
, hospede o repositório em um serviço Git de sua preferência e adicione em seu arquivo de configuração ~/.config/guix/channels.scm
o seguinte trecho de código:
(cons (channel
(name 'variant-packages)
(url "URL-DO-SEU-REPOSITORIO-GIT"))
%default-channels)
e seu canal será uma fonte adicional de pacotes ao canal oficial.
Se o pacote que você definiu não estiver no canal oficial do Guix, considere contribuir esse pacote se achar que se encaixa nos padrões de lá. Caso tenha interesse em contribuir com o projeto, as próximas seções explicarão o procedimento.
Contribuindo seu pacote
A contribuição de novos pacotes é feita baixando o código fonte do Guix, modificando a parte referente aos pacotes, e enviando um patch com as modificações para a lista de e-mail guix-patches@gnu.org
. Os pacotes estão todos definidos no próprio código fonte do Guix. Assim, o primeiro passo para contribuir é baixar o código fonte do Guix:
$ git clone https://git.savannah.gnu.org/git/guix.git
$ cd guix
Após entrar na pasta do código fonte, entre em um ambiente virtual puro (este elimina as variáveis de ambiente do sistema) do Guix com o comando abaixo.
$ guix environment --pure guix
Na primeira vez é preciso realizar um bootstrap e compilar o Guix (a compilação pode demorar mais de uma hora dependendo da máquina). Eventualmente será preciso recompilar as definições de pacotes do Guix executando make mostlyclean
e reexecutando os dois últimos comandos abaixo, no caso do repositório ser atualizado por um git pull
.
Observação: Os comandos a serem executados dentro deste ambiente virtual puro serão identificados por %
.
% ./bootstrap
% ./configure --localstatedir=/var
% make
Após o término da compilação, o código já está pronto para ser modificado. Um pacote que, no momento, está desatualizado no Guix é o python-identify
, uma biblioteca em Python para identificar tipos de arquivo. No momento de publicação deste post ele está na versão "1.14.25" e a última versão lançada é a "2.1.3". Vamos atualizar este pacote, primeiramente criando uma nova branch
no repositório local.
$ git checkout -b identify
Observação: Se você não tem uma configuração Git, salve o conteúdo do bloco abaixo em ~/.gitconfig
e substitua ...
pelos dados pessoais requisitados.
[user]
name = ... # Será o nome na árvore git do Guix (dado público)
email = ... # Será o email na árvore git do Guix (dado público)
[sendemail]
smtpserver = ...
smtpuser = ...
smtpencryption = ... # Recomendação: tls
smtpserverport = ... # 587 (para tls)
A definição do pacote python-identify
se encontra em gnu/packages/python-xyz.scm
. Se é sua primeira contribuição do ano neste arquivo, adicione também uma linha de copyright no topo do arquivo. Para construir utilizando o código fonte como canal, um shell script chamado pre-inst-env
, que exporta algumas variáveis de ambiente, é providenciado.
% ./pre-inst-env guix build python-identify
A construção vai falhar na primeira vez que o código acima for executado, pois não atualizamos o hash do pacote. O Guix irá dizer o hash correto. Copie e cole no campo base32
da definição do pacote removendo o hash antigo e tente construir novamente. Desta vez a construção deve funcionar. Como é uma biblioteca simples e leve, a construção não deve demorar mais do que cinco minutos.
Se tudo ocorrer bem, execute os comandos abaixo para aplicar as mudanças:
$ git add gnu/packages/python-xyz.scm
$ git commit
O Guix possui algumas normas para mensagens de commit. Utilize a mensagem abaixo e veja outros exemplos de normas com git log
.
gnu: python-identify: Update to 2.1.3.
* gnu/packages/python-xyz.scm (python-identify): Update to 2.1.3.
Depois, geramos um patch das alterações da branch identify
em comparação com a branch master
:
$ git format-patch master
E o patch está pronto (arquivo 0001-gnu-python-identify-update-to-2.1.3.patch
)! Mas, calma! Embora este patch seja perfeitamente válido e muito provavelmente seria aceito, não o envie e espere os comentários finais na próxima seção. Se fosse a hora de enviar o patch, seria utilizado o comando send-email
do git (pacote git-email
no Debian ou git:send-email
no Guix):
$ git send-email --to="guix-patches@gnu.org" 0001-gnu-python-identify-update-to-2.1.3.patch
e seu patch será avaliado por um revisor. Se o patch for aceito, parabéns, você fez sua primeira contribuição a um dos programas mais importantes do projeto GNU e sua contribuição estará gravada na história do repositório.
Comentários finais
Na seção anterior foi mostrado um exemplo de como seria uma contribuição de pacote ao Guix. Para iniciar no desenvolvimento por meio de empacotamento, se for do seu interesse, faça atualizações de pacotes que você conhece e teste o pacote atualizado. Escolha "programas finais" para começar, que não são dependências de outros ou que sejam dependências de poucos pacotes (veja os dependentes com guix refresh --list-dependent {nomedopacote}
). Depois, tente criar pacotes novos para se familiarizar com a estrutura. Como os pacotes estão no código fonte do Guix, você também pode experimentar atualizar a documentação, tradução, ou até mexer no próprio Guix implementando novos recursos. Quem sabe você se torna GNU Contributor no futuro? 🙂
Com este post se encerra a série Guix. Espero que esta tenha gerado interesse na ferramenta e a parte 3 em especial, mostrado que contribuir com software livre, mesmo na parte de programação, é bem menos complicado do que parece.
Em um futuro não muito distante trarei mais posts sobre outras ferramentas GNU. Até!