【转】如何为嵌入式开发建立交叉编译环境
2009年10月26日
如何为嵌入式开发建立交叉编译环境
级别: 初级
恩 梁元 (www.kernel.org 下载的内核源代码放入 $PRJROOT /kernel 目录
进入你的 kernel 目录:
$cd $PRJROOT /kernel
解开内核源代码
$tar -xzvf linux-2.4.21.tar.gz
或
$tar -xjvf linux-2.4.21.tar.bz2
小于 2.4.19 的内核版本解开会生成一个 linux 目录,没带版本号,就将其改名。
$mv linux linux-2.4.x
给 Linux 内核打上你的补丁
$cd linux-2.4.21$patch -p1
建立二进制工具(binutils)
binutils是一些二进制工具的集合,其中包含了我们常用到的as和ld。
首先,我们解压我们下载的binutils源文件。
$cd $PRJROOT/build-tools
$tar -xvjf binutils-2.10.1.tar.bz2
然后进入build-binutils目录配置和编译binutils。
$cd build-binutils
$../binutils-2.10.1/configure --target=$TARGET --prefix=$PREFIX
--target 选项是指出我们生成的是 arm-linux 的工具,--prefix 是指出我们可执行文件安装的位置。
会出现很多 check,最后产生 Makefile 文件。
有了 Makefile 后,我们来编译并安装 binutils,命令很简单。
$make
$make install
看一下我们 $PREFIX/bin 下的生成的文件
$ls $PREFIX/bin
arm-linux-addr2line arm-linux-gasp arm-linux-objdump arm-linux-stringsarm-linux-ar arm-linux-ld arm-linux-ranlib arm-linux-striparm-linux-as arm-linux-nm arm-linux-readelf arm-linux-c++filt arm-linux-objcopy arm-linux-size
我们来解释一下上面生成的可执行文件都是用来干什么的
add2line - 将你要找的地址转成文件和行号,它要使用 debug 信息。
Ar-产生、修改和解开一个存档文件
As-gnu 的汇编器
C++filt-C++ 和 java 中有一种重载函数,所用的重载函数最后会被编译转化成汇编的标号,c++filt 就是实现这种反向的转化,根据标号得到函数名。
Gasp-gnu 汇编器预编译器。
Ld-gnu 的连接器
Nm-列出目标文件的符号和对应的地址
Objcopy-将某种格式的目标文件转化成另外格式的目标文件
Objdump-显示目标文件的信息
Ranlib-为一个存档文件产生一个索引,并将这个索引存入存档文件中
Readelf-显示 elf 格式的目标文件的信息
Size-显示目标文件各个节的大小和目标文件的大小
Strings-打印出目标文件中可以打印的字符串,有个默认的长度,为4
Strip-剥掉目标文件的所有的符号信息
建立初始编译器(bootstrap gcc)
首先进入 build-tools 目录,将下载 gcc 源代码解压
$cd $PRJROOT/build-tools
$tar -xvzf gcc-2.95.3.tar.gz
然后进入 gcc-2.95.3 目录给 gcc 打上补丁
$cd gcc-2.95.3
$patch -p1 gcc/cstamp-h.in
在我们编译并安装 gcc 前,我们先要改一个文件 $PRJROOT/gcc/config/arm/t-linux,把
TARGET_LIBGCC2-CFLAGS = -fomit-frame-pointer -fPIC
这一行改为
TARGET_LIBGCC2-CFLAGS = -fomit-frame-pointer -fPIC -Dinhibit_libc -D__gthr_posix_h
你如果没定义 -Dinhibit,编译时将会报如下的错误
../../gcc-2.95.3/gcc/libgcc2.c:41: stdlib.h: No such file or directory
../../gcc-2.95.3/gcc/libgcc2.c:42: unistd.h: No such file or directory
make[3]: *** [libgcc2.a] Error 1
make[2]: *** [stmp-multilib-sub] Error 2
make[1]: *** [stmp-multilib] Error 1
make: *** [all-gcc] Error 2
如果没有定义 -D__gthr_posix_h,编译时会报如下的错误
In file included from gthr-default.h:1, from ../../gcc-2.95.3/gcc/gthr.h:98, from ../../gcc-2.95.3/gcc/libgcc2.c:3034:../../gcc-2.95.3/gcc/gthr-posix.h:37: pthread.h: No such file or directory
make[3]: *** [libgcc2.a] Error 1
make[2]: *** [stmp-multilib-sub] Error 2
make[1]: *** [stmp-multilib] Error 1
make: *** [all-gcc] Error 2
还有一种与-Dinhibit同等效果的方法,那就是在你配置configure时多加一个参数-with-newlib,这个选项不会迫使我们必须使用newlib。我们编译了bootstrap-gcc后,仍然可以选择任何c库。
接着就是配置boostrap gcc, 后面要用bootstrap gcc 来编译 glibc 库。
$cd ..;
cd build-boot-gcc
$../gcc-2.95.3/configure --target=$TARGET --prefix=$PREFIX >--without-headers --enable-languages=c --disable-threads
这条命令中的 -target、--prefix 和配置 binutils 的含义是相同的,--without-headers 就是指不需要头文件,因为是交叉编译工具,不需要本机上的头文件。-enable-languages=c是指我们的 boot-gcc 只支持 c 语言。--disable-threads 是去掉 thread 功能,这个功能需要 glibc 的支持。
接着我们编译并安装 boot-gcc
$make all-gcc
$make install-gcc
我们来看看 $PREFIX/bin 里面多了哪些东西
$ls $PREFIX/bin
你会发现多了 arm-linux-gcc 、arm-linux-unprotoize、cpp 和 gcov 几个文件。
Gcc-gnu 的 C 语言编译器
Unprotoize-将 ANSI C 的源码转化为 K&R C 的形式,去掉函数原型中的参数类型。
Cpp-gnu的 C 的预编译器
Gcov-gcc 的辅助测试工具,可以用它来分析和优程序。
使用 gcc3.2 以及 gcc3.2 以上版本时,配置 boot-gcc 不能使用 --without-headers 选项,而需要使用 glibc 的头文件。
建立 c 库(glibc)
首先解压 glibc-2.2.3.tar.gz 和 glibc-linuxthreads-2.2.3.tar.gz 源代码
$cd $PRJROOT/build-tools
$tar -xvzf glibc-2.2.3.tar.gz
$tar -xzvf glibc-linuxthreads-2.2.3.tar.gz --directory=glibc-2.2.3
然后进入 build-glibc 目录配置 glibc
$cd build-glibc
$CC=arm-linux-gcc ../glibc-2.2.3/configure --host=$TARGET --prefix="/usr" --enable-add-ons --with-headers=$TARGET_PREFIX/include
CC=arm-linux-gcc 是把 CC 变量设成你刚编译完的boostrap gcc,用它来编译你的glibc。--enable-add-ons是告诉glibc用 linuxthreads 包,在上面我们已经将它放入了 glibc 源码目录中,这个选项等价于 -enable-add-ons=linuxthreads。--with-headers 告诉 glibc 我们的linux 内核头文件的目录位置。
配置完后就可以编译和安装 glibc
$make
$make install_root=$TARGET_PREFIX prefix="" install
然后你还要修改 libc.so 文件
将
GROUP ( /lib/libc.so.6 /lib/libc_nonshared.a)
改为
GROUP ( libc.so.6 libc_nonshared.a)
这样连接程序 ld 就会在 libc.so 所在的目录查找它需要的库,因为你的机子的/lib目录可能已经装了一个相同名字的库,一个为编译可以在你的宿主机上运行的程序的库,而不是用于交叉编译的。
建立全套编译器(full gcc)
在建立boot-gcc 的时候,我们只支持了C。到这里,我们就要建立全套编译器,来支持C和C++。
$cd $PRJROOT/build-tools/build-gcc
$../gcc-2.95.3/configure --target=$TARGET --prefix=$PREFIX --enable-languages=c,c++ --enable-languages=c,c++ 告诉 full gcc 支持 c 和 c++ 语言。
然后编译和安装你的 full gcc
$make all
$make install
我们再来看看 $PREFIX/bin 里面多了哪些东西
$ls $PREFIX/bin
你会发现多了 arm-linux-g++ 、arm-linux-protoize 和 arm-linux-c++ 几个文件。
G++-gnu的 c++ 编译器。
Protoize-与Unprotoize相反,将K&R C的源码转化为ANSI C的形式,函数原型中加入参数类型。
C++-gnu 的 c++ 编译器。
到这里你的交叉编译工具就算做完了,简单验证一下你的交叉编译工具。
用它来编译一个很简单的程序 helloworld.c
#include
int main(void)
{
printf("hello world");
return 0;
}
$arm-linux-gcc helloworld.c -o helloworld
$file helloworld
helloworld: ELF 32-bit LSB executable, ARM, version 1, dynamically linked (uses shared libs), not stripped
上面的输出说明你编译了一个能在 arm 体系结构下运行的 helloworld,证明你的编译工具做成功了。
参考资料
Wookey ,Chris Rutter, Jeff Sutherland, Paul Webb ,《The GNU Toolchain for ARM Target HOWTO》
Karim Yaghmour,《Building Embedded Linux Systems》,USA:O'Reilly,2003
d-gnu 的连接器
Nm-列出目标文件的符号和对应的地址
Objcopy-将某种格式的目标文件转化成另外格式的目标文件
Objdump-显示目标文件的信息
Ranlib-为一个存档文件产生一个索引,并将这个索引存入存档文件中
Readelf-显示 elf 格式的目标文件的信息
Size-显示目标文件各个节的大小和目标文件的大小
Strings-打印出目标文件中可以打印的字符串,有个默认的长度,为4
Strip-剥掉目标文件的所有的符号信息
建立初始编译器(bootstrap gcc)
首先进入 build-tools 目录,将下载 gcc 源代码解压
$cd $PRJROOT/build-tools
$tar -xvzf gcc-2.95.3.tar.gz
然后进入 gcc-2.95.3 目录给 gcc 打上补丁
$cd gcc-2.95.3
$patch -p1 gcc/cstamp-h.in
在我们编译并安装 gcc 前,我们先要改一个文件 $PRJROOT/gcc/config/arm/t-linux,把
TARGET_LIBGCC2-CFLAGS = -fomit-frame-pointer -fPIC
这一行改为
TARGET_LIBGCC2-CFLAGS = -fomit-frame-pointer -fPIC -Dinhibit_libc -D__gthr_posix_h
你如果没定义 -Dinhibit,编译时将会报如下的错误
../../gcc-2.95.3/gcc/libgcc2.c:41: stdlib.h: No such file or directory
../../gcc-2.95.3/gcc/libgcc2.c:42: unistd.h: No such file or directory
make[3]: *** [libgcc2.a] Error 1
make[2]: *** [stmp-multilib-sub] Error 2
make[1]: *** [stmp-multilib] Error 1
make: *** [all-gcc] Error 2
如果没有定义 -D__gthr_posix_h,编译时会报如下的错误
In file included from gthr-default.h:1, from ../../gcc-2.95.3/gcc/gthr.h:98, from ../../gcc-2.95.3/gcc/libgcc2.c:3034:../../gcc-2.95.3/gcc/gthr-posix.h:37: pthread.h: No such file or directory
make[3]: *** [libgcc2.a] Error 1
make[2]: *** [stmp-multilib-sub] Error 2
make[1]: *** [stmp-multilib] Error 1
make: *** [all-gcc] Error 2
还有一种与-Dinhibit同等效果的方法,那就是在你配置configure时多加一个参数-with-newlib,这个选项不会迫使我们必须使用newlib。我们编译了bootstrap-gcc后,仍然可以选择任何c库。
接着就是配置boostrap gcc, 后面要用bootstrap gcc 来编译 glibc 库。
$cd ..;
cd build-boot-gcc
$../gcc-2.95.3/configure --target=$TARGET --prefix=$PREFIX >--without-headers --enable-languages=c --disable-threads
这条命令中的 -target、--prefix 和配置 binutils 的含义是相同的,--without-headers 就是指不需要头文件,因为是交叉编译工具,不需要本机上的头文件。-enable-languages=c是指我们的 boot-gcc 只支持 c 语言。--disable-threads 是去掉 thread 功能,这个功能需要 glibc 的支持。
接着我们编译并安装 boot-gcc
$make all-gcc
$make install-gcc
我们来看看 $PREFIX/bin 里面多了哪些东西
$ls $PREFIX/bin
你会发现多了 arm-linux-gcc 、arm-linux-unprotoize、cpp 和 gcov 几个文件。
Gcc-gnu 的 C 语言编译器
Unprotoize-将 ANSI C 的源码转化为 K&R C 的形式,去掉函数原型中的参数类型。
Cpp-gnu的 C 的预编译器
Gcov-gcc 的辅助测试工具,可以用它来分析和优程序。
使用 gcc3.2 以及 gcc3.2 以上版本时,配置 boot-gcc 不能使用 --without-headers 选项,而需要使用 glibc 的头文件。
建立 c 库(glibc)
首先解压 glibc-2.2.3.tar.gz 和 glibc-linuxthreads-2.2.3.tar.gz 源代码
$cd $PRJROOT/build-tools
$tar -xvzf glibc-2.2.3.tar.gz
$tar -xzvf glibc-linuxthreads-2.2.3.tar.gz --directory=glibc-2.2.3
然后进入 build-glibc 目录配置 glibc
$cd build-glibc
$CC=arm-linux-gcc ../glibc-2.2.3/configure --host=$TARGET --prefix="/usr" --enable-add-ons --with-headers=$TARGET_PREFIX/include
CC=arm-linux-gcc 是把 CC 变量设成你刚编译完的boostrap gcc,用它来编译你的glibc。--enable-add-ons是告诉glibc用 linuxthreads 包,在上面我们已经将它放入了 glibc 源码目录中,这个选项等价于 -enable-add-ons=linuxthreads。--with-headers 告诉 glibc 我们的linux 内核头文件的目录位置。
配置完后就可以编译和安装 glibc
$make
$make install_root=$TARGET_PREFIX prefix="" install
然后你还要修改 libc.so 文件
将
GROUP ( /lib/libc.so.6 /lib/libc_nonshared.a)
改为
GROUP ( libc.so.6 libc_nonshared.a)
这样连接程序 ld 就会在 libc.so 所在的目录查找它需要的库,因为你的机子的/lib目录可能已经装了一个相同名字的库,一个为编译可以在你的宿主机上运行的程序的库,而不是用于交叉编译的。
建立全套编译器(full gcc)
在建立boot-gcc 的时候,我们只支持了C。到这里,我们就要建立全套编译器,来支持C和C++。
$cd $PRJROOT/build-tools/build-gcc
$../gcc-2.95.3/configure --target=$TARGET --prefix=$PREFIX --enable-languages=c,c++ --enable-languages=c,c++ 告诉 full gcc 支持 c 和 c++ 语言。
然后编译和安装你的 full gcc
$make all
$make install
我们再来看看 $PREFIX/bin 里面多了哪些东西
$ls $PREFIX/bin
你会发现多了 arm-linux-g++ 、arm-linux-protoize 和 arm-linux-c++ 几个文件。
G++-gnu的 c++ 编译器。
Protoize-与Unprotoize相反,将K&R C的源码转化为ANSI C的形式,函数原型中加入参数类型。
C++-gnu 的 c++ 编译器。
到这里你的交叉编译工具就算做完了,简单验证一下你的交叉编译工具。
用它来编译一个很简单的程序 helloworld.c
#include
int main(void)
{
printf("hello world");
return 0;
}
$arm-linux-gcc helloworld.c -o helloworld
$file helloworld
helloworld: ELF 32-bit LSB executable, ARM, version 1, dynamically linked (uses shared libs), not stripped
上面的输出说明你编译了一个能在 arm 体系结构下运行的 helloworld,证明你的编译工具做成功了。
参考资料
Wookey ,Chris Rutter, Jeff Sutherland, Paul Webb ,《The GNU Toolchain for ARM Target HOWTO》
Karim Yaghmour,《Building Embedded Linux Systems》,USA:O'Reilly,2003
发表评论
-
Sharepoint+MOSS分册第2轮筛选结果文章列表
2012-01-20 00:34 731Sharepoint+MOSS分册第2轮筛 ... -
在 Android 平台上应用 Berkeley DB 11gR2 SQL(drop-in模式)(转http://www.cnmsdn.com/html/201004/1270362092ID3134.html)
2012-01-20 00:34 787在 Android 平台上应用 Ber ... -
编程心得
2012-01-20 00:34 680编程心得 2011年03月21日 转自:http://w ... -
在 C# 中通过 P/Invoke 调用Win32 DLL
2012-01-20 00:34 766在 C# 中通过 P/Invoke 调用Win32 DLL ... -
http://www.cnblogs.com/yungboy/archive/2010/05/28/1746376.html
2012-01-20 00:33 867http://www.cnblogs.com/yungboy/ ... -
10] 建立C帝国(GDAL编译安装以及一般的C库编译步骤)
2012-01-19 01:31 88910] 建立C帝国(GDAL编译安 ... -
Android开发之Android体系架构介绍
2012-01-19 01:31 1566Android开发之Android体系 ... -
EGLIBC库介绍
2012-01-19 01:31 603EGLIBC库介绍 2011年05月05 ... -
给Win32 GUI程序调试信息输出方法
2012-01-19 01:31 1357给Win32 GUI程序调试信息输出方法 2011年09月2 ... -
SAMSUNG S3C2440的简易BootLoader ㈢
2012-01-19 01:31 608SAMSUNG S3C2440的简易BootLoa ... -
Application/Session/Cookie/viewstate/Cache/隐藏域/查询字符串的比较
2012-01-17 00:48 650Application/Session/Cookie/view ... -
v4l2驱动编写篇(2)
2012-01-17 00:48 1188v4l2驱动编写篇(2) 2011年04月01日 应用可 ... -
file_operation结构体详解
2012-01-17 00:48 1012file_operation结构体详解 2011年06月22 ... -
电脑蓝屏自动关机故障的检修方法
2012-01-17 00:48 657电脑蓝屏自动关机故障的检修方法 2011年09月23日 ... -
Video4Linux
2012-01-17 00:48 777Video4Linux 2011年12月05日 Vide ... -
HK-2000数据采集仪WEB服务器BOA的移植方法
2012-01-15 19:37 686HK-2000数据采集仪WEB服务器BOA的移植方法 200 ... -
如何为linux嵌入式开发建立交叉编译环境(2.4内核)
2012-01-15 19:36 699如何为linux嵌入式开发建立交叉编译环境(2.4内核) 2 ... -
EGLIBC库介绍
2012-01-15 19:36 550EGLIBC库介绍 2011年05月05 ... -
c库函数qsort使用方法实例
2012-01-15 19:36 549c库函数qsort使用方法实例 2010年01月03日 ...
相关推荐
嵌入式开发Linux交叉编译环境建立,通俗易懂,容易上手
在Linux嵌入式开发中,为了在高性能的PC上构建适用于目标嵌入式设备的软件,我们需要建立一个交叉编译环境。这个环境包括一套编译器、链接器以及libc库,允许在不同架构之间进行编译。本文将基于2.4内核的Linux系统...
在Linux嵌入式开发中,建立交叉编译环境是一个至关重要的步骤,因为它允许开发者在功能强大的主机系统上构建适用于目标嵌入式设备的代码。交叉编译环境包括一系列工具,如编译器、链接器以及libc库,这些工具都是...
这里主要介绍如何建立交叉编译环境,因为嵌入式设备通常使用与开发主机不同的处理器架构,所以需要在主机上使用交叉编译工具链来生成能在目标设备上运行的代码。 首先,嵌入式开发通常基于Linux操作系统,因为Linux...
【建立交叉编译环境】 建立面向ARM的交叉编译环境涉及多个步骤: 1. **准备工作**:首先确定开发环境,比如本文中提到的宿主机是运行Debian 4.0的PC,目标板采用的是ARM9处理器(如Samsung S3C2410)。下载必要的...
这篇文档将详细阐述如何搭建一个嵌入式开发的交叉编译环境,主要涉及的步骤包括选择合适的软件版本、建立工作目录、配置环境变量、编译各个组件,以及最终构建完整的工具链。 首先,你需要确定所使用的软件版本。...
建立交叉编译环境 启动代码Bootloader的实现/移植 kernel的配置/移植/编译 根文件系统Crbmfs的实现
在嵌入式开发领域,搭建一个稳定可靠的交叉编译环境对于开发过程至关重要。Ubuntu 14.04作为一款稳定和广泛使用的Linux发行版,常被嵌入式开发者选作开发环境的基础。交叉编译环境使得开发者可以在一个与目标嵌入式...
交叉编译是嵌入式开发过程中的一项重要技术,它的主要特征是某机器中执行的程序代码不是在本...在裁减和定制Linux运用于你的嵌入式系统之前,通常你都要在你的强大的pc机(主机)上建立一个用于目标机的交叉编译环境。
构建嵌入式Linux交叉编译环境是一项复杂但至关重要的工作,它为后续的嵌入式Linux开发奠定了坚实的基础。通过按照上述步骤逐步实施,并注意各组件间的兼容性和目标架构的特殊需求,可以成功构建出稳定可靠的交叉编译...
该平台通常包括嵌入式Linux操作系统、交叉编译环境、开发工具和目标板等组件。嵌入式Linux开发平台的主要特点是跨平台移植性强、灵活性高、开发效率高、成本低等。 嵌入式Linux开发流程: 嵌入式Linux开发流程可以...
编译 binutils 是建立交叉编译环境的重要步骤之一。 ##### 4. 建立初始编译器 (bootstrapgcc) 构建初始的 GCC 编译器是为了后续能够编译 glibc。 ##### 5. 建立 C 库 (glibc) Glibc 是 Linux 系统中最常用的 C ...
==怎样为Linux内核打补丁.pdf ==自己实验建立交叉编译工具链.pdf ==交叉编译场景(arm-linux)分析.pdf ==如何为嵌入式开发建立交叉编译环境.pdf ==Ubuntu 9.10上建立ARM-Linux交叉编译环境.pdf
搭建嵌入式Linux的交叉编译环境是开发过程的关键步骤,它涉及选择合适的交叉编译工具、配置主机环境、建立与目标机的通信机制。通过这个过程,开发者可以在主机上编写和调试代码,然后将其部署到目标机上运行,从而...