Vimos um tempo atrás como gerar um Linux embar­cado do zero com o Buil­d­root neste artigo aqui. Ger­amos o tool­chain, a imagem do ker­nel e o rootfs. Mas com­pil­amos ape­nas com os pacotes disponíveis por padrão no Buil­d­root. E se agora você quiser com­pi­lar uma apli­cação ou um device dri­ver e inte­grar na sua solução. Como podemos usar a infraestru­tura ger­ada pelo Buil­d­root e cross-compilar qual­quer código para ser exe­cu­tado na mini2440. Isso é o que ver­e­mos neste artigo.

Obs: Os ter­mos cross-compiling, cross-compilar, cross-compilação e com­pi­lação cruzada tem o mesmo sig­nifi­cado: com­pi­lar uma apli­cação em uma arquite­tura e gerar código para uma outra arquite­tura. No nosso caso ire­mos com­pi­lar em um x86 e gerar código para um ARM.

Como pré-requisito, é necessário que você tenha exe­cu­tado todos os pas­sos do artigo men­cionado acima. Para realizar os testes, você pode con­fig­u­rar um ambi­ente com NFS, con­forme expliquei neste artigo aqui.

Vamos uti­lizar o tool­chain ger­ado pelo Buil­d­root. Você verá que o processo de com­pi­lação cruzada é bem sim­ples, bas­tando ape­nas algu­mas alter­ações no Make­file do pro­jeto.

COMPILANDO UMA APLICAÇÃO STANDALONE

Este é o código que ire­mos com­pi­lar para tes­tar na mini2440:

1
2
3
4
5
6
7
8
9
10
/* hello.c */
 
#include "stdio.h"
 
int main()
{
    printf("Hello mini2440!\n");
 
    return 0;
}

Se fos­se­mos com­pi­lar nor­mal­mente em nossa máquina, este seria o Make­file que utilizaríamos:

all:
	@gcc hello.c -o hello
 
clean:
	@rm -Rf *.o hello

Porém, ire­mos cross-compilar. Isso sig­nifica que ire­mos uti­lizar um com­pi­lador difer­ente, e o código com­pi­lado será linkado com uma bib­lioteca difer­ente. Este será o nosso Make­file para cross-compilar a apli­cação:

TOOLCHAIN=/opt/buildroot/buildroot-2010.08/output/staging/usr/bin/
CROSS_COMPILE=arm-linux-
 
PATH := ${TOOLCHAIN}:${PATH}
 
all:
	@${CROSS_COMPILE}gcc hello.c -o hello
 
clean:
	@rm -Rf *.o hello

A var­iável TOOLCHAIN vai depen­der do local onde você instalou o Buil­d­root. No meu caso, instalei em “/opt/buildroot/buildroot-2010.08″. Ajuste de acordo com seu ambiente.

Veja que foram ape­nas 2 mudanças em relação ao Make­file ante­rior. Alter­amos a var­iável de ambi­ente PATH para que o sis­tema encon­tre os binários do tool­chain, e em vez de com­pi­lar com o “gcc”, esta­mos usando o “arm-linux-gcc”.

Os dois arquivos (hello.c e Make­file) devem estar no mesmo diretório. Para com­pi­lar, dig­ite ape­nas “make”. Após a com­pi­lação, você pode con­ferir se o binário foi com­pi­lado para a arquite­tura cor­reta com o comando “file”:

$ file hello
hello: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped

Para tes­tar, copie o binário para o sis­tema de arquivos que você con­fig­urou com o NFS:

$ sudo cp hello /home/mini2440/rootfs/usr/bin/

Agora, entre na con­sole da mini2440 e teste sua aplicação:

$ /usr/bin/hello
Hello mini2440!

COMPILANDO UM DEVICE DRIVER

Para com­pi­lar um device dri­ver não é muito difer­ente ou mais com­pli­cado.

Este é um “esqueleto” de um dri­ver sim­ples que escrevi, ape­nas com as funções de ini­cial­iza­ção e final­iza­ção, mas que serve para nosso propósito de com­pi­lar e tes­tar na mini2440:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
/* file leds.c */
 
#include "linux/fs.h"
#include "linux/cdev.h"
#include "linux/module.h"
#include "linux/kernel.h"
#include "linux/device.h"
#include "asm/uaccess.h"
#include "linux/slab.h"
 
