搭建Linux交叉编译开发环境 您所在的位置:网站首页 交叉编译器如何构建程序 搭建Linux交叉编译开发环境

搭建Linux交叉编译开发环境

2024-07-04 16:26| 来源: 网络整理| 查看: 265

搭建Linux交叉开发环境 一、建立交叉编译开发工具链1.1 编译工具链1.1.1 下载源文件、补丁和建立编译的目录1.1.2 建立内核头文件1.1.3 建立二进制工具(binutils)1.1.4 建立初始编译器(bootstrap gcc)1.1.5 建立C库(glibc)1.1.6 建立全套编译器(full gcc) 1.2 下载工具链1.3 验证工具链 二、配置主机服务2.1 配置samba2.2 配置DHCP2.3 配置TFTP2.4 配置NFS

交叉编译指在一个平台上生成另一个平台可执行的代码,这里的平台包括体系结构(Architecture)和操作系统(Operating System)。同一个体系结构可以运行不同的操作系统,且同一个操作系统也可以在不同体系结构上运行。本文从两个方面讲解如何搭建Linux交叉开发环境。在两种情况下,通常需要交叉编译:第一,在项目的起始阶段,目标平台还没有建立,此时需要进行交叉编译,以生成所需的bootloader(启动引导代码)以及操作系统核心;第二,当目标平台能启动后,由于目标平台上的资源有限,当编译大型程序时,有可能也需要交叉编译。 一、建立交叉编译开发工具链 建立交叉编译开发工具链有两种方法:手动编译一个工具链和直接下载制作好的工具链。 1.1 编译工具链 在进行嵌入式开发前,需要建立一套由编译器、连接器和libc库等构成的交叉编译环境。下面以建立针对ARM的交叉编译开发环境为例来讲解,注意本文采用的开发环境式宿主机为i386-redhat-9.0、目标机为ARM。整个编译过程包括:(1)下载源文件、补丁和建立编译的目录;(2)建立内核头文件;(3)建立二进制工具(binutils);(4)建立初始编译器(bootstrap gcc);(5)建立C库(glibc);(6)建立全套编译器(full gcc)。 1.1.1 下载源文件、补丁和建立编译的目录 (1)选定软件的版本号。先查看glibc代码中的INSTALL文件,该文件中列举了本版本的glibc编译时所需要的binutils和gcc的版本号。本文采用的软件本文为:linux-2.4.21+rmk2;gcc-2.95.3;glibc-2.2.3;glibc-linuxthreads-2.2.3。Linux内核可以从www.kernel.org网站上下载。binutils、gcc和glibc可以从FSF的FTP站点(http://ftp.gnu.org/gnu/)下载。在编译glibc时,需要到Linux内核中的include目录的内核头文件。gcc推荐使用gcc-2.95以上版本,太老的版本在编译时可能出现问题,gcc-2.95.3是一个比较稳定的版本,也是内核开发人员推荐使用的。另外,太新的版本大多数没有经过大量的测试,建议不要选用。(2)建立几个用来工作的目录。假设用户目录为/home/liang,则建立一个项目目录embedded:$pwd/home/liang$mkdir embedded然后,在这个项目目录embedded下建立3个子目录build-tools、kernel和tools。build-tools用来存放下载的binutils、gcc和glibc的源代码以及编译这些源代码的目录。kernel用来存放内核代码和内核补丁。tools用来存放编译好的交叉编译工具和库文件,指令如下:$cd /home/liang/embedded$mkdir build-tools kernel tools执行完上述命令后,目录结构如下:$ls embeddedbuild-tools kernel tools紧接着,需要输出环境变量,输入如下环境变量以便编译:$export PRJROOT=/home/liang/embedded$export TARGET=arm-linux$export PREFIX=$PRJROOT/tools$export TARGET_PREFIX=$PREFIX/$TARGET$export PATH=$PREFIX/bin:$PATH如果不想用环境变量,也可以直接采用绝对路径。环境变量也可以定义在.bashrc文件中,这样当logout或换了控制台时,就不用总是export这些变量了。体系结构和TARGET变量对应值下表所示: 体系结构TARGETPowerPCPowerpc-linuxARMarm-linuxMIPS(big endian)mips-linuxMIPS(little endian)mipsel-linuxMIPS64mips64-linuxSuperH3sh3-linuxSuperH4sh4-linuxI386i386-linuxIa64ia64-linuxM68km68k-linuxM88km88k-linuxAlphaalpha-linuxSparcsparc-linuxSparc64sparc64-linux 可以在通过glibc下的config.sub脚本来之道所选用的TARGET变量是否被支持,例如:$./config.sub arm-linux上述环境中,config.sub在glibc-2.2.3/scripts目录下。(3)建立编译目录。为了把源代码和编译时生成的文件分开,通常编译工作不在源码目录中进行,需要新建一个目录专门用来编译。用如下的命令来建立编译下载的binutils、gcc和glibc的源代码的目录:$cd $PRJROOT/build-tools$mkdir build-binutils build-boot-gcc build-gcc build-glibc gcc-patch其中,build-binutils——编译binutils的目录;build-boot-gcc——编译gcc启动部分的目录;build-glibc——编译glibc的目录;build-gcc——编译gcc全部目录;gcc-patch——存放gcc的补丁的目录。gcc-2.95.3的补丁包括gcc-2.95.3-2.patch、gcc-2.95.3-no-fixinc.patch和gcc-2.95.3-returntype-fix.patch,这些均可以从“http://www.linuxfromscratch.org”下载这些补丁。再将下载的binutils-2.10.1、gcc-2.95.3、glibc-2.2.3和glibc-linuxthreads-2.2.3的源代码放入build-tools目录中。build-tools目录的内容包含如下:$lsbinutils-2.10.1.tar.bz2 build-gcc gcc-patchbuild-binutils build-glibc glibc-2.2.3.tar.gzbuild-boot-gcc gcc-2.95.3.tar.gz glibc-linuxthreads-2.2.3.tar.gz 1.1.2 建立内核头文件 (1)把从“www.kernel.org”下载的内核源代码放入到$PRJROOT/kernel目录。进入kernel目录:$cd $PRJROOT /kernel解压内核源代码:$tar -xzvf linux-2.4.21.tar.gz或者$tar -xjvf linux-2.4.21.tar.gz给Linux内核打上补丁:$cd linux-2.4.21$patch -p1 < ../patch-2.4.21-rmk2编译内核生成头文件:$make ARCH=arm CROSS_COMPILE=arm-linux- menuconfig配置完成后保存并退出,检查内核目录中是否生成include/linux/version.h和/include/linux/autoconf.h文件,它们两个是编译glibc时需要用到的,如果这两个文件存在就说明生成了正确的头文件。(2)紧接着,需要建立几个正确的链接:$cd include$ln -s asm-arm asm$cd asm$ln -s arch-epxa arch$ln -s proc-armv proc执行完,这几条命令后,即可以为交叉编译环境建立内核头文件链接了,代码如下:$mkdir -p $TARGET_PREFIX/include$ln -s $PRJROOT/kernel/linux-2.4.21/include/linux $TARGET_PREFIX/include/linux$ln -s $PRJROOT/kernel/linux-2.4.21/include/asm-arm$TARGET_PREFIX/include/asm 1.1.3 建立二进制工具(binutils) binutils是一些二进制工具的集合,其中包含了一些常用的as和ld。解压下载的binutils源文件:$cd $PRJROOT/build-tools$tar -xjvf 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/binarm-linux-addr2line arm-linux-objecopy arm-linux-ar arm-linux-objdump arm-linux-as arm-linux-ranlib arm-linux-c++filt arm-linux-readelf arm-linux-gasp arm-linux-size arm-linux-ld arm-linux-strings arm-linux-nm arm-linux-strip其中,addr2line——将要照的地址转换为文件和行号,它要使用debug信息;objcopy——将某种格式的目标文件转换为另一种格式的目标文件;ar——生成、修改和解压一个存档文件;objdump——显示目标文件的信息;as——gnu的汇编器;ranlib——为一个存档文件生成一个索引,并将这些索引存入存档文件中;c++filt——C++和java中由一种重载函数,所用的重载函数最后会被编译转换为汇编的标号,c++filt就是实现这种反向的转换,并根据标号得到函数名;readelf——显示elf格式的目标文件的信息;gasp——gnu汇编器的预编译器;size——显示目标文件各个节与目标文件的大小;ld——gnu的连接器;strings——打印出目标文件中可以打印的字符串,默认长度为4;nm——罗列目标文件的符号与对应地址;strip——去掉目标文件的所有符号信息。 1.1.4 建立初始编译器(bootstrap gcc) 注意,在编译和安装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。(1)进入build-tools目录,下载gcc源代码并解压:$cd $PRJROOT/build-tools$tar -xvzf gcc-2.95.3.tar.gz(2)进入gcc-2.95.3目录,给gcc打上补丁:$cd gcc-2.95.3$patch -pl< ../gcc-patch/gcc-2.95.3.-2.patch$patch -pl< ../gcc-patch/gcc-2.95.3.-no-fixinc.patch$patch -pl< ../gcc-patch/gcc-2.95.3-returntype-fix.patch$echo timestamp > gcc/cstamp-h.in(3)配置bootstrap 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的支持。(4)编译和安装boot-gcc$make all-gcc$make install-gcc下面罗列出$PREFIX/bin中多出来的文件:$ls $PREFIX/binarm-linux-gcc arm-linux-unprotoize cpp gcov其中,gcc——gnu的C语言编译器;unprotoize——将ANSI C的代码转换为K&R C的形式,即去掉函数原型的参数类型;cpp——gnu的C语言预编译器;gcov——gcc的辅助测试工具,可以用来分析和优化程序。注意!在使用gcc3.2以上版本(包括自己)时,配置boot-gcc时不能使用–without-headers选项,因为需要使用glibc的头文件。 1.1.5 建立C库(glibc) (1)解压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 -xvzf glibc-linuxthreads-2.2.3.tar.gz --directory=glibc-2.2.3(2)进入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变量设置为编译后的bootstrap gcc,用它来编译glibc;“–enable-add-ons”表示glibc采用放入glibc源码目录中的linuxthreads包,该命令等价于“-enable-add-ons=linuxthreads”;“–with-headers”表示glibc linux内核头文件的目录位置。(3)编译和安装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)。 1.1.6 建立全套编译器(full gcc) (1)建立全套编辑器,此处需要支持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++语言。(2)编译和安装full gcc:$make all$make install查看$PREFIX/bin中多了那些文件:$ls $PREFIX/binarm-linux-g++ arm-linux-protoize arm-linux-c++其中,g++——gnu的C++编译器;protoize——与unprotoize相反,将K&R C的源码转换为ANSI C的形式,在函数原型中加入参数类型;c++——gnu的C++编译器。至此,交叉编译工具已经编译完成了。 1.2 下载工具链

通常,编译一个交叉工具链非常复杂,而且很容出错。因此,直接下载一个编译好的工具链是非常实用的。本文介绍Denx公司发布的一套开源的嵌入式Linux开发工具链ELDK(Embedded Linux Development Kit,ELDK),ELDK不仅简单而且非常好用,最重要的是它还是完全免费的!ELDK的下载网址如下表所示:

HTTPFTPhttp://mirror.switch.ch/ftp/mirror/eldk/eldk/ftp://mirror.switch.ch/mirror/eldk/eldk/http://sunsite.utk.edu/ftp/pub/linux/eldk/ftp://sunsite.utk.edu/pub/linux/eldk/http://ftp.sunet.se/pub/Linux/distributions/eldk/ftp://ftp.sunet.se/pub/Linux/distributions/eldk/http://archiv.leo.org/pub/comp/os/unix/linux/eldk/ftp://ftp.leo.org/pub/eldk/ ELDK同时支持ARM、PPC、MIPS等多种处理器,它包括一个安装工具和很多RPM包,它可以安装到用户的交叉编译的主机中。ELDK的RPM包分为两类:(1)嵌入式Linux开发工具;(2)为目标处理器编译号的工具和元件。其中,第一部分执行在开发主机上的交叉编译工具,包括gnu交叉编译器gcc、binutils和gdb等;第二部分是一些已经编译好的、能在目标开发板上运行的工具和库,这些工具和库可以用来建立一个Linux的Roofs文件系统。ELDK中的元件包如下表所示: 名称版本名称版本binutils2.14make3.79.1-17cpp3.3.3make-doc3.79.1-17gcc3.3.3mkcramfs0.0.1gcc-c++3.3.3mkimage1.1.3gdb5.2.1-4bmtd_utils2-1genext2fs1.3rpm4.1.1-1.8xaldd0.1rpm-build4.1.1-1.8xa 如果需要安装Linux开发主机版本的ELDK,可以执行如下命令:$chmod+x install./install [-d ] [] [] ...其中,(1)[ -d < dir >]表示安装的目录,如果不设置则表示安装在当前目录;(2):表示需要安装的目录CPU的类型。可将ELDK安装到任何目录,注意需要具有写和执行的权限,并不需要由root权限。ELDK是基于RPM结构的,表明每个ELDK的元件都是一个个的RPM文件,它们可以安装或者删除。(1)罗列出已经安装的ELDK元件包的指令为:${CROSS_COMPILE}rpm -aq(2)删除一个元件包的指令为:${CROSS_COMPILE}rpm -e (3)安装一个元件包指令为:${CROSS_COMPILE}rpm -i (4)更新一个元件包的指令为:${CROSS_COMPILE}rpm -U 如果要删除ELDK,则只需要删除ELDK安装的目录即可:$rm -rf 其中,< dir >表示ELDK安装的目录。注意,在执行上述命令前一定要配置好正确的ELDK环境变量。设置CROSS_COMPILE的环境变量,并添加ELDK的bin和usr/bin路径到系统的PATH环境变量中。CROSS_COMPILE将区分x86主机的gcc工具和安装的ELDK的ARM的gcc交叉编译工具。下面为一个安装并配置ELDK的例子:(1)建立ELDK的安装目录:$mkdir /opt/eldk(2)将安装程序载入光盘:$mount /dev/cdrom /mnt/cdrom(3)运行install脚本,安装ELDK到指定的目录:$/mnt/cdrom/install -d /opt/eldk(4)安装完成后,输出CROSS_COMPILE环境变量:$export CROSS_COMPILE=arm-linux-(5)在PATH环境变量中加入/opt/eldk/usr/bin和/opt/eldk/bin目录:$PATH=$PATH:/opt/eldk/usr/bin:/opt/eldk/bin 1.3 验证工具链 安装了交叉编译工具链后,需要经过验证才能正式实用。下面是一个简单的程序“helloworld.c”: #include int main(void) { printf("hello world!\n"); return 0; } 对于1.1节搭建好的交叉工具链进行编译,结果如下:$arm-linux-gcc -o helloworld helloworld.c$file helloworldhelloworld:ELF 32-bit LSB executable, ARM, version 1, dynamically linked (uses shared libs), not stripped上面的输出说明编译成功了一个能在ARM体系结构上运行“helloworld.c”,这就证明工具链已经搭建成功了。对于1.2节搭建好的工具链,可以进行一下编译进行验证:${CROSS_COMPILE}gcc -o helloworld helloworld.c$file helloworldhelloworld:ELF 32-bit LSB executable, ARM, version 1, dynamically linked (uses shared libs), not stripped上面的输出证明ELDK安装成功。 二、配置主机服务

在嵌入式软件开发过程中,有些主机服务有时非常必要,这样会为开发工作开来便利,下面主要介绍4种主机服务:samba、DHCP、TFTP和NFS。

2.1 配置samba samba服务能够实现Linux和Windows之间的文件共享,方便于文件编辑,具体配置方法如下:(1)修改samba配置文件“/etc/samba/smb.conf”:第一,修改interfaces=your ip/24;第二,添加开放的目录和权限,如下: [sharename] comment = Insert a comment here path = /home/share/ valid users = root browseable = yes writable = yes printable = no create mode = 0664 directory mode = 0775 (2)为samba创建一个单独的口令文件,根据“/etc/passwd”文件来创建,在shell种输入命令:$cat /etc/passwd | mksmbpasswd.sh > /etc/samba/smbpasswd(3)改变samba口令文件的权限,只有根用户才有读写权限:$chmod 600 /etc/samba/smbpasswd(4)设置每个samba用户的口令,如下命令把username替换为每个用户的用户名:$smbpasswd username(5)加密口令必须在samba配置文件种被启用,在“smb.conf”文件种,请确定一下行没有被注释掉: encrypt passwords = yes smb passwd file = /etc/samba/smbpasswd (6)在shell命令行输入“service smb restart”来确定samba服务被启动。(7)为了避免每次启动都要手动启动samba服务,可使用如下命令在系统启动时自动启动samba服务:$chkconfig smb on注意,使用samba服务之前,必须关闭Linux的防火墙功能。 2.2 配置DHCP DHCP是动态主机配置协议,这个协议用于向计算机自动提供IP地址,子网掩码和路由信息。在开发过程中,目标系统没有自己的静态IP地址,在启动时向DHCP服务器申请,因此需要在主机上配置DHCP服务,使得目标系统在请求IP地址时,动态地为它分配IP地址。DHCP服务地配置文件为“etc/dhcpd.conf”,它通常包含三部分:parameters、declarations和option。(1)DHCP配置文件地parameters(参数)表示是否和如何执行任务,即将那些网络配置选项发送给用户,parameters的主要内容如下表所示: 参数含义ddns-update-style配置DHCP-DNS互动更新模式default-lease-time指定缺省租赁时间的长度(s)max-lease-time指定最大租赁时间的长度(s)hardware指定网卡接口类型和MAC地址sever-name通知DHCP客户服务器名称get-lease-hostnames flag检查客户端使用的IP地址fixed-address ip分配给客户端一个固定的地址authritative拒绝不正确的IP地址请求 (2)DHCP配置文件中的declarations(声明),用来描述网络布局、提供用户的IP地址等,declarations的主要内容如下表所示: 声明解释shared-network用来告知是否一些子网络分享相同的网络subnet描述一个IP地址是否属于该子网range 起始IP终止IP提供动态分配IP地址的范围host主机名称参考特别的主机group为一组参数提供声明allow unknown-clients; deny unknown-client是否动态分配IP地址给未知的用户allow bootp; deny bootp是否响应激活查询allow booting; deny booting是否响应用户查询filename开始启动文件的名称,应用于无盘工作站next-server设置服务器从引导文件中装入主机名,应用于无盘工作站 (3)DHCP配置文件中的option(选项),用来配置DHCP可选参数,其主要内容如下表所示: 选项解释subnet-mask为用户端设置子网掩码domain-name为用户端指明DNS名字domain-name-servers为用户端知名DNS服务器的IP地址host-name为用户端指定主机名称routers为用户端设定默认网关broadcast-address为用户端设定广播地址ntp-server为用户端设定网络时间服务器的IP地址time-offset为用户端设定与格林尼治时间的偏移时间(s) 下面为一个典型的配置实例: ddns-update-style interim; ignore client-updates; allow bootp; subnet 192.168.1.0 netmask 255.255.255.0{ range dynamic-bootp 192.168.1.1 192.168.1.200; default-lease-time 216000; max-lease-time 432000; # we want the nameserver to appear at a fixed address host armlinux{ hardware ethernet 11:22:33:44:55:66; fixed-address 192.168.1.20; option root-path "/tftpboot"; } } 重启DHCP服务,命令如下:$service dhcpd restart为了避免每次启动主机都要手动启动DHCP服务,使用如下命令使得DHCP服务在每次系统启动时都默认执行:$chkconfig dhcpd on 2.3 配置TFTP 在目标系统的开发过程中,Linux内核是从主机下载到目标系统上解压并运行的,因此主机必须提供这种文件传输功能。TFTP是一种简单的文件传输协议,多用于嵌入式系统应用中,因此主机需要配置TFTP服务,以供内核下载时使用。(1)修改而皮质参数,TFTP服务的配置文件为“etc/xinetd.d/tftp”,只需要将server-args的参数设置为“-s/tftpboot”,/tftpboot为包含要下载到目标系统中去的Linux内核映射文件的目录,其他使用默认设置即可。(2)在主机上创建/tftpboot目录,用于存放内核,命令如下:$mkdir /tftpboot(3)重启TFTP服务:$service xinetd restart(4)为了避免每次重启主机都要手动启动TFTP服务,使用如下指令实现TFTP服务在每次启动系统时都默认执行:$chkconfig tftp on典型的TFTP配置文件如下: service tftp { disable=no socket-type=dgram protocol=udp wait=yes user=root server=/usr/sbin/in.tftpd server-args=-s /tftpboot per_source=11 cps=100 2 flags=IPv4 } 2.4 配置NFS 网络文件系统(NFS)是一种在网络上及其间共享文件的方法,在开发过程中,目标系统没有足够的本地存储设备,可以通过主机提供NFS服务,使用在主机上的文件系统,就如同本地硬盘驱动器一样。(1)修改NFS配置文件NFS服务的配置文件为“etc/exports”,其格式如下:共享目录 主机名1或IP1(参数1,参数2) 主机名2或IP2(参数3,参数4)上面的格式表示:一个共享目录提供给两台不同的主机,但提供给这两台主机的权限和参数可以是不同的,可以设置的参数如下所示:rw:可读写的权限;ro:只读权限;root_squash:root用户的所有请求映射为如匿名(anonymous)用户一样的权限;no_root_squash:保留共享文件的UID和GID;all_squash:共享文件的UID和GID映射匿名用户,适用于公共目录;no_all_squash:保留共享文件的UID和GID;sync:资料同步写入到内存和硬盘中;async:资料会先暂存于内存中,而非直接写入硬盘;secure:NFS通过1024个以下的安全TCP/IP端口发送;insecure:NFS通过1024个以上的端口发送;hide:在NFS共享目录不共享其子目录;no_hide:共享NFS目录的子目录。(2)重启NFS服务:$service nfs restart(3)为了避免每次启动时手动启动NFS服务,输入如下指令在启动机器时自动启动NFS:$chkconfig nfs on典型的NFS配置文件如下:/tftpboot *(rw, no_root_squash, no_all_squash)


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有