--- title: Capítulo 4. Port Lento prev: books/porters-handbook/quick-porting next: books/porters-handbook/makefiles showBookMenu: true weight: 4 params: path: "/books/porters-handbook/slow-porting/" --- [[slow-porting]] = Port Lento :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 4 :partnums: :source-highlighter: rouge :experimental: :images-path: books/porters-handbook/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] Certo, então não foi tão simples e o port precisou de algumas modificações para poder funcionar. Nesta seção, vamos explicar passo a passo como modificá-lo para que funcione com o paradigma do ports. [[slow-work]] == Como as Coisas Funcionam Primeiro, esta é a sequência de eventos que ocorre quando o usuário executa `make` no diretório do port. Ter o [.filename]#bsd.port.mk# aberto em outra janela enquanto lê esta seção realmente irá ajudar a entender melhor. Mas não se preocupe, não são muitas as pessoas que entendem exatamente como o [.filename]#bsd.port.mk# funciona..._:-)_ [.procedure] ==== . O target `fetch` é executado. O target `fetch` é responsável por garantir que o tarball exista localmente em `DISTDIR`. Se o `fetch` não puder encontrar os arquivos necessários no `DISTDIR` ele procurará a URL na variável `MASTER_SITES`, definida no Makefile, assim como nos nossos mirrors FTP nos quais colocamos os distfiles como backup. Em seguida, ele tentará buscar o arquivo de distribuição nomeado com `FETCH`, assumindo que o site solicitante tem acesso direto à Internet. Se isso for bem sucedido, ele salvará o arquivo em `DISTDIR` para uso futuro e continuará. . O target `extract` é executado. Ele procura pelo arquivo de distribuição do port (normalmente um tarball compactado) em `DISTDIR` e irá descompactá-lo em um subdiretório temporário especificado por `WRKDIR` (padrão é [.filename]#work#). . O target `patch` é executado. Primeiro, quaisquer patches definidos em `PATCHFILES` são aplicados. Segundo, se arquivos de patch nomeados [.filename]#patch-*# forem encontrados em `PATCHDIR` (padrão para o subdiretório [.filename]#files#), eles serão aplicados neste momento em ordem alfabética. . O target `configure` é executado. Ele pode fazer qualquer uma de muitas coisas diferentes. .. Se existir, [.filename]#scripts/configure# é executado. .. E se `HAS_CONFIGURE` ou `GNU_CONFIGURE` está definido, [.filename]#WRKSRC/configure# é executado. . O target `build` é executado. Ele é responsável por mudar para o diretório de trabalho privado do port (`WRKSRC`) e compila-lo. . O target `stage` é executado. Este coloca o conjunto final de arquivos construídos em um diretório temporário (`STAGEDIR`, Veja crossref:special[staging,Staging]). A hierarquia deste diretório espelha a do sistema no qual o pacote será instalado. . O target `package` é executado. Ele cria um pacote usando os arquivos do diretório temporário criado durante o target `stage` e o [.filename]#pkg-plist# do port. . O target `install` é executado. Este instala o pacote criado durante o target `package` no host. ==== As ações acima são padrão. Além disso, defina os targets `pre-_something_` ou `post-_something_`, ou insira scripts com esses nomes no subdiretório [.filename]#scripts#, e eles serão executados antes ou depois das ações padrão serem executadas. Por exemplo, se houver um target `post-extract` definido no [.filename]#Makefile# e um arquivo [.filename]#pre-build# no subdiretório [.filename]#scripts#, o target `post-extract` será chamado após as ações de extração regulares e [.filename]#pre-build# será executado antes que as regras de compilação padrão sejam feitas. Recomenda-se usar targets no [.filename]#Makefile# se as ações forem simples, porque será mais fácil para alguém descobrir que tipo de ação não padrão o port necessita. As ações padrão são feitas pelos targets `do-_something_` do [.filename]#bsd.port.mk#. Por exemplo, os comandos para extrair um port estão no target `do-extract`. Se o target padrão não fizer o trabalho direito, redefina o target `do-_something_` no [.filename]#Makefile#. [NOTE] ==== O target "principal" (por exemplo, `extract`, `configure`, etc.) fazem nada mais do que certificar-se de que todos os estágios até aquele estão concluídos e chamar os targets ou scripts reais, e eles não pretendem ser alterados. Para consertar a extração, corrija `do-extract`, mas nunca mude a forma como `extract` opera! Além disso, o target `post-deinstall` é inválido e não é executado pela infraestrutura de ports. ==== Agora que o que acontece quando o usuário digita `make install` é melhor entendido, vamos seguir as etapas recomendadas para criar o port perfeito. [[slow-sources]] == Obtendo os Fontes Originais Obtenha os fontes originais (normalmente) como um tarball compactado ([.filename]#foo.tar.gz# ou [.filename]#foo.tar.bz2#) e copie-o para `DISTDIR`. Use fontes do _mainstream_ sempre que possível. Definir a variável `MASTER_SITES` para refletir onde o tarball original reside. Existem definições abreviadas para a maioria dos sites mainstream em [.filename]#bsd.sites.mk#. Por favor, use esses sites - e as definições associadas--se for possível, para ajudar a evitar o problema de ter as mesmas informações repetidas várias vezes na base de origem. Como esses sites tendem a mudar com o tempo, isso se torna um pesadelo de manutenção para todos os envolvidos. Veja crossref:makefiles[makefile-master_sites,`MASTER_SITES`] para detalhes. Se não houver nenhum site FTP/HTTP bem conectado à rede ou se puder encontrar apenas sites com formatos irritantemente não-padrão, coloque uma cópia em um servidor FTP ou HTTP confiável (por exemplo, uma home page). Se um lugar conveniente e confiável para colocar o distfile não puder ser encontrado, nós podemos "hospedar" em `ftp.FreeBSD.org`; no entanto, esta é a solução menos preferida. O distfile deve ser colocado em [.filename]#~/public_distfiles/# da conta `freefall` de alguém. Peça para a pessoa que for fazer o commit do port para realizer isso. Essa pessoa também irá definir `MASTER_SITES` para `LOCAL/_username_` onde `_username_` é o seu login do cluster do FreeBSD. Se o distfile do port mudar o tempo todo sem nenhum tipo de atualização de versão pelo autor, considere colocar o distfile em uma página pessoal e liste-a como o `MASTER_SITES` primário. Tente falar com o autor do port para parar de fazer isso; Isso realmente ajuda a estabelecer algum tipo de controle de código-fonte. Hospedar uma versão específica impedirá que os usuários obtenham erros de `checksum mismatch`, e também irá reduzir a carga de trabalho dos mantenedores do nosso site FTP. Além disso, se houver apenas um site master para o port, recomenda-se armazenar um backup em uma home page e listá-lo como o `MASTER_SITES` secundário. Se o port exigir patches adicionais disponíveis na Internet, baixe-os também e coloque-os em `DISTDIR`. Não se preocupe se eles vierem de um site diferente de onde vem o tarball do código fonte principal, temos uma maneira de lidar com essas situações (veja a descrição <> abaixo). [[slow-modifying]] == Modificando o Port Desempacote uma cópia do tarball em um diretório privado e faça as alterações necessárias para que o port compile corretamente sob a versão atual do FreeBSD. _Atenção dobrada_ nessas etapas, pois elas serão necessárias para automatizar o processo em breve. Tudo, incluindo a exclusão, adição ou modificação de arquivos, devem ser realizados usando um script automatizado ou um arquivo patch quando o port estiver finalizado. Se o port exigir interação/customização significativa do usuário para compilar ou instalar, dê uma olhada em um dos scripts Configure clássicos de Larry Wall e talvez faça algo semelhante. O objetivo da nova coleção de ports é fazer com que cada port seja "plug-and-play" o quanto possível para o usuário final, usando um mínimo de espaço em disco. [NOTE] ==== A menos que explicitamente declarado, os arquivos de patch, scripts e outros arquivos criados e contribuídos para a coleção de ports do FreeBSD são assumidos como cobertos pelas condições de copyright padrão do BSD. ==== [[slow-patch]] == Patching Na preparação do port, arquivos que forem adicionados ou alterados podem ser gravados com man:diff[1] para posterior inclusão em um man:patch[1]. Fazer isso com um arquivo típico envolve salvar uma cópia do arquivo original antes de fazer qualquer alteração usando um sufixo [.filename]#.orig#. [source,shell] .... % cp file file.orig .... Depois que todas as alterações forem realizadas, `cd` de volta ao diretório do port. Execute `make makepatch` para gerar arquivos de patch atualizados no diretório [.filename]#files#. [TIP] ==== Usar `BINARY_ALIAS` para substituir comandos codificados durante a compilação e para evitar patching de arquivos de compilação. Veja crossref:makefiles[binary-alias,Use `BINARY_ALIAS` para Renomear Comandos Em Vez de Aplicar Patch na Compilação] para maiores informações. ==== [[slow-patch-rules]] === Regras Gerais para Patching Arquivos patch são armazenados em `PATCHDIR`, geralmente [.filename]#files/#, de onde serão aplicados automaticamente. Todas os patches devem ser relativos ao `WRKSRC`. Tipicamente `WRKSRC` é um subdiretório de `WRKDIR`, o diretório onde o distfile é extraído. Execute `make -V WRKSRC` para ver o caminho real. Os nomes dos patches devem seguir estas regras: * Evite ter mais de um patch modificando o mesmo arquivo. Por exemplo, ter os dois [.filename]#patch-foobar.c# e [.filename]#patch-foobar.c2# fazendo alterações em [.filename]#${WRKSRC}/foobar.c# torna-os frágeis e difíceis de serem depurados. * Ao criar nomes para arquivos de patch, substitua cada underline (`_`) com dois underlines (`__`) e cada barra (`/`) com um underline (`_`). Por exemplo, para corrigir um arquivo chamado [.filename]#src/freeglut_joystick.c# nomeie o patch correspondente [.filename]#patch-src_freeglut__joystick.c#. Não nomeie patches como [.filename]#patch-aa# ou [.filename]#patch-ab#. Sempre use o caminho e o nome do arquivo nos nomes dos patches. O `make makepatch` gera automaticamente os nomes corretos. * Um patch pode modificar vários arquivos se as alterações estiverem relacionadas e o patch tiver o nome apropriado. Por exemplo, [.filename]#patch-add-missing-stdlib.h#. * Use apenas caracteres `[-+._ a-zA-Z0-9]` para nomear patches. Em particular, não use ``::`` como um separador de path, use `_` no lugar. Minimize a quantidade de mudanças de espaço em branco não funcionais em patches. É comum no mundo Open Source para projetos compartilhar grandes quantidades de uma base de código, mas obedecer a regras de recuo e estilo diferentes. Ao usar uma funcionalidade funcional de um projeto para consertar áreas similares em outra, por favor, tenha cuidado: o patch resultante pode estar cheio de mudanças não-funcionais. Ele não só aumenta o tamanho do repositório do ports, mas torna difícil descobrir o que exatamente causou o problema e o que foi alterado em todos. Se um arquivo precisar ser excluído, faça-o no target `post-extract` em vez de como parte do patch. [[slow-patch-manual]] === Geração Manual de Patches [NOTE] ==== A criação manual de patches geralmente não é necessária. A geração automática de patches, conforme descrito anteriormente nesta seção, é o método preferido. No entanto, patches manuais podem ser necessários ocasionalmente. ==== Patches são salvos em arquivos nomeados como [.filename]#patch-*# onde _*_ indica o nome do caminho do arquivo que está sendo feito o patch, como [.filename]#patch-imakefile# ou [.filename]#patch-src-config.h#. Depois que o arquivo foi modificado, man:diff[1] é usado para registrar as diferenças entre a versão original e a modificada. `-u` faz com que o man:diff[1] produza diffs "unificados", a forma preferida. [source,shell] .... % diff -u file.orig file > patch-pathname-file .... Ao gerar patches para novos arquivos adicionados, `-N` é usado para dizer ao man:diff[1] para tratar o arquivo original inexistente como se existisse, mas estava vazio: [source,shell] .... % diff -u -N newfile.orig newfile > patch-pathname-newfile .... Não adicione Strings RCS `$FreeBSD: head/pt_BR.ISO8859-1/books/porters-handbook/book.xml 54410 2020-08-05 22:13:01Z dbaio $` em patches. Quando os patches são adicionados ao repositório Subversion com `svn add`, a propriedade `fbsd:nokeywords` é definida para `yes` automaticamente para que as keywords no patch não sejam modificadas no commit. A propriedade pode ser adicionada manualmente `svn propset fbsd:nokeywords yes _files..._`. Usar a opção (`-r`) do man:diff[1] para gerar patches é razoável, mas por favor, analise os patches resultantes para se certificar de que não há nenhum lixo desnecessário neles. Em particular, diffs entre dois arquivos de backup, quando o port usa `Imake` ou GNU `configure`, etc., diffs de [.filename]##Makefile##s são desnecessários e devem ser eliminados. Se for necessário editar o [.filename]#configure.in# e executar o `autoconf` para regerar o `configure`, não gere diffs do `configure` (ele geralmente cresce para algumas milhares de linhas!). Em vez disso, defina `USES=autoreconf` e gere os diffs no [.filename]#configure.in#. [[slow-patch-automatic-replacements]] === Substituições Automáticas Simples Substituições simples podem ser realizadas diretamente do [.filename]#Makefile# do port usando o modo in-loco do man:sed[1]. Isso é útil quando as alterações usam o valor de uma variável: [.programlisting] .... post-patch: @${REINPLACE_CMD} -e 's|/usr/local|${PREFIX}|g' ${WRKSRC}/Makefile .... [IMPORTANT] ==== Use o man:sed[1] apenas para substituir conteúdo de variáveis. Você deve usar arquivos patch em vez do man:sed[1] para substituir conteúdo estático. ==== Muitas vezes, o software sendo portado usa a convenção CR/LF nos arquivos fonte. Isso pode causar problemas com correções adicionais, avisos do compilador ou execução de scripts (como `/bin/sh^M não encontrado`.) Para converter rapidamente todos os arquivos de CR/LF para apenas LF, adicione essa entrada ao [.filename]#Makefile# do port: [.programlisting] .... USES= dos2unix .... Uma lista de arquivos específicos para conversão pode ser informada: [.programlisting] .... USES= dos2unix DOS2UNIX_FILES= util.c util.h .... Use `DOS2UNIX_REGEX` para converter um grupo de arquivos em subdiretórios. Seu argumento é um man:find[1] compatível com expressão regular. Mais sobre o formato está em man:re_format[7]. Esta opção é útil para converter todos os arquivos de uma determinada extensão. Por exemplo, converta todos os arquivos de código-fonte, deixando os arquivos binários intactos: [.programlisting] .... USES= dos2unix DOS2UNIX_REGEX= .*\.([ch]|cpp) .... Uma opção similar é `DOS2UNIX_GLOB`, que executa o `find` para cada elemento listado nele. [.programlisting] .... USES= dos2unix DOS2UNIX_GLOB= *.c *.cpp *.h .... O diretório base para a conversão pode ser definido. Isso é útil quando há vários distfiles e vários arquivos contidos que requerem conversão de fim de linha. [.programlisting] .... USES= dos2unix DOS2UNIX_WRKSRC= ${WRKDIR} .... [[slow-patch-extra]] === Corrigindo Condicionalmente Alguns ports precisam de patches que são aplicados apenas para versões específicas do FreeBSD ou quando uma determinada opção é ativada ou desativada. Os patches condicionais são especificados colocando-se os caminhos completos para os arquivos de patch em `EXTRA_PATCHES`. [[slow-patch-extra-ex1]] .Aplicando um Patch para uma Versão Específica do FreeBSD [example] ==== [.programlisting] .... .include # Patch in the iconv const qualifier before this .if ${OPSYS} == FreeBSD && ${OSVERSION} < 1100069 EXTRA_PATCHES= ${PATCHDIR}/extra-patch-fbsd10 .endif .include .... ==== [[slow-patch-extra-ex2]] .Aplicando Opcionalmente um Patch [example] ==== Quando um crossref:makefiles[makefile-options,option] requer um patch, use `OPT_EXTRA_PATCHES` e `OPT_EXTRA_PATCHES_OFF` para fazer o patch condicional na opção `_opt_`. Veja <> Para maiores informações. [.programlisting] .... OPTIONS_DEFINE= FOO BAR FOO_EXTRA_PATCHES= ${PATCHDIR}/extra-patch-foo BAR_EXTRA_PATCHES_OFF= ${PATCHDIR}/extra-patch-bar.c \ ${PATCHDIR}/extra-patch-bar.h .... ==== [[slow-patch-extra-ex-dirs]] .Usando `EXTRA_PATCHES` Com um Diretório [example] ==== As vezes, existem muitos patches que são necessários para um recurso, neste caso, é possível apontar `EXTRA_PATCHES` para um diretório, e ele aplicará automaticamente todos os arquivos nomeados como [.filename]#patch*# nele. Crie um subdiretório em [.filename]#${PATCHDIR}#, e mova os patches para ele. Por exemplo: [source,shell] .... % ls -l files/foo-patches -rw-r--r-- 1 root wheel 350 Jan 16 01:27 patch-Makefile.in -rw-r--r-- 1 root wheel 3084 Jan 18 15:37 patch-configure .... Então adicione isso ao [.filename]#Makefile#: [.programlisting] .... OPTIONS_DEFINE= FOO FOO_EXTRA_PATCHES= ${PATCHDIR}/foo-patches .... O framework irá então usar todos os arquivos nomeados [.filename]#patch*# nesse diretório. ==== [[slow-configure]] == Configurando Inclua quaisquer comandos de personalização adicionais no script [.filename]#configure# e salve-o no subdiretório [.filename]#scripts#. Como mencionado acima, também é possível fazer isso com targets no [.filename]#Makefile# e/ou scripts com o nome [.filename]#pre-configure# ou [.filename]#post-configure#. [[slow-user-input]] == Manipulando a Entrada do Usuário Se o port requer intervenção do usuário para build, configure ou install, defina `IS_INTERACTIVE` no [.filename]#Makefile#. Isso fará com que os "overnight builds" pulem ele. Se o usuário definir a variável `BATCH` em seu ambiente (e se o usuário definir a variável `INTERATIVE`, então _apenas_ aqueles ports que requerem interação serão compilados). Isso economizará muito tempo perdido no conjunto de máquinas que continuamente compilam ports (veja abaixo). Também é recomendado que, se houver respostas padrão razoáveis ​​para as perguntas, `PACKAGE_BUILDING` pode usado para desativar a intervenção do usuário quando o mesmo estiver definido. Isso nos permitirá compilar os pacotes para CDROMs e FTP.