#define DEVICE_NAME     "leds"
 
#define NUM_LEDS        1
 
int __init leds_init(void);
void __exit leds_exit(void);
 
/* per led structure */
struct leds_device {
    int status;
    struct cdev cdev;
} leds_dev[NUM_LEDS];
 
/* file operations structure */
static struct file_operations leds_fops = {
    .owner      = THIS_MODULE,
};
 
static dev_t leds_dev_number;
 
/* driver initialization */
int __init leds_init(void)
{
    int ret, i;
 
    /* request device major number */
    if ((ret = alloc_chrdev_region(&leds_dev_number, 0, NUM_LEDS, DEVICE_NAME) < 0)) {
        printk(KERN_DEBUG "Error registering device!\n");
        return ret;
    }
 
    /* init each led device */
    for (i = 0; i < NUM_LEDS; i++) {
 
        /* init led status */
        leds_dev[i].status = 0;
 
        /* connect file operations to this device */
        cdev_init(&leds_dev[i].cdev, &leds_fops);
        leds_dev[i].cdev.owner = THIS_MODULE;
 
        /* connect major/minor numbers */
        if ((ret = cdev_add(&leds_dev[i].cdev, (leds_dev_number + i), 1))) {
            printk(KERN_DEBUG "Error adding device!\n");
            return ret;
        }
 
    }
 
    printk("Initializing leds driver.\n");
 
    return 0;
}
 
/* driver exit */
void __exit leds_exit(void)
{
    /* release major number */
    unregister_chrdev_region(leds_dev_number, NUM_LEDS);
 
    printk("Exiting leds driver.\n");
}
 
module_init(leds_init);
module_exit(leds_exit);
 
MODULE_LICENSE("GPL");

Para com­pi­lar, este é o Makefile:

TOOLCHAIN := /opt/buildroot/buildroot-2010.08/output/staging/usr/bin/
KDIR := /opt/buildroot/buildroot-2010.08/output/build/linux-2.6/
PWD  := $(shell pwd)
PATH := $(TOOLCHAIN):${PATH}
 
obj-m += leds.o
 
default:
	$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
 
clean:
	@rm -Rf *.o *.ko *.mod.c modules.order Module.symvers

A var­iável KDIR deve apon­tar para o diretório do ker­nel que o Buil­d­root com­pi­lou para a mini2440. Ajuste-a de acordo com seu ambi­ente. O mesmo deve ser feito nova­mente com a var­iável TOOLCHAIN. Perceba que aqui não pre­cisamos setar o com­pi­lador para “arm-linux-gcc”. Este Make­file é uma exten­são do Make­file do ker­nel, e como o ker­nel já foi com­pi­lado para esta arquite­tura, ele sabe qual tool­chain (com­pi­lador) usar.

Nova­mente, os dois arquivos (leds.c e Make­file) devem estar no mesmo diretório, e para com­pi­lar, dig­ite ape­nas “make”. O módulo ger­ado terá a exten­são “.ko”. Você tam­bém pode con­ferir se o módulo foi com­pi­lado para a arquite­tura cor­reta com o comando “file”:

$ file leds.ko
leds.ko: ELF 32-bit LSB relocatable, ARM, version 1 (SYSV), not stripped

Agora, copie o binário para o sis­tema de arquivos que você con­fig­urou com o NFS:

$ sudo cp leds.ko /home/mini2440/rootfs/usr/bin/

E teste inserindo e removendo o driver:

$ insmod /usr/bin/leds.ko
Initializing leds driver.
 
$ rmmod leds
Exiting leds driver.

Claro que estes exem­p­los são bem sim­ples, e o Make­file pode ficar bem com­pli­cado em pro­je­tos maiores. Mas os con­ceitos uti­liza­dos serão sem­pre os mesmos.

Um abraço,

Ser­gio Prado

VN:F [1.9.17_1161]
Rat­ing: 10.0/10 (1 vote cast)
Mini2440 — Com­pi­lando apli­cações e device dri­vers, 10.0 out of 10 based on 1 rating

