7 Comentários

Introdução a cross-compiling com a Raspberry Pi

Devido à contínua evolução tecnológica e acessibilidade a hardware com cada vez mais "poder de fogo", os sistemas embarcados estão cada vez mais contando com sistemas operacionais completos. Destes, o Linux embarcado (e suas mais diversas distribuições) se destaca em popularidade e aceitação. Um dos grandes motivos para isso é a capacidade de rodar muito bem em hardwares baratos, com poucos recursos computacionais, o que implica em redução de custo de projeto final.

Dado este cenário, há uma situação delicada: devido à restrição de recursos computacionais, o desenvolvimento (principalmente a compilação) de projetos grandes nos próprios sistemas embarcados é inviável, ou até mesmo impossível. Neste caso, como é feito o desenvolvimento e compilação de projetos para estes sistemas? É exatamente isso que este artigo irá mostrar.

Primeiro, algumas definições

Antes de prosseguir com o artigo, é necessário deixar claro as seguintes definições:

  • Host: máquina que compilará um código-fonte/projeto;
  • Target: máquina (ou máquinas) que executará o projeto compilado pelo host.

Compilação de um projeto - modalidades

A compilação de qualquer código-fonte / projeto pode ser dividida em duas modalidades:

  1. Compilação nativa: é a modalidade de compilação onde o host é da mesma arquitetura (utiliza mesmo processador ou linha de processadores) do(s) target(s);
  2. Compilação cruzada (ou cross-compiling): nesta modalidade, o host não é da mesma arquitetura do(s) target(s).

Na modalidade de compilação nativa, intuitivamente nota-se que não há segredos. Como as arquiteturas do host e do(s) target(s) são iguais (ou, ao menos, compatíveis), o executável do projeto será gerado com código de máquina perfeitamente executável por qualquer uma das máquinas-alvo. No mundo "não embarcado" (não se tratando de sistemas embarcados) esta modalidade é, de longe, a mais comum. Um grande exemplo disso é o desenvolvimento de jogos para computador, os quais normalmente são compilados em computadores da mesma arquitetura. Já na modalidade de compilação cruzada, as arquiteturas do host e target(s) são distintas. Portanto, se for feita uma simples compilação de um projeto no host, o executável do projeto não funcionará no target.

E agora, como proceder para compilar algo para um target de arquitetura diferente do host?

Para isso, é adotada a técnica de cross-compiling (em português, compilação cruzada). Nesta técnica, no host é utilizado um conjunto de ferramentas especial para compilação chamado toolchain. Dessa forma, o host será capaz de gerar um executável do projeto compatível com a arquitetura do(s) target(s).

Pareceu complicado? Veja a seguinte analogia: imagine que você fala somente português e precisa se comunicar com uma pessoa que fala somente inglês. Naturalmente, se você falar somente em português, a outra pessoa não irá compreender uma só palavra. Mas, se você utilizar um dicionário português-inglês e traduzir suas frases para o inglês, a outra pessoa será capaz de entender o que você quis dizer, mesmo o inglês não sendo sua língua nativa.

Analisando com calma, constatamos duas coisas nesta situação:

  • Você (host) precisou de um dicionário português-inglês (toolchain) para falar (cross-compiling) com a pessoa que só fala inglês (target). Dessa forma, ela entendeu sua mensagem (executável do projeto, compilado para rodar no target);
  • O dicionário (toolchain) utilizado precisa ser da língua (arquitetura) da outra pessoa desta conversação (target). Portanto, ele precisa ser utilizável por você (host) e produzir como resultado frases (programa executável do projeto, compilado para rodar no target) que a outra pessoa (target) possa entender.

Portanto, em poucas palavras, um toolchain funciona como um dicionário. Este dicionário é capaz de "traduzir" a compilação de um host de forma que seja gerado um executável do projeto compatível com a arquitetura do(s) target(s). Em termos simples, o que foi explicado aqui é o processo de cross-compiling.

Exemplo prático de cross-compiling

Até agora foi dada uma noção de cross-compiling, sobretudo do que ele se trata e porque ele é necessário. Agora, será visto na prática um exemplo de cross-compiling, utilizando um computador (host, de arquitetura x86-64 bits) para compilar um programa simples em C para uma Raspberry Pi (target, de arquitetura ARM), modelo 3B ou Zero W. Segue abaixo mais informações do ambiente utilizado:

  • Ambiente do host: computador pessoal (arquitetura x86-64 bits), rodando como sistema operacional o Linux (distribuição: Ubuntu 16.04);
    Ambiente do target: Raspberry Pi (arquitetura ARM), rodando como sistema operacional o Linux (distribuição: Raspbian OS Jessie).

Primeiro passo: código-fonte

Primeiramente, precisamos de algo a ser compilado. Para isso, vamos utilizar um código-fonte muito simples: o bom e velho Hello World.

Segue abaixo o código-fonte. Salve-o como helloworld.c.

Segundo passo: obtenção do toolchain para cross-compilar para Raspberry Pi

Um toolchain pode ser obtido de duas maneiras:

  1. Fazer seu próprio toolchain (algo que pode ser realmente complicado dependendo do target, além de ser algo fora do escopo deste artigo);
  2. Utilizar um toolchain pronto (opção disponível na grande maioria das vezes, seja em repositórios-padrão ou site/SDK das plataformas de desenvolvimento).

Neste caso, vamos seguir na opção número 2. No caso da Raspberry Pi, os toolchains necessários estão disponíveis gratuitamente no repositório GitHub deste link. Portanto, primeiramente é preciso clonar o repositório. Para termos um norte neste artigo (padronizarmos os paths, sem criar confusões e facilitar seu entendimento), na sequência de comandos dada, será criado dentro do seu diretório home o diretório RaspPiCrossCompiling, e nele será clonado o repositório. Portanto, a sequência de comandos para isso fica assim:

