如何把powerpc处理器-e300c3-linux-gnu写在环境变量中

Linux内核空间到用户空间的共享内存映射
当内核空间和用户空间存在大量数据交互时, 共享内存映射就成了这种情况下的不二选择; 它能够最大限度的降低内核空间和用户空间之间的数据拷贝, 从而大大提高系统的性能.
以下是创建从内核空间到用户空间的共享内存映射的模板代码(在内核2.6.18和2.6.32上测试通过):
1.内核空间分配内存:
#include &linux/types.h&
#include &linux/mm.h&
#include &linux/vmalloc.h&
int mmap_alloc(int require_buf_size)
& struct page *
& mmap_size = PAGE_ALIGN(require_buf_size);
#if USE_KMALLOC //for kmalloc
& mmap_buf = kzalloc(mmap_size, GFP_KERNEL);
& if (!mmap_buf) {
&&& return -1;
& for (page = virt_to_page(mmap_buf ); page & virt_to_page(mmap_buf + mmap_size); page++) {
&&& SetPageReserved(page);
#else //for vmalloc
& mmap_buf& = vmalloc(mmap_size);
& if (!mmap_buf ) {
&&& return -1;
& for (i = 0; i & mmap_ i += PAGE_SIZE) {
&&& SetPageReserved(vmalloc_to_page((void *)(((unsigned long)mmap_buf) + i)));
& return 0;
2.用户空间映射内存
int test_mmap()
& mmap_fd = open(&/dev/mmap_dev&, O_RDWR);
& mmap_ptr = mmap(NULL, mmap_size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, mmap_fd, 0);
& if (mmap_ptr == MAP_FAILED) {
&&& return -1;
& return 0;
3.内核空间映射内存: 实现file_operations的mmap函数
static int mmap_mmap(struct file *filp, struct vm_area_struct *vma)
& unsigned long start = vma-&vm_
& unsigned long size = PAGE_ALIGN(vma-&vm_end - vma-&vm_start);
& if (size & mmap_size || !mmap_buf) {
&&& return -EINVAL;
#if USE_KMALLOC
& return remap_pfn_range(vma, start, (virt_to_phys(mmap_buf) && PAGE_SHIFT), size, PAGE_SHARED);
& /* loop over all pages, map it page individually */
& while (size & 0) {
&&&&&&&&& pfn = vmalloc_to_pfn(mmap_buf);
&&&&&&&&& if ((ret = remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED)) & 0) {
&&&&&&&&&&&
&&&&&&&&& }
&&&&&&&&& start += PAGE_SIZE;
&&&&&&&&& mmap_buf += PAGE_SIZE;
&&&&&&&&& size -= PAGE_SIZE;
& return 0;
static const struct file_operations mmap_fops = {
& .owner = THIS_MODULE,
& .ioctl = mmap_ioctl,
& .open = mmap_open,
& .mmap = mmap_mmap,
& .release = mmap_release,
4.用户空间撤销内存映射
void test_munmap()
& munmap(mmap_ptr, mmap_size);
& close(mmap_fd);
5.内核空间释放内存; 必须在用户空间执行munmap系统调用后才能释放
void mmap_free()
#if USE_KMALLOC
& struct page *
& for (page = virt_to_page(mmap_buf); page & virt_to_page(mmap_buf + mmap_size); page++) {
&&& ClearPageReserved(page);
& kfree(mmap_buf);
& for (i = 0; i & mmap_ i += PAGE_SIZE) {
&&& ClearPageReserved(vmalloc_to_page((void *)(((unsigned long)mmap_buf) + i)));
& vfree(mmap_buf);
& mmap_buf = NULL;
基于NETLINK的内核与用户空间共享内存的实现
author:bripengandre Email:
& & 前些日子,开发中用到了netlink来实现内核与用户空间共享内存,写点笔记与大家分享。因为我对这块也不了解,写出来的东西一定存在很多错误,请大家批评指正~
& & 内核与用户空间共享内存的关键是,用户空间必须得知共享内存的起始地址,这就要求内核空间应该有一种通信机制来通知用户空间。已经有Godbach版主等人用proc文件系统实现了(可以google '共享内存 内核 用户空间'),很显然任何内核空间与用户空间的通信方法都可资利用。本文主要讲基于NETLINK机制的实现。
二、NETLINK简介
& & netlink在linux的内核与用户空间通信中用得很多(但具体例子我举不出,因为我不清楚~~请google之),其最大优势是接口与网络编程中的socket相似,且内核要主动发信息给用户空间很方便。
& &但通过实践,我发现netlink通信机制的最大弊病在于其在各内核版本中接口变化太大,让人难以适从(可从后文列出的源码中的kernel_receive的声明窥一斑)。
&&既然涉及到内核与用户空间两个空间,就应该在两个空间各有一套接口。用户空间的接口很简单,与一般的socket接口相似,内核空间则稍先复杂,但简单的应用只需简单地了解即可:首先也是建立描述符,建立描述符时会注册一个回调函数(源码中的kernel_receive即是),然后当用户空间有消息发过来时,我们的函数将被调用,显然在这个函数里我们可做相应的处理;当内核要主动发消息给用户进程时,直接调用一个类send函数即可(netlink_unicast系列函数)。当然这个过程中,有很多结构体变量需要填充。具体用法请google,我差不多忘光了~。
三、基于netlink的共享内存& &
& &这里的共享内存是指内核与用户空间,而不是通常的用户进程间的。
& &大概流程如下。
&&内核:__get_free__pages分配连续的物理内存页(貌似返回的其实是虚拟地址)--&SetPageReserved每一页(每一页都需这个操作,参见源码)--&如果用户空间通过netlink要求获取共享内存的起始物理地址,将__get_free__pages返回的地址__pa下发给用户空间。
& &用户空间:open &/dev/shm&(一个读写物理内存的设备,具体请google&linux读写物理内存&)--&发netlink消息给内核,得到共享内存的起始物理地址--&mmap上步得到的物理地址。
四、源码说明
& &正如二中提到的,netlink接口在各版本中接口变化很大,本人懒惰及时间紧,只实验了比较新的内核2.6.25,源码如需移植到老版本上,需要一些改动,敬请原谅。
& &另外,由于本源码是从一个比较大的程序里抠出来的,所以命名什么的可能有点怪异~
&&源码包括shm_k.c(内核模块)和用户空间程序(shm_u.c)两部分。shm_k.c模块的工作是:分配8KB内存供共享,并把前几十个字节置为“hello, use share memory withnetlink&字样。shm_u.c工作是:读取共享内存的前几十个字节,将内容输出在stdout上。
& & 特别说明:该程序只适用于2.6.25左右的新版本!用__get_free_pages分配连续内存时,宜先用get_order获取页数,然后需将各页都SetPageReserved下,同样地,释放内存时,需要对每一页调用ClearPageReserved。
& & 我成功用该程序分配了4MB共享内存,运行还比较稳定。因为linux内核的默认设置,一般情况下用get_free_pages只能分配到4MB内存左右,如需增大,可能需改相应的参数并重新编译内核。
五、运行结果
& & 我是在mpc8377上运行的,全过程如下(有少许编辑,如dmesg信息只列出新增的)。
-sh-2.05b# insmod shm_k.ko
-sh-2.05b# dmesg
SHM_TEST: linux version:
SHM_TEST: init_netlink ok.
SHM_TEST: size=, page_cnt=2
SHM_TEST: __get_free_pages ok.
SHM_TEST: init_mem_pool ok.
-sh-2.05b# ./shm_u
SHM_TEST: 24, errno=0.Success, 0defe000,
the first 30 bytes of shm are: hello, use share memory with netlink
-sh-2.05b# dmesg
SHM_TEST: begin kernel_receive
SHM_TEST: receiv TA_GET_SHM_INFO
SHM_TEST: nlk_get_mem_addr ok
-sh-2.05b# rmmod shm_k
-sh-2.05b# dmesg
SHM_TEST: ta_exit ok.
-sh-2.05b#
六、内核源码
&& 1、common.h(内核与用户空间都用到的头文件)
#ifndef _COMMON_H_
#define _COMMON_H_
/* protocol type */
#define SHM_NETLINK 30
/* message type */
#define SHM_GET_SHM_INFO 1
/* you can add othe message type here */
#define SHM_WITH_NETLINK &hello, use share memory with netlink&
typedef struct _nlk_msg
& & union _data
& && &&&struct _shm_info
& && && && &uint32_t mem_
& && && && &uint32_t mem_
& && &&&}shm_
& && &&&/* you can add other content here */
}nlk_msg_t;
#endif /* _COMMON_H_ */
2、shm_k.c(内核模块)
#include &linux/init.h&
#include &linux/module.h&
#include &linux/version.h&
#include &linux/types.h&
#include &linux/skbuff.h&
#include &linux/netlink.h&
#include &net/sock.h&
#include &linux/spinlock.h&
#include &common.h&
#define SHM_TEST_DEBUG
#ifdef SHM_TEST_DEBUG
#define SHM_DBG(args...) printk(KERN_DEBUG &SHM_TEST: & args)
#define SHM_DBG(args...)
#define SHM_ERR(args...) printk(KERN_ERR &SHM_TEST: & args)
static struct _glb_para
& & struct _shm_para
& && &&&uint32_t mem_ /* memory starting address */
& && &&&uint32_t mem_ /* memory size */
& && &&&uint32_t page_ /* memory page count*/
& && &&&uint16_
& && &&&uint8_t mem_init_ /* 0, 1, init successful */
& & struct sock * /* netlink descriptor */
& & uint32_ /* user-space process's pid */
& & rwlock_
static void init_glb_para(void);
static int init_netlink(void);
static void kernel_receive(struct sk_buff* __skb);
static int nlk_get_mem_addr(struct nlmsghdr *pnhdr);
static void clean_netlink(void);
static int init_shm(void);
static void clean_shm(void);
static int&&__init init_shm_test(void);
static void clean_shm_test(void);
static void init_glb_para(void)
& & memset(&glb_para, 0, sizeof(glb_para));
static int init_netlink(void)
& & rwlock_init(&glb_para.lock);
& & SHM_DBG(&linux version:%08x\n&, LINUX_VERSION_CODE);
#if(LINUX_VERSION_CODE & KERNEL_VERSION(2,6,18))
& & glb_para.nlfd = netlink_kernel_create(SHM_NETLINK, kernel_receive);
#elif(LINUX_VERSION_CODE & KERNEL_VERSION(2,6,24))
& & glb_para.nlfd = netlink_kernel_create(SHM_NETLINK, 0, kernel_receive, THIS_MODULE));
& & glb_para.nlfd = netlink_kernel_create(&init_net, SHM_NETLINK, 0, kernel_receive, NULL, THIS_MODULE);
& & if(glb_para.nlfd == NULL)
& && &&&SHM_ERR(&init_netlink::netlink_kernel_create error\n&;);
& && &&&return (-1);
& & return (0);
static void kernel_receive(struct sk_buff* __skb)
struct sk_buff *
& & struct nlmsghdr *nlh = NULL;
SHM_DBG(&begin kernel_receive\n&;);
skb = skb_get(__skb);
invalid = 0;
if(skb-&len &= sizeof(struct nlmsghdr))
& && &&&nlh = (struct nlmsghdr *)skb-&
& && &&&if((nlh-&nlmsg_len &= sizeof(struct nlmsghdr))
& && && && &&& (skb-&len &= nlh-&nlmsg_len))
& && && && &switch(nlh-&nlmsg_type)
& && && && &{
& && && && && & case SHM_GET_SHM_INFO:
& && && && && && &&&SHM_DBG(&receiv TA_GET_SHM_INFO\n&;);
& && && && &&&nlk_get_mem_addr(nlh);
& && && && && && &&&
& && && && && & default:
& && && && && && &&&
& && && && &}
& & kfree_skb(skb);
static int nlk_get_mem_addr(struct nlmsghdr *pnhdr)
& & int ret,
& & unsigned char *old_
& & struct sk_buff *
& & struct nlmsghdr *
& & struct _nlk_msg *p;
& & glb_para.pid = pnhdr-&nlmsg_ /* get the user-space process's pid */
& & size = NLMSG_SPACE(sizeof(struct _nlk_msg)); /* compute the needed memory size */
& & if( (skb = alloc_skb(size, GFP_ATOMIC)) == NULL) /* allocate memory */
& && &&&SHM_DBG(&nlk_hello_test::alloc_skb error.\n&;);
& && &&&return (-1);
& & old_tail = skb-&
& & nlh = NLMSG_PUT(skb, 0, 0, SHM_GET_SHM_INFO, size-sizeof(struct nlmsghdr)); /* put netlink message structure into memory */
& & p = NLMSG_DATA(nlh); /* get netlink message body pointer */
& & p-&data.shm_info.mem_addr = __pa(glb_para.shm_para.mem_addr); /*__pa:convert virtual address to physical address, which needed by/dev/mem */
& & p-&data.shm_info.mem_size = glb_para.shm_para.mem_
& & nlh-&nlmsg_len = skb-&tail - old_
& & NETLINK_CB(skb).pid = 0;& && &/* from kernel */
& & NETLINK_CB(skb).dst_group = 0;
& & read_lock_bh(&glb_para.lock);
& & ret = netlink_unicast(glb_para.nlfd, skb, glb_para.pid, MSG_DONTWAIT); /* send message to user-space process */
& & read_unlock_bh(&glb_para.lock);
& & SHM_DBG(&nlk_get_mem_addr ok.\n&;);
& & return (ret);
nlmsg_failure:
& & SHM_DBG(&nlmsg_failure\n&;);
& & if(skb)
& && &&&kfree_skb(skb);
& & return (-1);
static void clean_netlink(void)
& & if(glb_para.nlfd != NULL)
& && &&&sock_release(glb_para.nlfd-&sk_socket);
static int init_shm(void)
& & char *p;
& & uint32_t page_
& & glb_para.shm_para.order = get_order(1024*8); /* allocate 8kB */
& & glb_para.shm_para.mem_addr = __get_free_pages(GFP_KERNEL, glb_para.shm_para.order);
& & if(glb_para.shm_para.mem_addr == 0)
& && &&&SHM_ERR(&init_mem_pool::__get_free_pages error.\n&;);
& && &&&glb_para.shm_para.mem_init_flag = 0;
& && &&&return (-1);
& && &&&glb_para.shm_para.page_cnt = (1&&glb_para.shm_para.order);
& && &&&glb_para.shm_para.mem_size = glb_para.shm_para.page_cnt*PAGE_SIZE;
& && &&&glb_para.shm_para.mem_init_flag = 1;
& && &&&page_addr = glb_para.shm_para.mem_
& && &&&SHM_DBG(&size=%08x, page_cnt=%d\n&, glb_para.shm_para.mem_size, glb_para.shm_para.page_cnt);
& && &&&for(i = 0; i &&&glb_para.shm_para.page_ i++)
& && && && &SetPageReserved(virt_to_page(page_addr)); /* reserved for used */
& && && && &page_addr += PAGE_SIZE;
& && &&&p = (char *)glb_para.shm_para.mem_
& && &&&strcpy(p, SHM_WITH_NETLINK); /* write */
& && &&&SHM_DBG(&__get_free_pages ok.\n&;);
& & return (0);
static void clean_shm(void)
& & uint32_t page_
& & if(glb_para.shm_para.mem_init_flag == 1)
& && &&&page_addr = glb_para.shm_para.mem_
& && &&&for(i = 0; i & glb_para.shm_para.page_ i++)
& && && && &ClearPageReserved(virt_to_page(page_addr));
& && && && &page_addr += PAGE_SIZE;
& && &&&free_pages(glb_para.shm_para.mem_addr, glb_para.shm_para.order);
static int&&__init init_shm_test(void)
& & init_glb_para();
& & if(init_netlink() & 0)
& && &&&SHM_ERR(&init_shm_test::init_netlink error.\n&;);
& && &&&return (-1);
& & SHM_DBG(&init_netlink ok.\n&;);
& & if(init_shm() & 0)
& && &&&SHM_ERR(&init_shm_test::init_mem_pool error.\n&);
& && &&&clean_shm_test();
& && &&&return (-1);
& & SHM_DBG(&init_mem_pool ok.\n&);
& & return (0);
static void clean_shm_test(void)
& & clean_shm();
& & clean_netlink();
& & SHM_DBG(&ta_exit ok.\n&);
module_init(init_shm_test);
module_exit(clean_shm_test);
MODULE_LICENSE(&GPL&);
MODULE_AUTHOR(&bripengandre ()&);
MODULE_DESCRIPTION(&Memory Share between user-space and kernel-space with netlink.&);
3、shm_u.c(用户进程)
#include &stdio.h&
#include &sys/socket.h&
#include &arpa/inet.h&
#include &linux/netlink.h&
#include &stdlib.h&
#include &string.h&
#include &errno.h&
#include &sys/types.h&
#include &unistd.h&
#include &fcntl.h&
#include &sys/mman.h&
#include &common.h&
/* netlink */
#define MAX_SEND_BUF_SIZE 2500
#define MAX_RECV_BUF_SIZE 2500
#define SHM_TEST_DEBUG
#ifdef SHM_TEST_DEBUG
#define SHM_DBG(args...) fprintf(stderr, &SHM_TEST: & args)
#define SHM_DBG(args...)
#define SHM_ERR(args...) fprintf(stderr, &SHM_TEST: & args)
struct _glb_para
& & struct _shm_para
& && &&&uint32_t mem_
& && &&&uint32_t mem_
& & int nlk_
& & char send_buf[MAX_SEND_BUF_SIZE];
& & char recv_buf[MAX_RECV_BUF_SIZE];
static void init_glb_para(void);
static&&int create_nlk_connect(void);
static int nlk_get_shm_info(void);
static int init_mem_pool(void);
int main(int argc ,char *argv[])
& & char *p;
& & init_glb_para();
& & if(create_nlk_connect() & 0)
& && &&&SHM_ERR(&main::create_nlk_connect error.\n&);
& && &&&return (1);
& & if(nlk_get_shm_info() & 0)
& && &&&SHM_ERR(&main::nlk_get_shm_info error.\n&);
& && &&&return (1);
& & init_mem_pool();
& & /* printf the first 30 bytes */
& & p = (char *)glb_para.shm_para.mem_
& & p[strlen(SHM_WITH_NETLINK)] = '\0';
& & printf(&the first 30 bytes of shm are: %s\n&, p);
& & return (0);
static void init_glb_para(void)
& & memset(&glb_para, 0, sizeof(glb_para));
static&&int create_nlk_connect(void)
& & struct sockaddr_
& & sockfd = socket(PF_NETLINK, SOCK_RAW, SHM_NETLINK);
& & if(sockfd & 0)
& && &&&SHM_ERR(&create_nlk_connect::socket error:%s\n&, strerror(errno));
& && &&&return (-1);
& & memset(&local, 0, sizeof(local));
& & local.nl_family = AF_NETLINK;
& & local.nl_pid = getpid();
& & local.nl_groups = 0;
& & if(bind(sockfd, (struct sockaddr*)&local, sizeof(local)) != 0)
& && &&&SHM_ERR(&create_nlk_connect::bind error: %s\n&, strerror(errno));
& && &&&return -1;
& & glb_para.nlk_fd =
& & return (sockfd);
static int nlk_get_shm_info(void)
& & struct nlmsghdr *
& & struct _nlk_msg *p;
& & struct sockaddr_
& & int recv_len,
& & memset(&kpeer, 0, sizeof(kpeer));
& & kpeer.nl_family = AF_NETLINK;
& & kpeer.nl_pid = 0;
& & kpeer.nl_groups = 0;
& & memset(glb_para.send_buf, 0, sizeof(glb_para.send_buf));
& & nlh = (struct nlmsghdr *)glb_para.send_
& & nlh-&nlmsg_len = NLMSG_SPACE(0);
& & nlh-&nlmsg_flags = 0;
& & nlh-&nlmsg_type = SHM_GET_SHM_INFO;
& & nlh-&nlmsg_pid = getpid();
& & sendto(glb_para.nlk_fd, nlh, nlh-&nlmsg_len, 0, (struct sockaddr*)&kpeer, sizeof(kpeer));
& & memset(glb_para.send_buf, 0, sizeof(glb_para.send_buf));
& & kpeerlen = sizeof(struct sockaddr_nl);
recv_len = recvfrom(glb_para.nlk_fd, glb_para.recv_buf,sizeof(glb_para.recv_buf), 0, (struct sockaddr*)&kpeer,&kpeerlen);
p = NLMSG_DATA((struct nlmsghdr *) glb_para.recv_buf);
SHM_DBG(&%d, errno=%d.%s, %08x, %08x\n&, recv_len, errno,strerror(errno),p-&data.shm_info.mem_addr,&&p-&data.shm_info.mem_size);
glb_para.shm_para.mem_addr = p-&data.shm_info.mem_
glb_para.shm_para.mem_size = p-&data.shm_info.mem_
return (0);
static int init_mem_pool(void)
& & int map_
& & void *map_
& & map_fd = open(&/dev/mem&, O_RDWR);
& & if(map_fd & 0)
& && &&&SHM_ERR(&init_mem_pool::open %s error: %s\n&, &/dev/mem&, strerror(errno));
& && &&&return (-1);
& & map_addr = mmap(0, glb_para.shm_para.mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, glb_para.shm_para.mem_addr);
& & if(map_addr == NULL)
& && &&&SHM_ERR(&init_mem_pool::mmap error: %s\n&, strerror(errno));
& && &&&return (-1);
& & glb_para.shm_para.mem_addr = (uint32_t)map_
& & return (0);
4、Makefile
#PREFIX = powerpc-e300c3-linux-gnu-
CC&&?= $(PREFIX)gcc
KERNELDIR ?= /lib/modules/`uname -r`/build
all: modules app
obj-m:= shm_k.o
module-objs := shm_k.c
make -C $(KERNELDIR) M=`pwd` modules
app: shm_u.o
$(CC) -o shm_u shm_u.c
rm -rf *.o Module.symvers modules.order shm_u shm_k.ko shm_k.mod.c .tmp_versions .shm_k.*
看过本文的人也看了:
我要留言技术领域:
取消收藏确定要取消收藏吗?
删除图谱提示你保存在该图谱下的知识内容也会被删除,建议你先将内容移到其他图谱中。你确定要删除知识图谱及其内容吗?
删除节点提示无法删除该知识节点,因该节点下仍保存有相关知识内容!
删除节点提示你确定要删除该知识节点吗?VM linux宿主机开发的一些基本设置_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
VM linux宿主机开发的一些基本设置
上传于||暂无简介
阅读已结束,如果下载本文需要使用1下载券
想免费下载本文?
定制HR最喜欢的简历
你可能喜欢推荐这篇日记的豆列
······版本:v1.2Crifan Li摘要本文主要介绍了什么是交叉编译,为何要有交叉编译;解释了什么是工具链,什么是交叉工具链;详解解释了交叉编译器的名字的命名规则,以及如何获得交叉编译器,制作交叉编译器的各种工具,使用已有的交叉编译器和自己手动编译交叉编译器之间的对比;最后总结了交叉编译方面的心得和注意事项。本文提供多种格式供:在线阅读下载(7zip压缩包)HTML版本的在线地址为:有任何意见,建议,提交bug等,都欢迎去讨论组发帖讨论:修订历史修订 1.2crl将帖子内容整理过来添加了关于交叉编译器命名规则的解释添加了使用已有的交叉编译器和自己手动编译交叉编译器之间的对比补充完整帖子引用版权 (C) 2013 Crifan, 本文章遵从:署名-非商业性使用 2.5 中国大陆(CC BY-NC 2.5)目录1.1. 什么是交叉编译2.1. 什么是工具链2.2. 什么是交叉工具链3. 交叉编译器简介3.1. 交叉编译器的名字的命名规则3.1.1. 交叉编译器名字举例3.1.2. crosstool-ng中交叉编译前缀的命名规则3.1.2.1. 交叉编译器名字中的arch部分3.1.2.1.1. crosstool-ng中arch的值3.1.2.2. 交叉编译器名字中的vendor部分3.1.2.2.1. crosstool-ng中vendor的值3.1.2.3. 交叉编译器名字中的kernel部分3.1.2.3.1. crosstool-ng中kernel的值3.1.2.4. 交叉编译器名字中的system部分3.1.2.4.1. system中的gnu3.1.2.4.1.1. crosstool-ng中system为gnu的情况3.1.2.4.2.1. crosstool-ng中system为eabi的情况3.1.2.4.3. system中的uclibc3.1.2.4.3.1. crosstool-ng中system为uclibc的情况3.2. 如何得到交叉编译器3.2.1. 拿来主义:直接去下载和使用别人已经编译好的交叉编译器3.2.2. 自己动手,丰衣足食:自己去编译出来一套自己想要的交叉编译器3.2.2.1. 白手起家从头开始制作交叉编译器3.2.2.2. 借助别人的工具去制作交叉编译器3.3. 各种制作交叉编译器的工具3.3.1. crosstool-NG3.3.2. Buildroot3.3.3. crosstool3.3.4. Embedded Linux Development Kit (ELDK)3.3.5. OpenEmbedded的BitBake3.3.6. Crossdev3.3.7. OSELAS.Toolchain()3.4. 使用已有的交叉编译器和自己手动编译交叉编译器之间的对比3.4.1. 使用已有交叉编译器的优点3.4.2. 使用已有交叉编译器的缺点4. 交叉编译心得和注意事项4.1. 交叉编译心得和注意事项范例清单1.1. 3.1. 3.2. 3.3. 3.4. 3.5. 前言目录1. 本文目的1. 本文目的本文目的在于,介绍关于交叉编译方面的概念,以及如何获得和制作交叉编译器等等内容。2. 待完成有空再去自己,不用工具,手动的,从头到尾的,制作一个交叉编译器。然后再把内容整理过来。第 1 章 交叉编译简介目录1.1. 什么是交叉编译相关旧帖:1.1. 什么是交叉编译解释什么是交叉编译之前,先要明白一个概念:本地编译我们之前常见的软件开发,都是属于本地编译:在当前的PC下,x86的CPU下,直接编译出来程序,可以运行的程序(或者库文件),其可以直接在当前的环境,即x86的CPU下,当前电脑中,运行。此时的编译,可以叫做,本地编译,即在当前目标平台下,编译出来的程序,也只是放到当前平台下,就可以运行的。交叉编译,是一个和,本地编译,相对应的概念。而所谓的,交叉编译,就是:在一种平台上编译,编译出来的程序,是放到别的平台上运行即编译的环境,和运行的环境,不一样,属于交叉的,此所谓cross交叉编译,这个概念,主要和嵌入式开发有关。例 1.1. 在x86平台上编译,在ARM平台上运行一种最常见的例子就是:在进行嵌入式开发时手上有个嵌入式开发板,CPU是arm的然后在x86的平台下开发,比如Ubuntu的Linux,或者是Win7然后就需要:在x86的平台上,(用交叉编译器)去编译你写好的程序代码编译生成的(可执行的)程序,是放到目标开发板,arm的CPU上运行的此所谓:在x86平台上编译,在ARM平台上运行交叉编译,英文常写作cross compile,也有其他写法:crosscompile, cross compiling等1.2. 为何要有交叉编译之所以要有交叉编译,主要原因是:嵌入式系统中的资源太少具体的解释就是:交叉编译出来的程序,所要运行的目标环境中,各种资源,都相对有限,所以很难进行直接的本地编译最常见的情况是:在进行嵌入式开发时,目标平台,即嵌入式开发板,比如是最大主频200MHz的ARM的CPU,加上32M的RAM,加上1G的Nand Flash等等。在如此相对比较紧张的硬件资源的前提下,在已经运行了嵌入式Linux的前提下,是没法很方便的,直接在嵌入式Linux下,去本地编译,去在ARM的CPU下,编译出来,供ARM的CPU可以运行的程序的。因为编译,开发,都需要相对比较多的CPU,内存,硬盘等资源,而嵌入式开发上的那点资源,只够嵌入式(Linux)系统运行的,没太多剩余的资源,供你本地编译。BusyBox中包含make等和编译开发相关的工具对应的,等你后期熟悉了嵌入式开发,熟悉了Busybox后,比如在Buildroot中去配置Busybox,或者单独交叉编译BusyBox时:就会看到,后来的BusyBox,功能增加后,也已经包含了一些,和编译开发相关的工具,比如make等等而这些工具,本来的话,只是,放在PC端使用,即在x86平台下做开发的时候,在交叉编译的时候,才用到的工具,现在,也在(BusyBox的)嵌入式环境中,支持了。此时,如果,你在BusyBox中把相关的开发工具都选上的话,再加上,你的目标开发板的硬件配置足够强大的话,比如CPU都是以GHz为单位,等等加上相关的开发的库和工具都很全的话实际上,至少理论上,也是可以在你的嵌入式Linux中,进行,有限的,甚至是很大程度上的,本地开发即,直接在ARM的开发板上,嵌入式Linux中,直接进行嵌入式开发,进行针对ARM的本地编译比如,编译出一个helloworld,估计还是可以的这样,就不存在,或者说,避免了,此处所说的,交叉编译,而变成了本地编译就相当于,之前在x86的PC端的,编译程序放在x86的CPU上运行的本地编译,在ARM的CPU,嵌入式Linux中,也实现了但是很明显,对于更加复杂的程序或者库,在ARM开发板上直接编译的可行性和效率,相对就很低而且如果是本身折腾Uboot等东西,本身目标运行环境,就没有完整的(嵌入式Linux)系统的话,那么就更加没法在目标平台实现本地编译了。则还是只能进行,此处所说的,交叉编译第 2 章 交叉工具链简介目录2.1. 什么是工具链2.2. 什么是交叉工具链搞懂了前面介绍的的概念后,再来解释什么是交叉工具链。相关旧帖:【整理】关于Toolchain,cross toolchain,cross compiler2.1. 什么是工具链所谓的工具链,两部分的含义:工具工具,即tool工具,是用来干活的此处要干的活,目标是为了:生成(可以运行的)程序或库文件而为了达成此目标,内部的执行过程和逻辑主要包含了:编译编译的输入(对象)是:程序代码编译输出(目标)是:目标文件编译所需要的工具是:编译器编译器,常见的编译器,即为gcc链接链接的输入(对象)是:(程序运行时所依赖的,或者某个库所依赖的另外一个)库(文件)链接的输出(目标)是:程序的可执行文件,或者是可以被别人调用的完整的库文件链接所需要的工具是:链接器链接器,即ld即,此处,为了将程序代码,编译成可执行文件,涉及到编译,链接(等其他步骤),要依赖到很多相关的工具,最核心的是编译器gcc,链接器ld。而此处,所谓的工具,主要指的就是:和程序编译链接等相关的gcc,ld等工具binutils包含了ld等工具实际上,上面所说的ld,只是处理操作目标文件,二进制文件的最主要的一个工具而和操作目标等文件相关的,还有其他很多工具的:as,objcopy,strip,ar等等工具的所以,对此,GNU官网,弄出一个binutils,即binary utils,二进制工具(包),集成了这些,和操作二进制相关的工具集合,叫做binutils所以,之后你所见到的,常见的工具,就是那个著名的了。更加详细的解释,参见教程:GNU Binutils详解链链,即链条,chain之所以能称为链,你是说明不止一个东西,然后,按照对应的逻辑,串在一起,链在一起而对应的,涉及到的:不止一个东西指的是就是前面所说的那个工具,即:和程序编译链接等相关的gcc,binutils等工具按照对应的逻辑指的就是,按照程序本身编译链接的先后顺序,即:先编译,后链接,再进行后期其他的处理等等,比如用objcopy去操作相应的目标文件等等。如此的,将:和程序编译链接等相关的gcc,binutils等工具按照先编译后链接等相关的编译程序的内在逻辑串起来,就成了我们所说的:工具链2.2. 什么是交叉工具链普通所说的,工具链,指的是当前自己的本地平台的工具链。用于,交叉编译,的工具链,就叫做交叉工具链即,那些工具,即编译的gcc,链接的ld,以及相关的工具,用于交叉编译的,工具链,叫做交叉工具链。交叉工具链,很明显,是用来,交叉编译,跨平台的程序所用的。交叉工具链,和(本地)工具链类似,也是包含了很多的,对应的工具,交叉编译版本的gcc,ld,as等等。但是,由于其中最最主要的是用于编译的gcc,所以,我们也常把:交叉工具链,简称为交叉编译器即:严格意义上来说,交叉编译器,只是指的是交叉编译版本的gcc但是实际上为了叫法上的方便,我们常说的交叉编译器,都是指的是交叉工具链即,常说的交叉编译版本的gcc,比如arm-linux-gcc,实际上指代了,包含一系列交叉编译版本的交叉工具链(arm-linux-gcc,arm-linux-ld,arm-linux-as等等)而此文中,后面,所说的,如无特殊指明,均用交叉编译器指代交叉工具链。下面就对交叉编译器,进行详细的解释。第 3 章 交叉编译器简介目录3.1. 交叉编译器的名字的命名规则3.1.1. 交叉编译器名字举例3.1.2. crosstool-ng中交叉编译前缀的命名规则3.1.2.1. 交叉编译器名字中的arch部分3.1.2.1.1. crosstool-ng中arch的值3.1.2.2. 交叉编译器名字中的vendor部分3.1.2.2.1. crosstool-ng中vendor的值3.1.2.3. 交叉编译器名字中的kernel部分3.1.2.3.1. crosstool-ng中kernel的值3.1.2.4. 交叉编译器名字中的system部分3.1.2.4.1. system中的gnu3.1.2.4.1.1. crosstool-ng中system为gnu的情况3.1.2.4.2.1. crosstool-ng中system为eabi的情况3.1.2.4.3. system中的uclibc3.1.2.4.3.1. crosstool-ng中system为uclibc的情况3.2. 如何得到交叉编译器3.2.1. 拿来主义:直接去下载和使用别人已经编译好的交叉编译器3.2.2. 自己动手,丰衣足食:自己去编译出来一套自己想要的交叉编译器3.2.2.1. 白手起家从头开始制作交叉编译器3.2.2.2. 借助别人的工具去制作交叉编译器3.3. 各种制作交叉编译器的工具3.3.1. crosstool-NG3.3.2. Buildroot3.3.3. crosstool3.3.4. Embedded Linux Development Kit (ELDK)3.3.5. OpenEmbedded的BitBake3.3.6. Crossdev3.3.7. OSELAS.Toolchain()3.4. 使用已有的交叉编译器和自己手动编译交叉编译器之间的对比3.4.1. 使用已有交叉编译器的优点3.4.2. 使用已有交叉编译器的缺点相关旧帖:3.1. 交叉编译器的名字的命名规则在折腾嵌入式开发,用到交叉编译器的时候,常常会看到这样的名字:arm-xscale-linux-gnueabi-gccarm-liunx-gnu-gcc等等其中,对应的交叉编译器的前缀为:arm-xscale-linux-gnueabi-arm-liunx-gnu-而关于这些名字,我之前也是没注意,或者说很模糊,不是很清楚这些名字是从何而来的。后来,经过折腾了crosstool-ng后,基本上明白了这些名字,是如何生成的。其中,貌似此交叉编译器命名的规则,应该是通用的,至少记得是Buildroot中,好像也是这样命名的。下面,就以crosstool-ng为例,参考我之前折腾crosstool-ng期间:【整理】crosstool中如何设置xscale的Tuple’s vendor string(CT_TARGET_VENDOR)所了解到的内容,来解释解释,这些名字的含义。3.1.1. 交叉编译器名字举例此处,以编译crosstool-ng中:通过ct-ng list-samples中得到的输出为例,当做交叉编译器的名字的例子,供参考:CLi@PC-CLI-1 ~/develop/crosstool-ng/crosstool-ng-1.18.0_build
$ ct-ng list-samples
Sample name
alphaev56-unknown-linux-gnu
alphaev67-unknown-linux-gnu
arm-bare_newlib_cortex_m3_nommu-eabi
arm-cortex_a15-linux-gnueabi
arm-cortex_a8-linux-gnueabi
arm-davinci-linux-gnueabi
armeb-unknown-eabi
armeb-unknown-linux-gnueabi
armeb-unknown-linux-uclibcgnueabi
arm-unknown-eabi
arm-unknown-linux-gnueabi
arm-unknown-linux-uclibcgnueabi
armv6-rpi-linux-gnueabi
avr32-unknown-none
bfin-unknown-linux-uclibc
i586-geode-linux-uclibc
i586-mingw32msvc,i686-none-linux-gnu
i686-nptl-linux-gnu
i686-unknown-mingw32
m68k-unknown-elf
m68k-unknown-uclinux-uclibc
mips64el-n32-linux-uclibc
mips64el-n64-linux-uclibc
mips-ar2315-linux-gnu
mipsel-sde-elf
mipsel-unknown-linux-gnu
mips-malta-linux-gnu
mips-unknown-elf
mips-unknown-linux-uclibc
powerpc-405-linux-gnu
powerpc64-unknown-linux-gnu
powerpc-860-linux-gnu
powerpc-e300c3-linux-gnu
powerpc-e500v2-linux-gnuspe
powerpc-unknown_nofpu-linux-gnu
powerpc-unknown-linux-gnu
powerpc-unknown-linux-uclibc
s390-ibm-linux-gnu
s390x-ibm-linux-gnu
sh4-unknown-linux-gnu
x86_64-unknown-linux-gnu
x86_64-unknown-linux-uclibc
x86_64-unknown-mingw32
: sample was found in current directory
G (Global)
: sample was installed with crosstool-NG
X (EXPERIMENTAL): sample may use EXPERIMENTAL features
B (BROKEN)
: sample is currently broken3.1.2. crosstool-ng中交叉编译前缀的命名规则crosstool-ng中,交叉编译器的(前缀)的名字的命名规则是:arch-vendor-kernel-system对应分别是:3.1.2.1. 交叉编译器名字中的arch部分arch,即系统架构表示交叉编译器,是用于哪个目标系统架构中,用于那个平台中的即,用此交叉编译器编译出来的程序,是运行在哪种CPU上面的arch的值,常见的有很多种,比如arm,x86,mips等等。例 3.1. 举例:交叉编译器中的arch的值arm-cortex_a8-linux-gnueabi中的armmips-ar2315-linux-gnu中的mipspowerpc-e500v2-linux-gnuspe中的powerpcx86_64-unknown-mingw32中的x86_643.1.2.1.1. crosstool-ng中arch的值crosstool-ng中,和arch对应的值,应该就是"Target options"中的"Target Architecture"的值了。比如常见的,配置为arm的话,就是:Target options
Target Architecture (arm)
---&对应的配置参数是:ARCH_arm3.1.2.2. 交叉编译器名字中的vendor部分vendor,即生成厂家,提供商表示谁提供的,即谁制作出来这个交叉编译器的。vendor的值,貌似是可以自己随便填写的。其他常见写法,还有写成编译交叉编译器的作者的自己的名字的比如,我叫crifan,那么就可以写成crifan,然后生成的交叉编译器,就是xxx-crifan-xxx-xxx了。更加通用的做法,好像是:把vendor写成,体系架构的值,比如我之前针对xscale的去配置crosstool-ng的时候,就写了个xscale。或者写成CPU的厂家的名字,或者是开发板的名字等等。例 3.2. 举例:交叉编译器中的vendor的值arm-cortex_a8-linux-gnueabi中的cortex_a8,就属于CPU的名字mips-ar2315-linux-gnu中的ar2315powerpc-e500v2-linux-gnuspe中的e500v2,也是CPU的内核名arm-buildroot-linux-uclibcgnueabi中的buildroot,是之前折腾Buildroot时,看到的,即Buildroot把自己视为当前自己制作出来的交叉编译器的vendor。3.1.2.2.1. crosstool-ng中vendor的值crosstool-ng中,和vendor对应的值,应该就是"Toolchain options"中的"Tuple's vendor string"的值了。比如我之前配置为xscale的话,就是:Toolchain options
(xscale) Tuple's vendor string对应的配置参数是:CT_TARGET_VENDOR对应的help的解释是:┌────────────────────────────────── Tuple's vendor string ──────────────────────────────────┐
│ CT_TARGET_VENDOR:
│ Vendor part of the target tuple.
│ A tuple is of the form arch-vendor-kernel-system.
│ You can set the second part, vendor, to whatever you see fit.
│ Use a single word, or use underscores "_" to separate words.
│ Use neither dash nor space, as it breaks things.
│ Keep the default (unknown) if you don't know better.
│ Symbol: TARGET_VENDOR [=xscale]
│ Prompt: Tuple's vendor string
Defined at config/toolchain.in:99
-& Toolchain options
│3.1.2.3. 交叉编译器名字中的kernel部分kernel,直译为,内核其实指的是,你用此交叉编译器,编译出来的程序,所运行的目标系统即,此交叉编译器,编译出来的程序,在什么系统中,什么环境中,运行。而对应的环境或系统,主要有两种:Linux表示:有OS(此处主要指的是Linux)操作系统的环境比如,我用交叉编译器,编译一个helloworld程序,然后下载到嵌入式开发中的嵌入式Linux中运行,就属于,用此交叉编译器,编译出来的程序,是要运行于,带OS,即嵌入式Linux系统,环境中的此处,简称为,有OS的目标系统:Linuxbare-metalbare-metal,直译为:裸金属表示:无(此处主要指的是Linux)操作系统的环境,比如,用此交叉编译器,去编译一个Uboot,或者是其他一个小程序,是运行在,无嵌入式Linux的时候,单独运行的一个程序。比如,你购买的嵌入式系统开发版,常常附带一些小程序,比如点亮LED,跑马灯等程序,就是这种,运行在无OS的环境的此处,简称为:无OS系统的:bare-metal关于,运行在有OS的Linux下,和,无OS的bare-metal,到底有何区别目前,还没有完全搞懂。但是,之前遇到一个实际的例子:之前用比较新的一个交叉编译器去编译比较老的uboot时,会出现一个错误:【已解决】uboot交叉编译出错:gcc/config/arm/lib1funcs.asm:1266: undefined reference to `raise’其就是和这个kernel有关:编译的uboot,目标运行平台,不是Linux,而是裸的开发板,即Linux还没有运行呢,Uboot去运行,去初始化开发板的时候详细的情况,见该贴中的解释。例 3.3. 举例:交叉编译器中的kernel的值arm-bare_newlib_cortex_m3_nommu-eabi中的bare_newlib_cortex_m3_nommu,此处的bare,应该就是指的是bare-metal,用于运行在无OS的环境下powerpc-e300c3-linux-gnu中的linuxm68k-unknown-uclinux-uclibc中的uclinux,就是指的是编译出来的程序,是运行于没有MMU的uclinux下3.1.2.3.1. crosstool-ng中kernel的值crosstool-ng中,和kernel对应的值,应该就是"Operating System"中的"Target OS"的值了。比如我之前配置为Linux的话,就是:Operating System
Target OS (linux)
---&对应的配置参数是:GEN_CHOICE_KERNEL中的CT_KERNEL_linux对应的help的解释是:┌────────────────────────────────────────── linux ──────────────────────────────────────────┐
│ CT_KERNEL_linux:
│ Build a toolchain targeting systems running Linux as a kernel.
│ Symbol: KERNEL_linux [=y]
│ Prompt: linux
Defined at config.gen/kernel.in:8
Depends on: GEN_CHOICE_KERNEL [=y] && KERNEL_linux_AVAILABLE [=y]
-& Operating System
-& Target OS (GEN_CHOICE_KERNEL [=y])
Selects: KERNEL_SUPPORTS_SHARED_LIBS [=y]
│3.1.2.4. 交叉编译器名字中的system部分system,直译为,系统其实主要表示的,交叉编译器所选择的库函数和目标系统最常见的一些值有,gnu,gnueabi,uclibcgnueabi等等。其中,此处有几方面的值,表示了几方面的含义:3.1.2.4.1. system中的gnu好像都是gnu不是很明白,貌似是:gnu == gnu libc == glibc即,gnu,就是表示用的是glibc的意思。3.1.2.4.1.1. crosstool-ng中system为gnu的情况crosstool-ng中,和system中gnu对应的值,应该就是"C-library"中的"C library"的值设置为"glibc"了。C-library
C library (glibc)
---&对应的配置参数是:CT_LIBC_glibc对应的help的解释是:┌────────────────────────────────────────── glibc ──────────────────────────────────────────┐
│ CT_LIBC_glibc:
│ The de-facto standard for Linux distributions.
│ Feature-rich, but large...
Most usefull for desktop-like systems.
│ Symbol: LIBC_glibc [=y]
│ Prompt: glibc
Defined at config.gen/libc.in:53
Depends on: GEN_CHOICE_LIBC [=y] && LIBC_glibc_AVAILABLE [=y] && !WINDOWS [=n] && !\
│ BARE_METAL [=n] && ARCH_USE_MMU [=y]
-& C-library
-& C library (GEN_CHOICE_LIBC [=y])
Selects: LIBC_SUPPORT_NPTL [=y] && CC_CORE_PASSES_NEEDED [=y]
│3.1.2.4.2. system中的eabi与此相对应的,之前早期的是oabieabi和oabi的对比,详见:3.1.2.4.2.1. crosstool-ng中system为eabi的情况crosstool-ng中,和system中eabi对应的值,应该就是"Target options"中的"-*- Use EABI"的值了。Target options
-*- Use EABI注意:此处是选择的ARM,EABI在此处,已经是默认,无法修改的值,只能是EABI了。好像是因为,Linux内核等其他选择导致的,此处无法更改EABI。对应的配置参数是:CT_ARCH_ARM_EABI对应的help的解释是:┌──────────────────────────────────────── Use EABI ─────────────────────────────────────────┐
│ CT_ARCH_ARM_EABI:
│ Set up the toolchain so that it generates EABI-compliant binaries.
│ If you say 'n' here, then the toolchain will generate OABI binaries.
│ OABI has long been deprecated, and is now considered legacy.
│ Symbol: ARCH_ARM_EABI [=y]
│ Prompt: Use EABI
Defined at config/arch/arm.in.2:54
Depends on: ARCH_arm [=y]
-& Target options
Selected by: ARCH_ARM_EABI_FORCE [=y] && ARCH_arm [=y]
│3.1.2.4.3. system中的uclibcuclibc,是c库中的一种crosstool-ng中,目前支持三种:glibc,eglibc,uclibc关于三种的关系,详见:3.1.2.4.3.1. crosstool-ng中system为uclibc的情况crosstool-ng中,和system中uclibc对应的值,应该就是"C-library"中的"C library"的值设置为"uClibc"了。C-library
C library (uClibc)
---&对应的配置参数是:CT_LIBC_uClibc对应的help的解释是:┌───────────────────────────────────────── uClibc ──────────────────────────────────────────┐
│ CT_LIBC_uClibc:
│ The de-facto standard for embeded linux systems.
│ Highly configurable, thus as feature-rich as you
│ need, without compromising for size.
│ Symbol: LIBC_uClibc [=y]
│ Prompt: uClibc
Defined at config.gen/libc.in:24
Depends on: GEN_CHOICE_LIBC [=y] && LIBC_uClibc_AVAILABLE [=y] && !WINDOWS [=n] && !\
│ BARE_METAL [=n]
-& C-library
-& C library (GEN_CHOICE_LIBC [=y])
Selects: LIBC_SUPPORT_LINUXTHREADS [=y] && LIBC_SUPPORT_THREADS_NONE [=y] && \
│ CC_CORE_PASSES_NEEDED [=y]
│所以,针对上述,gnu,eabi,uclibc等几个选项,对应的常见的一些组合的含义是:gnu等价于:glibc+oabignueabi等价于:glibc+eabiuclibc等价于:uclibc+oabi(待确认)例 3.4. 举例:交叉编译器中的system的值arm-cortex_a8-linux-gnueabi中的gnueabi,即glibc+eabimips-ar2315-linux-gnu中的gnu,即glibc+oabipowerpc-e500v2-linux-gnuspe中的gnuspe,没搞懂啥意思。。x86_64-unknown-mingw32中的mingw32,用的是Windows下的mingw32的库3.2. 如何得到交叉编译器了解了之前的交叉编译器的命名规则后,也就明白了交叉编译,针对不同架构,平台,目标系统等的区别。而对于嵌入式开发,想要获得,针对我们所需要的,目标的CPU所合适的交叉编译器,就成了接下来,顺其自然要考虑的事情。想要得到,可用的,针对自己的CPU的交叉编译器,主要有两种方式:3.2.1. 拿来主义:直接去下载和使用别人已经编译好的交叉编译器难度等级:1级这个没有啥特殊要求解释的,就是,网上,总会有,免费的,好用的各种资源的。其中就包括,别人,已经针对某些CPU,某些平台,编译好了交叉编译器了而你要做的事情就是:找到合适的,并下载下来使用。关于网上,现存的,可用的,针对arm的交叉编译器,可以参考我之前整理的一些:常见的,获得交叉编译器的方式其实,相对比较常见的,获得可用的,交叉编译器的方式是:当你购买某一家的(嵌入式)开发板的时候,然后开发板厂家,提供你对应的硬件开发板的同时,也提供对应的整套开发软件。此处,整套的开发软件,其中就包括,对应的,用来编译其厂家提供的BSP的软件源码的,交叉编译器。即:一般来说,你买了某家的某款的嵌入式开发板的时候,就送了对应的交叉编译器例 3.5. 购买了TQ2440的开发板,就送了对应的交叉编译器拿我之前,购买的TQ2440的开发板为例买了TQ2440的开发板的时候,就送了对应的光盘了。光盘里面,就包含了对应的各种开发资料和交叉编译器其实,对于交叉编译器本身,TQ2440的厂家,叫做天嵌公司,其本身有自己的论坛,论坛里面,也可以免费下载到对应的交叉编译器的[光盘下载] 2010年6月 最新TQ2440光盘下载 (Linux内核,WinCE的eboot,uboot均有更新)3.2.2. 自己动手,丰衣足食:自己去编译出来一套自己想要的交叉编译器如果网上没有合适的交叉编译器,那么就需要你手动去制作了。自己手动制作交叉编译器,又分两种:3.2.2.1. 白手起家从头开始制作交叉编译器难度等级:10级此法,目前我也还没折腾过只是知道,难度,相对是最大的等抽空折腾了之后,再总结出来。3.2.2.2. 借助别人的工具去制作交叉编译器难度等级:6级相关旧帖:对于,制作交叉编译器这样的事情,本身是很需要技术含量,和很耗时的事情所以,对此,现在现存很多相关的工具,以简化制作交叉编译器这个事情的复杂度,帮你节省很多精力和时间而你所要做的事情就只是:了解有哪些工具,选个合适的工具,搞懂如何使用,用其制作出你所需要的交叉编译器,即可。关于现在有哪些交叉编译器的制作工具,正是下文正要详细解释的:第 3.3 节 “各种制作交叉编译器的工具”3.3. 各种制作交叉编译器的工具下面,就针对,现存已知的,交叉编译器,的制作工具,进行简单的总结和介绍:3.3.1. crosstool-NGcrosstool-ng的主页:关于crosstool-ng的更多介绍和使用,可以参考我的另外一个教程:3.3.2. BuildrootBuildroot主页:特点:不仅能制作交叉工具链,而且还可以制作根文件系统rootfs。而且还支持同时编译对应的Linux内核和Uboot。关于Buildroot的更多介绍和使用,可以参考我的另外一个教程:3.3.3. crosstool现在用的最多的是那个0.43的版本:也可以去在线浏览对应的源码:3.3.4. Embedded Linux Development Kit (ELDK)也是和交叉编译相关的。提供编译好的东西供使用。可以去这里:去下载。3.3.5. OpenEmbedded的BitBakeOpenEmbedded是一个创建嵌入式Linux的整套框架,其中包括了制作对应的交叉编译器的工具,叫做BitBakeOpenEmbedded简称OE。OpenEmbedded主页:OpenEmbedded的在线文档:关于BitBake可去参考:中的:3.3.6. Crossdev中的:3.3.7. OSELAS.Toolchain()3.4. 使用已有的交叉编译器和自己手动编译交叉编译器之间的对比后来在:中发现作者ymorin之前的一些会议演讲:等内容,比如:其中,对于下载别人已有的交叉编译器和自己手动编译一个交叉编译器之间,做了些对比,分析了各自的优缺点。个人觉得其说的比较全面,特此整理如下:3.4.1. 使用已有交叉编译器的优点安装和使用都很方便别人发布的,已经编译好的交叉编译器,基本都是压缩包然后你解压后,即可得到对应的,可用的,交叉编译器其效果,类似于,之前自己编译出来的交叉编译器,有对应的交叉编译版本的gcc,ld等等程序,即:arm-xscale-linux-gnueabi-gccarm-xscale-linux-gnueabi-ld等等文件的了。比如:中的:crifan@ubuntu:~/develop/crosstool-ng/crosstool-ng-1.18.0_build$ ls /home/crifan/develop/crosstool-ng/x-tools/arm-xscale-linux-gnueabi/bin -lh
-r-xr-xr-x 1 crifan crifan 605K Aug
8 01:10 arm-xscale-linux-gnueabi-addr2line
-r-xr-xr-x 2 crifan crifan 633K Aug
8 01:10 arm-xscale-linux-gnueabi-ar
-r-xr-xr-x 2 crifan crifan 1.1M Aug
8 01:10 arm-xscale-linux-gnueabi-as
-r-xr-xr-x 2 crifan crifan 276K Aug
8 01:10 arm-xscale-linux-gnueabi-c++
lrwxrwxrwx 1 crifan crifan
8 00:54 arm-xscale-linux-gnueabi-cc -& arm-xscale-linux-gnueabi-gcc
-r-xr-xr-x 1 crifan crifan 605K Aug
8 01:10 arm-xscale-linux-gnueabi-c++filt
-r-xr-xr-x 1 crifan crifan 276K Aug
8 01:10 arm-xscale-linux-gnueabi-cpp
-r-xr-xr-x 1 crifan crifan 3.1K Aug
7 23:57 arm-xscale-linux-gnueabi-ct-ng.config
-r-xr-xr-x 1 crifan crifan
8 01:10 arm-xscale-linux-gnueabi-elfedit
-r-xr-xr-x 2 crifan crifan 276K Aug
8 01:10 arm-xscale-linux-gnueabi-g++
-r-xr-xr-x 2 crifan crifan 272K Aug
8 01:10 arm-xscale-linux-gnueabi-gcc
-r-xr-xr-x 2 crifan crifan 272K Aug
8 01:10 arm-xscale-linux-gnueabi-gcc-4.6.0
-r-xr-xr-x 1 crifan crifan
8 01:10 arm-xscale-linux-gnueabi-gcov
-r-xr-xr-x 1 crifan crifan 2.7M Aug
8 01:10 arm-xscale-linux-gnueabi-gdb
-r-xr-xr-x 1 crifan crifan 2.7M Aug
8 01:10 arm-xscale-linux-gnueabi-gdbtui
-r-xr-xr-x 1 crifan crifan 670K Aug
8 01:10 arm-xscale-linux-gnueabi-gprof
-r-xr-xr-x 4 crifan crifan 1.1M Aug
8 01:10 arm-xscale-linux-gnueabi-ld
-r-xr-xr-x 4 crifan crifan 1.1M Aug
8 01:10 arm-xscale-linux-gnueabi-ld.bfd
-r-xr-xr-x 1 crifan crifan
8 01:10 arm-xscale-linux-gnueabi-ldd
-r-xr-xr-x 2 crifan crifan 617K Aug
8 01:10 arm-xscale-linux-gnueabi-nm
-r-xr-xr-x 2 crifan crifan 775K Aug
8 01:10 arm-xscale-linux-gnueabi-objcopy
-r-xr-xr-x 2 crifan crifan 943K Aug
8 01:10 arm-xscale-linux-gnueabi-objdump
-r-xr-xr-x 1 crifan crifan
8 01:10 arm-xscale-linux-gnueabi-populate
-r-xr-xr-x 2 crifan crifan 633K Aug
8 01:10 arm-xscale-linux-gnueabi-ranlib
-r-xr-xr-x 1 crifan crifan 317K Aug
8 01:10 arm-xscale-linux-gnueabi-readelf
-r-xr-xr-x 1 crifan crifan 609K Aug
8 01:10 arm-xscale-linux-gnueabi-size
-r-xr-xr-x 1 crifan crifan 605K Aug
8 01:10 arm-xscale-linux-gnueabi-strings
-r-xr-xr-x 2 crifan crifan 775K Aug
8 01:10 arm-xscale-linux-gnueabi-strip
crifan@ubuntu:~/develop/crosstool-ng/crosstool-ng-1.18.0_build$然后,你把包含了上述arm-xscale-linux-gnueabi-gcc等文件的路径,加到环境变量PATH中,然后就可以使用了。已验证和测试别人发布的,交叉编译器,一般都是,经过相应的验证和测试保证了,可以使用,不会出问题的。所以,你可以放心使用,不会担心,出现编译程序出错的时候,确保不会是由于交叉编译器问题。已优化别人发布的交叉编译器,一般都是经过,在制作的时候,加了一些优化参数使得针对某些方面,比如性能等等,做了相应的优化使得,交叉编译器编译出来的程序,对于目标的CPU,是相对最优的(售后)支持比较好就像你买东西,很多时候,不出问题的时候,售后,看不出有啥用但是当出问题,就发现,售后其实很重要而搞嵌入式开发,尤其是交叉编译很多时候,涉及到很多技术细节有时候遇到问题的话,如果你不熟悉,不了解,不会解决这时候,去找到,交叉编译器的提供者,去咨询对于你来说,就显得很有价值,很重要了。别人提供的交叉编译器的话,往往都是提供后续的技术支持的对于多数的开发者,这点,还是有价值的3.4.2. 使用已有交叉编译器的缺点无针对你自己的CPU的优化别人提供的,已有的交叉编译器,相对来说,更多时候,都是针对某个系列的CPU,进行制作出来的,进行优化的即,其优化,也是相对比较通用的如果你的CPU和其不同,则其就没有对应的优化了专有化和上面有点类似,即没有针对你自己的CPU,进行优化太老,太旧别人给的,网上可以下载到的,很多交叉编译器,相对来说,版本都比较旧了,都是很老的,之前的了其所用的,其他各个组件,模块,也都是旧版本的旧的软件,对于新出来的CPU,新的功能等,自然没有对应的支持也就无法发挥新的硬件特性了了其所用的源码不清楚别人给你编译好的交叉编译器,你是可以用了但是,其针对于具体什么版本的源码,以及是否打了相应补丁等情况你是无法,也很难知道的所以,即无法掌控此已有交叉编译器的所用的源码的确切情况此点,针对于你对自己的CPU很熟悉的情况下,想要完全了解已有交叉编译器的背后的情况而言,算是个缺点即不能完全在你掌握范围内,不清楚后面的情况未必适合你的系统或许是不可重载(relocatable)的没有很方便的方式去获得一些系统库文件所以,未必真正适合你自己的,嵌入式系统环境3.4.3. 自己手动编译交叉编译器的优点自定义各种组件及版本对于自己去制作交叉编译器的话,则其所用的各种组件,模块的版本,都可以自己选择和定制针对你自己的CPU进行特定的优化对于各种补丁包,已经很清楚了既然是自己制作交叉编译器,那么自然选择了,相对较新的源码包,以及各种模块其自然,已经现存有很多补丁包这些补丁包,修复了很多bug,或者是增加了很多新的功能支持等这时候,你就可以找到并打上这些补丁包以实现,修复该模块的已知的bug,增加新的功能的支持了Same source for all targets暂未搞懂此点的确切含义。可以同步更新最新补丁相应的,如果有最新的补丁,也可以及时打上可重复对于自己制作交叉编译器的话,制作完成后,就确定了对应的各个模块的版本,有了对应的配置文件此配置,拿到别的地方,别人用同样的工具和类似的环境,是可以重新编译为其自己的即,所谓的可重复,别人可以利用你已经验证,可以正常制作和使用的各个版本的模块和配置,实现自己也制作一个属于自己的交叉编译器有社区支持当然,对应的,在制作交叉编译器期间,使用交叉编译器期间,出了问题,有任何疑问,都有对应的社区的,热心人,帮你解决,回答你的问题。适合你自己的系统如前所述,拿别人已制作好的交叉编译器,未必真正完全适合你自己的系统而如果你自己制作的话,当然就完全根据自己的需求,去制作出最适合自己的系统的交叉编译器了3.4.4. 自己手动编译交叉编译器的缺点制作交叉编译器相对比较复杂制作交叉编译器,相对来说,是个技术活加体力活不仅仅要求有对应的知识背景,解决各种问题的能力,还要准备一定的时间和精力,去真正实现,真正去建立出来一个可用的交叉编译器可能存在的,对于你的处理器支持度不是足够好既然制作交叉编译器期间,可能需要打上很多的patch等等那也就存在,比如缺少了对应的补丁,补丁不太完整,补丁不合适等等特殊情况使得,对于对应的,有些处理器,支持度,不是很好验证在制作出了交叉编译器后,其实还需要一定的验证,保证其可用,好用。这也需要对应的技术能力,和精力,去实现。社区的支持对于社区的支持,有其之前所说的优点,那就是,社区活跃的话,可能解决问题的效率就相对较高但是当社区不够活跃,社区中没有合适的人,那么可能你的问题,就很难得到解决即,有问题的时候,依靠社区去解决,未必是完全靠谱的。第 4 章 交叉编译心得和注意事项目录4.1. 交叉编译心得和注意事项4.1. 交叉编译心得和注意事项待整理:相关旧帖:参考书目[1] [2] [光盘下载] 2010年6月 最新TQ2440光盘下载 (Linux内核,WinCE的eboot,uboot均有更新)[3] [4] [5] [6] [7] [8] [9] [10] [11] [12] 【整理】关于Toolchain,cross toolchain,cross compiler[13] [14] [15] 【整理】crosstool中如何设置xscale的Tuple’s vendor string(CT_TARGET_VENDOR)[16] [17] 【已解决】uboot交叉编译出错:gcc/config/arm/lib1funcs.asm:1266: undefined reference to `raise’[18] [19] [20] [21] [22] [23] [24]
如果您想留下此文,您可以将其发送至您的邮箱(将同时以邮件内容&PDF形式发送)
相关文章推荐
(Ctrl+Enter提交) &&
已有0人在此发表见解
&在& 15:17收藏到了
&&在信息爆炸的时代,您的知识需要整理,沉淀,积累!Lai18为您提供一个简单实用的文章整理收藏工具,在这里您可以收藏对您有用的技术文章,自由分门别类,在整理的过程中,用心梳理自己的知识!相信,用不了多久,您收藏整理的文章将是您一生的知识宝库!
· 蜀ICP备号-1

我要回帖

更多关于 gnu汇编全局变量.word 的文章

 

随机推荐