Posts rela­ciona­dos:

  1. Linux Device Dri­vers — Parte 1
  2. Mini2440 — Linux from scratch com Buildroot
  3. Mini2440 — Mon­tando rootfs no Linux via NFS
  • juliano

    Muito bom Ser­gio,
    Parabéns por mais um artigo muito esclarecedor,e aprovei­tando já pra te dese­jar um feliz ano novo que vc con­tinue com essa von­tade de aju­dar o pes­soal menos expe­ri­ente da area .
    Deus te abençoe 
    Abraços

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

    Fala Ser­gio,
    mas uma vez agradeco a boa von­tade de aju­dar com mais este artigo.
    tenho uma per­gunta:
    tem como enviar o bina­rio de outro modo sem ser pela NFS?
    abraco

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

    Olá Thi­ago,

    Tem sim. Você pode com­pi­lar o busy­box com suporte a ftp, ou então cross-compilar o drop­bear e usar o pro­to­colo ssh, por exemplo.

    Um abraço!

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

    Olá Ser­gio,
     
    Muito bom este artigo, obri­gado! Gostaria de saber se você pode­ria postar um artigo sobre como criar e con­fig­u­rar um ambi­ente para com­pi­lação cruzada de apli­cações baseadas em Qt para a mini2440. Tenho o Qt Cre­ator insta­l­ado e o SDK para plataforma PC mas não encon­tro mate­r­ial claro que informe como insta­lar um SDK para linux embed­ded.
     
    Mais uma vez agradeço e parabéns.
     

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

      Olá Renato!

      Sug­estão anotada!

      Um abraço!

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

    Ola,
     
    Gostaria de saber como faço para com­pi­lar pelo arm-linux-gcc, ja que este é o unico q temos aqui
    Desde ja agradeço

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

      Olá Bruna,

      O pro­ced­i­mento é o mesmo. Ape­nas altere a var­iável TOOLCHAIN para apon­tar para o diretório onde se encon­tra o “arm-linux-gcc”.

      Um abraço!

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

    Ola Ser­gio, exce­lente artigo, parabens. Segui seu passo a passo e o hel­loworld fun­cio­nou per­feita­mente no linux enx­uto ger­ado no buid­root. Porem o mesmo arquivo exe­cu­tavel, o qual nomeei de arm_helloword, não fun­cio­nou no Linux pre-carregado(Qtopia) que ja vem na placa, apare­cendo a seguinte men­sagem:
    [root@FriendlyARM arm_helloword]# ./arm_helloword
    -/bin/sh: ./arm_helloword: not found
    Como faço pra exe­cu­tar este pro­grama no Linux pre-carregado(Qtopia)?
    obri­gado pelas ajudas

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

      Olá Thi­ago,

      Dev­e­ria exe­cu­tar sem prob­le­mas na con­sole. Pela men­sagem de erro, é bem provável que você esteja copiando para o lugar errado. Tente lis­tar o arquivo antes, e ver­i­ficar onde você o copiou.

      Um abraço!

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

    Olá Ser­gio,
    não sei bem se entendi o que vc quis dizer sobre lis­tar o arquivo antes. Eu colo­quei o arquivo exe­cu­tavel em um pen­drive e conectei o pen­drive na placa. o con­teúdo do pen­drive  auto­mati­ca­mente pro dire­to­rio udisk. ten­tei copiar o arquivo para um outro dire­to­rio qual­quer e exe­cu­tar de lá, porem a men­sagem de erro con­tinua sendo a mesma.
    Des­culpe pelo inco­modo mas se puder me da uma dica seria ótimo, até mesmo pq acred­ito estar muito próx­imo de con­seguir.
    abraço   

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

      Olá Thi­ago,

      A provável causa deste prob­lema é você nao estar exe­cu­tando a apli­cação do diretório onde a salvou.

      Um abraço.

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

    Mas eu vou na pasta onde está a apli­cação e executo de lá mesmo e a men­sagem de erro con­tinua.
    Abraço

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

    Olá,
     
    esse erro é con­sis­tente com fal­has nas per­mis­sões definidas ou até de com­pi­lação mal feita da apli­cação.
    Há algum tempo que tra­balho com a Mini2440 e já tra­bal­hei com a NGW100 e esse prob­lema sem­pre me acon­te­ceu por esses dois motivos.
     
    Com os mel­hores cumpri­men­tos,
    Luís Silva

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

    Olá Rafael,

    Estranho ele não estar emitindo nen­hum erro, como se não estivesse real­mente com­pi­lando. Me manda o seu Makefile.

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