Vimos um tempo atrás como gerar um Linux embarcado do zero com o Buildroot neste artigo aqui. Geramos o toolchain, a imagem do kernel e o rootfs. Mas compilamos apenas com os pacotes disponíveis por padrão no Buildroot. E se agora você quiser compilar uma aplicação ou um device driver e integrar na sua solução. Como podemos usar a infraestrutura gerada pelo Buildroot e cross-compilar qualquer código para ser executado na mini2440. Isso é o que veremos neste artigo.
Obs: Os termos cross-compiling, cross-compilar, cross-compilação e compilação cruzada tem o mesmo significado: compilar uma aplicação em uma arquitetura e gerar código para uma outra arquitetura. No nosso caso iremos compilar em um x86 e gerar código para um ARM.
Como pré-requisito, é necessário que você tenha executado todos os passos do artigo mencionado acima. Para realizar os testes, você pode configurar um ambiente com NFS, conforme expliquei neste artigo aqui.
Vamos utilizar o toolchain gerado pelo Buildroot. Você verá que o processo de compilação cruzada é bem simples, bastando apenas algumas alterações no Makefile do projeto.
COMPILANDO UMA APLICAÇÃO STANDALONE
Este é o código que iremos compilar para testar 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 fossemos compilar normalmente em nossa máquina, este seria o Makefile que utilizaríamos:
all:
@gcc hello.c -o hello
clean:
@rm -Rf *.o hello
Porém, iremos cross-compilar. Isso significa que iremos utilizar um compilador diferente, e o código compilado será linkado com uma biblioteca diferente. Este será o nosso Makefile para cross-compilar a aplicaçã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 variável TOOLCHAIN vai depender do local onde você instalou o Buildroot. No meu caso, instalei em “/opt/buildroot/buildroot-2010.08″. Ajuste de acordo com seu ambiente.
Veja que foram apenas 2 mudanças em relação ao Makefile anterior. Alteramos a variável de ambiente PATH para que o sistema encontre os binários do toolchain, e em vez de compilar com o “gcc”, estamos usando o “arm-linux-gcc”.
Os dois arquivos (hello.c e Makefile) devem estar no mesmo diretório. Para compilar, digite apenas “make”. Após a compilação, você pode conferir se o binário foi compilado para a arquitetura correta com o comando “file”:
$ file hello
hello: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
Para testar, copie o binário para o sistema de arquivos que você configurou com o NFS:
$ sudo cp hello /home/mini2440/rootfs/usr/bin/
Agora, entre na console da mini2440 e teste sua aplicação:
$ /usr/bin/hello
Hello mini2440!
COMPILANDO UM DEVICE DRIVER
Para compilar um device driver não é muito diferente ou mais complicado.
Este é um “esqueleto” de um driver simples que escrevi, apenas com as funções de inicialização e finalização, mas que serve para nosso propósito de compilar e testar 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 compilar, 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 variável KDIR deve apontar para o diretório do kernel que o Buildroot compilou para a mini2440. Ajuste-a de acordo com seu ambiente. O mesmo deve ser feito novamente com a variável TOOLCHAIN. Perceba que aqui não precisamos setar o compilador para “arm-linux-gcc”. Este Makefile é uma extensão do Makefile do kernel, e como o kernel já foi compilado para esta arquitetura, ele sabe qual toolchain (compilador) usar.
Novamente, os dois arquivos (leds.c e Makefile) devem estar no mesmo diretório, e para compilar, digite apenas “make”. O módulo gerado terá a extensão “.ko”. Você também pode conferir se o módulo foi compilado para a arquitetura correta 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 sistema de arquivos que você configurou 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 exemplos são bem simples, e o Makefile pode ficar bem complicado em projetos maiores. Mas os conceitos utilizados serão sempre os mesmos.
Um abraço,
Sergio Prado
VN:F [1.9.17_1161]
Rating: 10.0/10 (1 vote cast)
Mini2440 — Compilando aplicações e device drivers, 10.0 out of 10 based on 1 rating Posts relacionados:
- Linux Device Drivers — Parte 1
- Mini2440 — Linux from scratch com Buildroot
- Mini2440 — Montando rootfs no Linux via NFS