Tool­chain e cross-compiling tool­chain são nomes que podem con­fundir e até assus­tar algu­mas pes­soas. Já vi gente con­fundindo tool­chain com buildsys­tem e com­pi­lador. Os con­ceitos estão rela­ciona­dos, mas não são a mesma coisa. É por isso que resolvi escr­ever este artigo.

TOOLCHAIN?

Ao pé da letra, e traduzindo lit­eral­mente, tool­chain é uma “cor­rente de fer­ra­men­tas”. Na prática, é um con­junto de fer­ra­men­tas de com­pi­lação.

Você se lem­bra do processo de com­pi­lação de um código em C?

É mais ou menos assim:

  1. Pré-processador: trata todas as dire­ti­vas de pré-processamento e gera um código C intermediário.
  2. Com­pi­lador: con­verte este código C inter­mediário em um código-fonte assembly.
  3. Assem­bler: con­verte o código-fonte assem­bly em arquivo objeto.
  4. Linker: Con­verte um ou mais arquivos objeto no binário final (firmware, apli­cação, etc).

Cada uma destas eta­pas é exe­cu­tada por uma fer­ra­menta, todas elas fazendo parte do tool­chain. Perceba como as fer­ra­men­tas estão interli­gadas e são exe­cu­tadas uma após a outra. Enten­deu agora o porque do “chain” no nome?

TIPOS DE TOOLCHAIN

Exis­tem basi­ca­mente dois tipos de tool­chain:

  1. Native tool­chain
  2. Cross-compiling tool­chain

O con­ceito é sim­ples. Dá uma olhada na imagem abaixo:

toolchain types Desmistificando toolchains em Linux embarcado

Fonte: free-electrons.com

O bloco de cima é sua máquina de desen­volvi­mento e o bloco de baixo é a arquitetura-alvo (hard­ware, kit de desen­volvi­mento, etc). As cores rep­re­sen­tam a arquite­tura: azul para x86 e laranja para ARM.

Por­tanto, você irá usar um native tool­chain quando quiser com­pi­lar uma apli­cação para a mesma arquite­tura da sua máquina de desen­volvi­mento. Na prática, esta apli­cação irá rodar na sua máquina de desen­volvi­mento (x86 no nosso exem­plo).

Já um cross-compiling tool­chain vai gerar um binário para uma arquite­tura difer­ente da sua máquina de desen­volvi­mento. No exem­plo acima, a máquina de desen­volvi­mento é x86 e a arquitetura-alvo é ARM.

PORQUE USAR UM CROSS-COMPILING TOOLCHAIN?

Por que não usamos um native tool­chain para desen­volver em Linux embar­cado? Sim­ples­mente porque na grande maio­ria dos casos não dá.

Para isso, pre­cis­aríamos colo­car todo o nosso tool­chain den­tro do dis­pos­i­tivo. Um tool­chain ocupa bas­tante espaço, de 50MB a 100MB. E se a sua memória flash tiver só 64M? Um tool­chain pre­cisa tam­bém de capaci­dade de proces­sa­mento. Já pen­sou com­pi­lar o ker­nel den­tro do seu kit de desen­volvi­mento? Iríamos tomar muito mais café neste caso! :)

É por isso que pre­cisamos de um cross-compiling tool­chain para desen­volvi­mento em Linux embar­cado.

MISTURANDO NOMES

Use o nome que achar mais bonito: native tool­chain ou tool­chain nativo, cross-compiling tool­chain, tool­chain de cross-compilação ou tool­chain de compilação-cruzada.

A par­tir de agora, e visando a lei do menor esforço :=), usarei ape­nas tool­chain quando quiser expres­sar cross-compiling tool­chain, ou serei mais explíc­ito quando necessário.

OS COMPONENTES DO TOOLCHAIN

Um tool­chain para desen­volvi­mento em Linux (embar­cado ou não) pos­sui 5 com­po­nentes prin­ci­pais:

1. Com­pi­lador GCC

O famoso com­pi­lador GNU C, com­patível tam­bém com diver­sas out­ras lin­gua­gens como C++ e Java, e capaz de gerar código para diver­sas arquite­turas incluindo ARM, AVR, Black­fin, MIPS, Pow­erPC e x86.

