Raspberry

Como transportar um programa para outro sistema

Selecionar modo de boot por GPIO Raspberry 3BT| ext to speech com Raspberry | Gerar binário a partir do script Python | resolvendo nomes | iniciar programa no boot | Multithread no Raspberry | Compilar programas escritos em Python

Talvez o termo “transportar um programa” não seja o mais adequado, mas explico.

Quando estamos desenvolvendo um programa, diversas dependências podem surgir durante o desenvolvimento. Nesse caso, as vamos suprindo conforme surgem, através do gerenciador de pacotes apt. Claro que nem sempre as dependências estão disponíveis via repositório, mas isso é a exceção.

Durante o desenvolvimento, sempre anotamos as dependências que surgem para poder reproduzir o processo quando necessário for. Um backup do sistema acaba sendo também uma opção em embarcados, ainda mais se for feita a redução do sistema de backup, como feito nesse artigo, por exemplo. O único problema desse processo é que para backup do ambiente de desenvolvimento ele é perfeito, mas para distribuir um sistema em um produto não é desejável que todo um ambiente de compilação esteja junto, seja por questões estratégicas ou por causa do tamanho final do sistema. Para isso, há uma forma bastante simples de montar um pacote que permita transportar o programa compilado de um sistema para outro, sem a necessidade de instalar programas extras.

Montar uma estrutura do programa

Essa técnica funciona muito bem, utilizo desde o início dos anos 2000 e utilizei muito em meu saudoso sistema de clonagem, o Phantom (ou Phantom System, ou Phantom Clone). Em servidores, consegui montar um sistema com suporte à controladora da época, que não funcionava no Debian, mas levei as dependências do Ubuntu. Ou seja, é uma solução que pode “salvar vidas”.

O programa que vou usar como exemplo tem poucas dependências, é o que criei para o AFMultiRadio da AFEletronica. Já será o suficiente para provar o conceito.

Crie o diretório que receberá o programa

Esse é o primeiro passo. Tudo deve ficar dentro de um diretório, mas com a devida estrutura de sistema. Todo o processo deve ser feito por terminal, uma vez que utilizaremos recursos do shell para recolher as dependências. faça:

Não preciso dizer para trocar o nome do diretório para o nome que desejar, certo?

Em seguida entre nele. No sistema em que instalei, o binário já está  no path do sistema. O path é uma variável de ambiente contendo a indicação dos diretório de arquivos binários, para quando um comando for executado, o sistema procurar por ele. Você pode visualizar os diretórios contidos no path usando (por exemplo) o comando:

Que deverá retornar algo com o formato similar a:

path - transportar um programa

Se desejar adicionar um diretório ao path, também é possível. Suponhamos que tenha um diretório no home do usuário pi, para arquivos binários, /home/pi/bin:

Isso exportará o diretório desejado apenas na seção de terminal aberta e também só será válida até que esse terminal seja fechado. Se quiser fazer a mudança permanente, uma das maneiras de fazê-lo é através do arquivo oculto .profile. Mas não é necessário fazê-lo para o diretório bin no home do usuário, caso esteja utilizando Raspbian, porque por padrão esse arquivo já procura pela existência do diretório e adiciona-o automaticamente ao path:

.profile

Em caso de utilizar outro sistema que não tenha o recurso, pode-se fazer como no exemplo acima.

Recolhendo as dependências

Agora, acesse o diretório. O primeiro passo é recolher o binário com seu caminho absoluto, para que no sistema em que for “instalado”, fique idêntico ao sistema de origem.

Isso trará o binário com toda sua estrutura para dentro do diretório atual. Perceba que o processo está sendo feito já dentro do diretório previamente criado. É a forma mais segura de copiar tudo para o lugar certo. Mostro a estrutura a seguir, mas fiz no diretório /tmp/AFmultiRadio. Assim quando o sistema for reiniciado, tudo o que estiver lá em /tmp será excluído e não preciso me preocupar em dar manutenção no sistema depois do artigo.

Do bit Ao Byte - cp --parents

Agora precisamos recolher as dependências do binário. Para isso, utilizamos o comando ldd para identificar quais são elas:

ldd - transportar um programa

Nesse exemplo, preciso recolher a libsqlite3.so.0, entre as demais. As linhas que identificam as dependências tem o sinal =>, apontando para onde as dependências estão.

Alguns programa possuem montes de dependências. Copiá-las uma a uma é uma péssima ideia, consumirá tempo e depois, mais tempo, como será visto mais adiante. Portanto, a melhor maneira de fazer a cópia das dependências é através de um comando personalizado no shell:

Recolhendo a dependência das dependências

Não é algo que se possa chamar de “recursivo”, mas em alguns casos pode ser necessário fazê-lo mais de uma vez. O interessante é fazer apenas uma vez esse processo e então testar em um sistema “virgem”. Se der mais dependências, repita o processo no sistema de origem.

Compactar a estrutura e transportar um programa

Agora basta compactar a estrutura, copiar e descomprimir no destino. Dá pra comprimir só os diretório internos, mas não gosto de fazer assim porque é comum o usuário descomprimir primeiro para depois ver o resultado e descomprimir os diretórios da estrutura pode bagunçar o diretório de destino da compressão.

Isso resultará no arquivo AFMultiRadio.txz, que deverá ser copiado para o destino. Daí faz-se a descompressão, entra-se no diretório e copia-se o conteúdo para a raiz:

Pronto, programa no destino!

Ao executar o programa reclama de dependência. E agora?

Uma das causas pode ser relacionado à carga de bibliotecas. O primeiro passo é verificar se o diretório de bibliotecas do seu programa é comum ao sistema. Se não for, adicione-o ao arquivo /etc/ld.so.conf e depois carregue-o com:

Ainda reclamando da dependência. E agora?

Verifique se faltou alguma dependência de dependência com o comando ldd, como mostrado acima. Se houver o sinal => sem o destino, então faltou copiar essa dependência da origem.

Mas não se preocupe muito com isso, essa falha raramente deve ocorrer! E essa é uma maneira de transportar um programa para outro sistema. Simples ou não?