O repositório é grande (pois contém muita coisa além do toolchain que usaremos), portanto o processo de clone do mesmo pode demorar alguns minutos.

Feito o clone do repositório, o próximo passo será adicionarmos à variável de ambiente PATH o caminho para o toolchain que usaremos. Isso fará com que a cada chamada do toolchain, o Linux procure na pasta em que ele está de fato (sem isso, teríamos que referenciar o path todo até o toolchain a cada processo de cross-compiling, o que deixaria os comandos de compilação desnecessariamente longos). Para isso, execute o comando abaixo:

Está feito! O toolchain agora está instalado. Para termos certeza que ele está sendo corretamente chamado, utilize o comando abaixo para verificar sua versão:

Este comando retorna informações gerais do toolchain, como pode ser visto abaixo:

Se este comando não retornar nenhum erro, significa que o toolchain está pronto para utilização. 

Terceiro passo: cross-compiling e análise do resultado do processo

É chegada a hora de cross-compilar o código-fonte. Para isso, utilize o seguinte comando:

Observe que a sintaxe é a mesma do GCC "padrão". A compilação deve acontecer sem problemas.

Agora vem a questão: como verificar que a compilação foi feita realmente para ARM? Felizmente, há uma maneira bem fácil de verificar isso, com um comando nativo do Linux, o comando file. Este comando tem como função informar o tipo de qualquer arquivo e, no caso de executáveis, informa inclusive a arquitetura para o qual foi compilado (ou seja, arquitetura do target).

A resposta a esse comando é a seguinte:

Logo, está claro que o executável está compilado para ARM. Para ter ainda mais certeza, tente rodá-lo na sua máquina (o host do cross-compiling, de arquitetura diferente do target). A execução falhará (erro mostrado abaixo), reforçando ainda mais que o processo de cross-compiling foi um sucesso.

Quarto passo: teste, na Raspberry Pi, do programa cross-compilado

Agora, basta passar o executável (código compilado) para a Raspberry Pi (via SSH, SFTP, enfim, da forma que desejar) e executar os comandos abaixo, os quais dão permissão de execução e executam o programa:

A execução ocorrerá sem problemas, produzindo a seguinte saída:

Cross-compiling na Raspberry Pi: saída do programa cross-compilado, rodando na Raspiberry Pi.
Figura 1 - Saída do programa cross-compilado, rodando na Raspberry Pi (target). Aqui, o acesso à Raspberry Pi foi feito via SSH

Portanto, o processo de cross-compiling foi feito com sucesso!

Conclusão

Neste artigo, foram abordados os conceitos básicos de cross-compiling, algo muito comum (e extremamente necessário) no desenvolvimento de sistemas embarcados em geral. Como exemplo prático, foi visto como se faz a obtenção e instalação de um toolchain para a Raspberry Pi (aplicável aos modelos 3B e Zero W), além do processo de cross-compiling em si.

Saiba mais sobre cross-compiling

GNU Cross-toolchain - Processo de build

Série "GNU ARM Cross-toolchain"

Referências

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Software » Introdução a cross-compiling com a Raspberry Pi
Comentários:
Notificações
Notificar
guest
7 Comentários
recentes
antigos mais votados
Inline Feedbacks
View all comments
Luan Dal Orto Vaz
08/07/2020 11:24

Bom dia, Gostaria de tirar uma dúvida.Eu li o seu artigo, e aprendi muito, mas eu quero compilar um programa do github pro raspberry, mas a pasta SRC (Source, código fonte), ela possui diversos arquivos com nomes e sufixos diferentes (.cpp, .s, .h),etc , então, eu usei o toolchain , mas gostaria de saber como juntar esses códigos para compilar, em um arquivo só? obrigado.

Gerson soares
Gerson soares
06/05/2020 16:37

Oi Pedro,sou gerson Curitiba,lê o artigo seu décima,esse método de crosscompile e para sem,mas para rodar esse exemplo no raspberry ele tem que estar com um sistema operacional instalado na rasp.com o raspibian para executar esse hello word? Acompanho o teu trabalho. Falei

Paulo andre Z Carvalho
Paulo
04/04/2020 14:36

Pelo que entendi você fez um cross compiler de linux para linux mudando o hardware destino ....como seria de windows 10 (Geanius) para raspberry pizero ?

Pedro Ferreira dos Santos Neto
Pedro Neto
23/02/2018 17:02

eu ainda tenho muitas duvidas com relação a isso. Por exemplo: Embarcados que "conversa" com o Host diretamente por rede ou um padrão de comunicação proprietário ou uma rede aberta. Exemplo CLPs, Drives de motores, Controladores de Processo Single Loop, etc. Todos estes carinhas comunicam só conectando porta/porta Host target sem que o usuário se quer saiba da existência de todo este processo. Exemplo: EU uso uma plataforma IBM-PC X86 windows para descarregar ou atualizar programas em CLPs, Inversores (drives) e Controladores Single Loop através de rede Modbus, Protocolo proprietário PPI, etc

Sandro Vieira
Sandro
15/01/2018 11:00

Isso poupa o tempo significativo, muito grato pelo artigo

Talvez você goste:

Séries

Menu

WEBINAR
 
Sensores e soluções para aplicações em indústria inteligente

Data: 13/08 às 15:00h - Apoio: STMicroelectronics
 
INSCREVA-SE AGORA »



 
close-link