2. Binu­tils

Um con­junto de fer­ra­men­tas para manip­u­lar binários para arquite­turas especí­fi­cas. Por exem­plo, pos­sui o “as” para ler um código-fonte assem­bly e gerar um arquivo-objeto e o “ld” para linkar um ou mais arquivos-objeto em um exe­cutável.

3. Bib­lioteca C padrão

A prin­ci­pal função da bib­lioteca C padrão é fazer a inter­face com o ker­nel através de chamadas do sis­tema (Sys­tem Calls).

Sabe quando você usa as funções open() ou write() no código C? A imple­men­tação desta função esta na bib­lioteca C, que gera uma chamada de sis­tema para o ker­nel. 

E quando você tenta com­pi­lar este código, o tool­chain irá linkar o código da bib­lioteca com o código da sua apli­cação (esta­ti­ca­mente ou dinami­ca­mente). Por este motivo, o tool­chain con­tém a bib­lioteca C padrão com­pi­lada para sua arquitetura-alvo.

E é por este mesmo motivo que, em Linux embar­cado, nem toda apli­cação com­pi­lada para ARM e linkada dinami­ca­mente vai rodar em qual­quer dis­pos­i­tivo ARM. Neste caso, a bib­lioteca C padrão do dis­pos­i­tivo pre­cisa ser a mesma do tool­chain. Se você quiser que a apli­cação rode em qual­quer dis­pos­i­tivo ARM com­patível, com­pile esta­ti­ca­mente.

Em Linux, exis­tem diver­sas imple­men­tações de bib­lioteca C, den­tre elas a glibc (padrão em sis­temas desk­top) e a uClibc (padrão em Linux embar­cado). Ape­sar de apre­sentarem a mesma inter­face (API) com as apli­cações, a uClibc é otimizada para gerar um código menor e a glibc é otimizada para ter mel­hor performance:

glibc uclibc Desmistificando toolchains em Linux embarcado

Fonte: free-electrons.com

Veja que um sim­ples printf() com­pi­lado esta­ti­ca­mente com a glibc gerou um código de 472K, enquanto que na uClibc o código ficou com ape­nas 18K!

4. Ker­nel Headers

Vimos que um tool­chain con­tém (com­pi­lada) a bib­lioteca C padrão do sis­tema. Isso sig­nifica que, quando o tool­chain é ger­ado, ele pre­cisa com­pi­lar a bib­lioteca e transformá-la em arquivo-objeto (*.so ou *.a) para poder ser usada (linkada) pelas aplicações.

Mas para com­pi­lar a bib­lioteca C padrão, existe uma dependên­cia adi­cional: os head­ers do ker­nel! Por quê?

kernel headers Desmistificando toolchains em Linux embarcado

A bib­lioteca C padrão con­versa com o ker­nel através de chamadas de sis­tema. Mas como a bib­lioteca C sabe quais são as chamadas de sis­tema disponíveis? Estão nos head­ers do kernel!

Definição das chamadas de sis­tema para uma arquite­tura ARM den­tro dos fontes do ker­nel, em “arch/arm/include/asm/unistd.h”:

1
2
3
4
5
6
7
8
9
10
...
#define __NR_SYSCALL_BASE       0
 
#define __NR_exit               (__NR_SYSCALL_BASE+  1)
#define __NR_fork               (__NR_SYSCALL_BASE+  2)
#define __NR_read               (__NR_SYSCALL_BASE+  3)
#define __NR_write              (__NR_SYSCALL_BASE+  4)
#define __NR_open               (__NR_SYSCALL_BASE+  5)
#define __NR_close              (__NR_SYSCALL_BASE+  6)
...

Além disso, a bib­lioteca C padrão pre­cisa ter acesso às con­stantes e estru­turas de dados do ker­nel. Exemplos:

1
2
3
4
/* em linux/fcntl.h */
...
#define O_RDWR          00000002
...
1
2
3
4
5
6
/* em asm/stat.h */
...
struct stat {
        unsigned long  st_dev;
        unsigned long  st_ino;
...

Por­tanto, e por estes motivos, a bib­lioteca C depende dos head­ers do ker­nel. Isso sig­nifica que um tool­chain depende tam­bém da ver­são do ker­nel do Linux. 

Neste caso, se você usar um tool­chain com os head­ers do ker­nel 2.6.32, terá prob­le­mas para gerar uma apli­cação para ser exe­cu­tada no ker­nel 2.6.33? Não nec­es­sari­a­mente! Em 99,9999% dos casos, irá fun­cionar nor­mal­mente. Isso porque os desen­volve­dores do ker­nel são bem con­ser­vadores. As chamadas do sis­tema nunca são mod­i­fi­cadas. Pode-se incluir alguma nova chamada, mas as exis­tentes con­tin­uam sem­pre as mes­mas. Isso garante com­pat­i­bil­i­dade de apli­cações e bib­liote­cas com difer­entes ver­sões do ker­nel do Linux.

5. GDB

O GDB é o debug­ger padrão em sis­temas Linux. Como ele tam­bém depende das bib­liote­cas do sis­tema, faz parte do tool­chain. Mas como não pre­cisamos dele para com­pi­lar as apli­cações, é ape­nas um ele­mento opcional.

NA PRÁTICA

Na prática, um tool­chain nativo é com­posto pelas fer­ra­men­tas de com­pi­lação que usamos na máquina de desen­volvi­mento, como o gcc, as, ld, strip e gdb.

Já um cross-compiling tool­chain acres­centa nor­mal­mente um pre­fixo ao nome destas fer­ra­men­tas para indicar a arquite­tura e out­ras infor­mações adi­cionais. Por exem­plo, o com­pi­lador gcc de um tool­chain para sis­temas Linux de arquite­tura ARM pode se chamar “arm-linux-gcc”. Veja a listagem com­pleta do diretório de fer­ra­men­tas de um tool­chain para ARM:

$ ls
arm-linux-addr2line  arm-linux-c++      arm-linux-cpp      arm-linux-gcc        arm-linux-gcov   arm-linux-ld.bfd    arm-linux-nm       arm-linux-ranlib   arm-linux-strings
arm-linux-ar         arm-linux-cc       arm-linux-elfedit  arm-linux-gcc-4.3.5  arm-linux-gprof  arm-linux-ldconfig  arm-linux-objcopy  arm-linux-readelf  arm-linux-strip
arm-linux-as         arm-linux-c++filt  arm-linux-g++      arm-linux-gccbug     arm-linux-ld     arm-linux-ldd       arm-linux-objdump  arm-linux-size

É isso aí. Espero ter desmisti­fi­cado um pouco o con­ceito de tool­chain para Linux embarcado.

No próx­imo artigo, ire­mos apren­der a gerar nosso próprio tool­chain e usá-lo para cross-compilar qual­quer apli­cação para Linux embarcado.

Até lá!

Um abraço,

Ser­gio Prado

VN:F [1.9.17_1161]
Rat­ing: 9.2/10 (13 votes cast)
Desmisti­f­i­cando tool­chains em Linux embar­cado, 9.2 out of 10 based on 13 ratings

Sem posts relacionados.

Tags:  
  • http://marcelojoeng.blogspot.com Marcelo

      Mais um exce­lent post! Obri­gado por com­par­til­har Sérgio!

      Abraços e sucesso!

      Marcelo Jo

    VA:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)
  • Alberto Fabi­ano

    Da série, não con­funda “con­haque de alca­trão” com “catraca de can­hão”, este foi um artigo sim­ples e direto.
    Mae­stro, uma nota: “sensacional”! :-)

    VA:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)
  • Mar­cos de Lima Carlos

    Poxa… tá aí uma coisa que eu nunca tinha visto alguém falar de forma tão clara! Show! Parabéns.

    VA:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)
  • Klaus da Cruz

    Um exe­ce­lente Post Ser­gio.… Está de uma forma bem clara a pas­sagem da infor­mação..
    Congratularions..

    VA:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)
  • http://mesa-reprap.blogspot.com/ Alain Mou­ette

    Boa expli­cação, mas para SW embar­cado pre­cisa em geral tam­bém do método de gravação. Em geral JTAG + soft­ware ade­quado. Já que a expli­cação é boa, vale a pena acres­cen­tar isso :)

    VA:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)
  • José Antônio

    Olá Sér­gio!
    Ótimo artigo, mas acho que ficaria mel­hor se incluísse o que
    seria o buildsys­tem e o porquê de tanta gente con­fundir este
    termo com tool­chain.
     
    Atenciosamente,

    VA:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)
    • http://www.sergioprado.org Ser­gio Prado

      Boa obser­vação José!

      Um buildsys­tem (ou sis­tema de build) é uma fer­ra­menta para gerar uma dis­tribuição Linux com­pleta, que além de ser capaz de gerar o tool­chain, tam­bém é capaz de gerar o boot­loader, o ker­nel e o sis­tema de arquivos! Ou seja, o tool­chain é ape­nas um dos com­po­nentes do buildsystem.

      Um abraço!

      VA:F [1.9.17_1161]
      Rating: 0.0/5 (0 votes cast)
  • Leo

    Voce explica de forma muito clara, parabens pelo artigo.
    Gostaria de deixar a sug­es­tao que seja feito um artigo para quem quer se aven­tu­rar em por­tar dis­pos­i­tivos winCe para android, assim como faz o pes­soal da xda-developers.

    VA:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)
    • http://www.sergioprado.org Ser­gio Prado

      Obri­gado Leandro!

      Sug­estão anotada.

      Um abraço.

      VA:F [1.9.17_1161]
      Rating: 0.0/5 (0 votes cast)
  • Lean­dro Martins

    Sér­gio,  Muito obri­gado pela sua con­tribuição.
    Sua lin­guagem clara e obje­tiva, de quem tem inter­esse em ensi­nar e paixão pela coisa deixa tudo mais facil de ser enten­dido.
    Estou me divertindo bas­tante.
    Porém, estou esperando um artigo que vc disse que seria o próx­imo. :-(
    No próx­imo artigo, vou falar sobre como cross-compilar qual­quer apli­cação open source para o Android. Você poderá inclu­sive tes­tar esta apli­cação cross-compilada no seu smart­phone, se tiver acesso de root. Até lá!
    Um abraço,
    Ser­gio Prado
    Abraços e parabéns pelo trabalho.

    VA:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)
    • http://www.sergioprado.org Ser­gio Prado

      Opa Lean­dro!

      Não esqueci deste artigo não! :)

      Quando come­cei a escrevê-lo, percebi que seria legal ter um artigo sobre tool­chains antes de falar sobre como cross-compilar para o Android. Mas ele deve sair em breve!

      Um abraço.

      VA:F [1.9.17_1161]
      Rating: 0.0/5 (0 votes cast)
  • Thi­ago

    exce­lente e muito esclare­ce­dor artigo. parabens.

    VA:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)
  • william gueiros

    parabens pelo post muito profis­sional…
    e aprendi bas­tante com o mesmo

    VA:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)
  • Per­domo

    Olá Ser­gio. Estou estu­dando o fun­ciona­mento do Open­Wrt para meu pro­jeto final de curso e seu artigo foi muito útil para meu apren­dizado.
    Obrigado.

    VA:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)
  • Rafael

    Muito bom post. Como sem­pre, escrito de forma clara e obje­tiva. Estou começando agora a estu­dar Linux embar­cado e seguida­mente con­sulto o blog.
    Parabéns e muito obrigado!

    VA:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)
  • http://t4v4res@wordpress.com Luis Anto­nio Tavares

    Olá Sér­gio,
    Parabéns pelo post.. No tra­balho o pes­soal cos­tu­mava chamar de tool­chain todo o buildsys­tem, seu post esclare­ceu muitos pon­tos.
    Gostaria de saber se você me indica algum con­teúdo sobre  ramdisk. Pre­ciso gerar um ramdisk para o mini2440 e não sei qual o mel­hor cam­inho.
    Mais uma vez, parabéns!

    VA:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)
  • Leonardo

    Ser­gio,
       Parabéns pelo Otimo Artigo.

    VA:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)
  • Felipe

    Cara per­feito o teu post!!! Muito Obrigado!

    VA:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)