嵌入式Linux开发教程
上QQ阅读APP看书,第一时间看更新

1.4 搭建嵌入式开发环境

构建开发环境是任何开发工作的基础,对于软硬件非常丰富的嵌入式系统来说,构建高效、稳定的环境是能否开展工作的重要要素之一。本节将介绍嵌入式开发环境的建立方法,包括嵌入式的Linux操作系统Ubuntu16.04,主机与开发板的通信软件,交叉编译工具等的安装和配置方法。

1.4.1 Ubuntu16.04的安装

Ubuntu 支持各种形形色色的架构,包括 i386[386/486/Pentium(II/III/IV)和 Athlon/Duron/Sempron处理器],AMD64(Athlon64,Opteron,最新的64位Intel处理器)以及PowerPC(iBook/Powerbook, G4 and G5)等。Ubuntu相对其他Linux发行版的主要特点如下。

(1)基于Debian/Linux,使用APT包管理系统。

(2)相对于Fedora Code,APT包管理系统优雅地解决了依赖问题,并且可以从容地在线安装升级。

(3)相对于Debian,软件更新积极,而Debian较保守。

(4)相对于Gentoo,基本无需编译,省力、省时、省心。

本小节将介绍在VirtualBox管理器5.1.2中安装Ubuntu 16.04,读者可以在Ubuntu的官方网站http://www.ubuntu.com/download中获取最新版的Ubuntu镜像文件。

在安装VirtualBox后,可以按照如下步骤安装Ubuntu。

(1)打开VirtualBox,可以看到图1-1所示的界面。

(2)单击“新建”按钮后会出现图1-2所示的界面,一般按照图中所示填写,版本根据读者下载的是32bit或64bit选择。

图1-1 打开VirtualBox后的界面

图1-2 虚拟机系统名称填写

(3)接下来是配置内存,如图1-3所示,内存大小可以选择默认,也可以根据实际情况填写。剩下的可以选择默认,直接单击“下一步”按钮。当出现虚拟硬盘时,文件位置及硬盘大小可以根据实际情况选择。单击“创建”按钮后,则创建虚拟机环境完成,如图1-4所示。

图1-3 内存大小的选择

图1-4 创建虚拟环境后的界面

(4)创建完成后,单击“设置”按钮,如图1-5所示,加载ISO镜像文件。然后单击“启动”,会开机进入图1-6所示的界面。选择“中文(简体)”,单击“安装Ubuntu”按钮,开始安装Ubuntu。

图1-5 加载ISO镜像文件

图1-6 安装Ubuntu欢迎界面

(5)进入准备安装Ubuntu界面,按照图1-7所示选择即可,单击“继续”按钮,进入图1-8所示的界面进行选择。

图1-7 准备安装Ubuntu界面

图1-8 安装类型选择

(6)接下来单击“现在安装”按钮,进入时区选择界面,选择“shanghai”,如图1-9所示。单击“继续”按钮,就进入键盘布局界面,选择“汉语”,如图1-10所示。

图1-9 时区选择界面

图1-10 键盘布局选择

(7)按照图1-10选择后,进入用户名及密码设置界面,如图1-11所示。用户名及密码根据读者自己需要设置。设置完成后,进入安装界面中,如图1-12所示,等待一段时间,即可安装完毕。

图1-11 用户名及登录密码设置

图1-12 安装界面

(8)在VirtualBox配置的过程中,网络已经默认选择好了,如图1-13所示,按照默认的选择, Ubuntu安装完成后,只要宿主机能够上网,虚拟机就能上网。

这样就完成了系统的安装,如图1-14所示。下面还将安装和设置一些常用的工具。

图1-13 网络设置

图1-14 安装完成后的系统桌面

1.4.2 Minicom的安装配置

Minicom是一款串口通信软件,在嵌入式开发领域应用十分广泛。类似的软件还有Windows下的超级终端(Hyperterminal),Linux下的kermit等。它们之间的区别很小,基本上可以互换,选择适合自己的就可以了。

1.安装Minicom

在Ubuntu下安装Minicom的方法很简单。正确设置网络后,打开终端,输入如下命令。

$sudo apt-get install Minicom

键入上述命令按Enter键后,得到图1-15所示界面。输入y并按Enter键,开始安装Minicom,如图1-16所示。

图1-15 获取安装包

图1-16 安装Minicom

2.配置Minicom

Minicom是在终端下运行的程序,可以通过它配置界面来配置其工作特性。第一次使用前,通常都需要做一次配置。在shell下执行命令:

$Minicom -s

出现图1-17所示的配置界面。

在图1-17所示的菜单中,可以先通过光标移动键选择菜单项,然后再按 Enter 键进入子菜单项。选择第三个菜单项,即“Serial port setup”,根据目标板的串口通信参数设置。进入图1-18所示的配置界面。这些配置项前的大写字母为该配置项的快捷键,要配置某个配置项可以通过相应的按键选择该配置项,然后再做修改。

图1-17 Minicom的配置界面

例如,按A键修改使用的串口设备,其中:“/dev/ttyS0”表示串口1,“/dev/ttyS1”表示串口2。修改完这一项,按Esc键返回。通常串口通信速率(E-Bps/Par/Bits)和硬件流控(F-Hardware Flow Control)也要设置为图1-18中所设置的那样。

参数设置完成后,按Enter键返回图1-17所示的主配置菜单。移动光标至“Sava setup as dfl”菜单项,按Enter键保存为默认配置。最后,选择“Exit from Minicom”命令退出。

再次启动Minicom时,直接在shell下执行Minicom命令就可以进入Minicom的控制台。在控制台下通过组合键Ctrl+A+Z可以进入Minicom菜单,如图1-19所示。

图1-18 Minicom串口参数配置界面

图1-19 Minicom命令菜单

1.4.3 Tftp服务的安装配置

Tftp协议是简单文件传输协议,基于UDP协议,没有文件管理、用户控制等功能,因此实现起来简单易行,使用方便,正好适合目标板的Boot Loader等使用。Tftp分为服务器端程序和客户端程序,在主机上通常同时配置有Tftp服务端和客户端。这里主要介绍服务端的配置方法。默认安装的Ubuntu系统没有包含Tftp的服务端和客户端,可以采取命令行的形式获取,步骤如下。

(1)安装客户端。

$sudo apt-get install tftp

(2)安装服务端。

$sudo apt-get install tftpd

(3)安装inetd。

$sudo apt-get install netkit-inetd

说明:inetd是监视一些网络请求的守护进程,其根据网络请求来调用相应的服务进程来处理连接请求。inetd可以为多种服务管理连接,当它接到连接时,它能够确定连接所需的程序,启动相应的进程,并把socket交给程序(服务器socket将作为程序的标准输入、输出和错误输出描述符)。使用inetd来运行那些负载不重的服务有助于降低系统负载,因为它不需要为每个服务都启动独立的服务程序。

(4)在“/”目录下建一个tftpboot,把属性改成777。

$cd /

$sudo mkdir tftpboot

$sudo chmod 777 tftpboot

(5)在/etc/inetd.conf里进行添加。

#tftpd dgram udp wait root /usr/sbin/in.tftpd /usr/sbin/in.tftpd -s /tftpboot

(6)重新加载inetd进程。

$sudo /etc/init.d/inetd reload

(7)Tftp服务器就安装完成了,下面测试一下。在/tftpboot文件夹下新建立一个文件。

$cd /tftpboot

$touch aaa

(8)进入另外一个文件夹。

$cd~

$tftp localhost

$tftp> get aaa

Tftp便配置完成了。

1.4.4 NFS的安装配置

网络文件系统(Network File System,NFS)是一种将远程主机上的分区(目录)经网络挂载到本地系统的一种机制,通过对网络文件系统的支持,用户可以在本地系统上像操作本地分区一样来对远程主机的共享分区(目录)进行操作。

在嵌入式Linux的开发过程中,开发者需要在Linux服务器上进行所有的软件开发,交叉编译后,通过FTP方式将可执行文件下载到嵌入式系统运行,但这种方式不但效率低下,且无法实现在线的调试。因此,可以通过建立NFS,把Linux服务器上的特定分区共享到待调试的嵌入式目标系统上,这样就可以直接在嵌入式目标系统上操作Linux服务器,同时可以在线对程序进行调试和修改,大大方便了软件的开发。因此,NFS是嵌入式Linux开发的一个重要的组成部分,本部分内容将详细说明如何配置NFS开发环境。NFS开发环境的实现包括两个方面。

(1)Linux服务器端的NFS服务器支持。

(2)嵌入式目标系统的NFS客户端的支持。

因此,NFS开发环境的建立需要配置Linux服务器端和嵌入式目标系统端。

在Ubuntu系统下,使用NFS需要首先安装以下NFS的软件包。

(1)服务器端:nfs-common、nfs-kernel-server、portmap。

(2)客户端:nfs-common、portmap。

安装服务器端软件包的命令是:

$sudo apt-get install nfs-kernel-server

安装nfs-kernel-server时,apt会自动安装nfs-common和portmap。刚安装好的NFS还不能提供实际的服务,需要配置共享目录的路径和访问权限。NFS 的配置文件是/etc/exports。这个文件的内容非常简单,每一行由抛出路径、客户名列表以及每个客户名后紧跟的访问选项构成,如下所示:

[共享的目录] [主机名或IP(参数,参数)]

其中参数是可选的。当不指定参数时,NFS将使用默认选项。默认的共享选项是:

sync,ro,root_squash,no_delay

当主机名或IP地址为空时,则代表共享给任意客户机提供服务。当将同一目录共享给多个客户机,但对每个客户机提供的权限不同时,可以这样:

[共享的目录] [主机名1或IP1(参数1,参数2)] [主机名2或IP2(参数3,参数4)]

表1-1列出了一些NFS共享的常用参数。

表1-1 NFS共享的常用参数

续表

举例说明如下:

/home/share 192.168.1.15(rw,sync) *(ro)

配置说明:对IP地址为192.168.1.15的客户端赋予读写权限,其他IP地址的客户端仅有只读权限。

/home/share 192.168.1.*(rw,sync,no_root_squash)

配置说明:允许IP地址范围在192.168.1.*的计算机以读写的权限来访问/home/share目录。

/home/share *(rw,no_root_squash)

配置说明:/home/share目录允许所有的IP以读写的权限来访问。

最后执行启动NFS服务的命令。命令如下。

$sudo /etc/init.d/nfs-kernel-server start

停止和重启服务,命令分别如下。

$sudo /etc/init.d/nfs-kernel-server stop

$sudo /etc/init.d/nfs-kernel-server restart

在NFS服务器启动后,还需要检查Linux服务器的防火墙等设置(一般需要关闭防火墙服务),确保没有屏蔽掉NFS使用的端口和允许通信的主机,主要是检查Linux服务器iptables、ipchains等选项的设置,以及/etc/hosts.deny、/etc/hosts.allow文件。通常都是在内部局域网中进行开发,在安装系统时最好不要安装防火墙等网络安全软件,以方便使用时的配置。

首先在Linux服务器上进行NFS服务器的回环测试,验证共享目录是否能够被访问。在Linux服务器上运行如下命令:

$ mount–t nfs 192.168.1.1:/home/share /mnt

如果没有错误发生,再运行如下命令:

$ ls /mnt

该命令将Linux服务器的NFS输出共享目录挂载到/mnt目录下,因此,如果NFS正常工作,应该能够在/mnt目录看到/home/share共享目录中的内容。

在Linux服务器设置好后,还需要对目标板系统进行相关配置。在移植内核时需要添加内核对NFS的支持,在内核的编译选项中,选中“networking options”“IP:kernel level autoconfiguralion”项;选中“file systems”“network file systems”“root file system on nfs”和“nfs file system support”。重新编译内核,将Boot Loader和kernel下载到开发板上。

启动开发板后,在目标系统的Linux Shell下,首先建立Linux服务器输出共享目录的挂载点:

$mkdir /mnt/nfs

执行如下命令来进行NFS共享目录挂载。

$mount–t nfs 192.168.1.1:/home/share /mnt/nfs–o nolock

mount命令中的参数192.168.1.1为Linux服务器的IP地址,/home/share为Linux服务器端所配置的共享输出目录,/mnt/nfs为嵌入式设备上的本地目录。

然后进入该目录,并列出该目录下的文件,命令操作如下所示。

$cd /mnt/nfs

$ls

此时,在目标系统端所显示的内容即为Linux服务器的输出目录的内容,即Linux服务器的输出目录/home/share 通过 NFS映射到了嵌入式目标系统的/mnt/nfs 目录,可以像对待本地的目录一样来对待NFS的共享目录了。用户可以用增加、删除和修改文件的方式来验证实际效果。

1.4.5 建立交叉工具链

交叉工具链是用来完成交叉编译的工具包,这里简要介绍其构建的基本方法。

1.设置用户环境

设置用户环境的步骤如下。

(1)添加工作用户(在root用户下)。

$useradd -G root -g root -d/home/ARM ARM

$mkdir -p /home/ARM

$chown -R ARM /home/ARM

$chmod -R 775 /home/ARM

(2)建立工作目录(用ARM用户登录)。

$ mkdir dev_home

$ cd dev_home

$ mkdir btools kernel

(3)登录时启动环境变量(用root用户登录)。

$ vi~/.bashrc

在.bashrc最后加上:

export PATH=/usr/local/ARM/6.1.0/bin:$PATH

重新登录ARM用户,环境变量生效。

$ su ARM

2.编译工具链

首先需要设置环境变量,如下所示:

$ vi~/.bashrc

export divFIX=/usr/local/ARM/6.1.0

export TARGET=ARM-linux

export SYSROOT=${divFIX}/sysroot

export ARCH=ARM

export CROSS_COMPILE=${TARGET}

export PATH=${divFIX}/bin:$PATH

export SRC=/home/ARM/dev_home/btools/tchain6.1.0

注意

如果已经安装过ARM-linux-gcc,并且已经加入到环境变量中,则应将其从环境中去掉,保证root用户和ARM用户环境中没有ARM-linux-gcc。

(1)准备源码包如表1-2所示。

表1-2 工具链所需的源码包

(2)准备补丁。上述的源码在进行编译时会出一些问题,还需稍做修改。

首先下载补丁 ioperm.c.diff,该补丁的作用是修正 ioperm()函数的一个 BUG。该补丁的下载地址为:http://frank. harvard.edu/~coldwell/toolchain/ioperm.c.diff。

然后下载补丁 flow.c.diff,该补丁的作用是修改 gcc 一处 BUG。该补丁的下载地址是:http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/flow.c.diff?cvsroot=gcc&only_with_tag=csl-ARM-branch&r1=1.563.4.2&r2=1.563.4.3。

最后一个补丁是t-linux.diff,该补丁的作用是用于产生crti.o和crtn.o文件,该补丁的下载地址为:http://frank.harvard.edu/~coldwell/toolchain/t-linux.diff。

(3)编译GNU binutils,重新以ARM用户登录,让新设置的环境变量起作用。

$ su ARM

$ cd ${SRC}

$ tar zxvf binutils-2.27.tar.gz

$ mkdir -p BUILD/binutils-2.27

$ cd BUILD/binutils-2.27

$ ../../binutils-2.27/configure --divfix=${divFIX} --target=${TARGET} --with-sysroot=${SYSROOT}

$ make

$make install

(4)准备内核头文件。使用当前平台的gcc编译内核头文件。

$ cd ${KERNEL}

$ tar zxvf ../btools/tchain6.1.0/linux-4.6.5.tar.gz

$ cd linux-4.6.5/

$ cp arch/ARM/configs/smdk2410_defconfig .config

因为本书介绍的 CPU 是 S3C2440,所以选择了一个配置文件 smdk2410_defconfig。通过menuconfig选择配置文件。

$ make ARCH=ARM menuconfig

选择后保存退出。

$ make

(5)复制内核头文件,指令如下所示。

$ mkdir -p ${SYSROOT}/usr/include

$cp -a include/linux ${SYSROOT}/usr/include/linux

$ cp -a include/asm-ARM ${SYSROOT}/usr/include/asm

$ cp -a include/asm-generic ${SYSROOT}/usr/include/asm-generic

(6)编译glibc头文件,指令如下所示。

$ cd ${SRC}

$ tar zxvf glibc-2.24.tar.gz

$ patch -d glibc-2.24 -p1 < ioperm.c.diff

$ cd glibc-2.3.5

$ tar jxvf ../ glibc-linuxthreads-2.5.tar.bz2

$ cd ..

$ mkdir -p BUILD/glibc-2.5-headers

$ cd BUILD/glibc-2.5-headers/

$../../glibc-2.5/configure --divfix=/usr --host=${TARGET} --enable-add-ons= linuxt hreads --with-headers=${SYSROOT}/usr/include

$make cross-compiling=yes install_root=${SYSROOT} install-headers

$touch ${SYSROOT}/usr/include/gnu/stubs.h

$touch ${SYSROOT}/usr/include/bits/stdio_lim.h

(7)编译gcc第一阶段,指令如下所示。

$ cd ${SRC}

$ tar jxvf gcc-6.1.0.tar.bz2

$ patch -d gcc-6.1.0 -p1 < flow.c.diff

$ patch -d gcc-6.1.0 -p1 < t-linux.diff

$ mkdir -p BUILD/gcc-6.1.0-stage1

$ cd BUILD/gcc-6.1.0-stage1/

$ ../../gcc-6.1.0/configure --divfix=${divFIX} --target=${TARGET} --enable- languages=c --with-sysroot=${SYSROOT}

注意

不能加上--disable-shared

$ make all-gcc

$ make install-gcc

(8)编译完整的glibc,指令如下所示。

$ cd ${SRC}

$ mkdir -p BUILD/ glibc-2.24

$ cd BUILD/glibc-2.24

$BUILD_CC=gcc CC=${CROSS_COMPILE}gcc AR=${CROSS_COMPILE}ar RANLIB=${CROSS_COMPILE}ranlib AS=${CROSS_COMPILE}as LD=${CROSS_COMPILE}ld ../../glibc-2.24/configure–divfix =/usr--build=i386-ubuntu-linux --host=ARM-unknown-linux-gnu --target=ARM-unknown- linux-gnu--without-__thread --enable-add-ons=linuxthreads --with-headers=${SYSROOT}/ usr/include

参数说明如下。

● --divfix:指定安装路径。

● --target:指定目标平台。

● --host:指定当前平台。

● --build:指定编译平台。

● --with-sysroot:用于指定编译所需要的头文件及链接库。

● --enable-add-ons:加入其他的库,如线程库等。

● --enable-languages:指定gcc所支持的语言。

$ make

$ make install_root=${SYSROOT} install

(9)编译完整的gcc,指令如下所示。

$ cd ${SRC}

$ mkdir -p BUILD/gcc-6.1.0

$ cd BUILD/gcc-6.1.0

$../../gcc-6.1.0/configure --divfix=${divFIX} --target=${TARGET} --with-sysroot=${SYSROOT} --disable-nls --enable-threads=posix --enable-symvers=gnu --enable-__cxa_atexit --with-softfloat-support=internal --enable-languages=c,c --enable-shared–enable-c99 --enable-long-long

$ make

$ make install

$ ARM-linux-gcc -v

Reading specs from /usr/local/ARM/6.1.0/lib/gcc/ARM-linux/6.1.0/specsConfigured with:../../gcc-6.1.0/configure --divfix=/usr/local/ARM/6.1.0 --target=ARM-linux–with -sysroot=/usr/local/ARM/6.1.0/sysroot --disable-nls --enable-threads=posix --enable- symvers=gnu -enable-__cxa_atexit --with-softfloat-support=internal --enable-languages =c,c --enableshared --enable-c99 --enable-long-long

Thread model: posix

gcc version 6.1.0

$ ls

ARM-linux-addr2line ARM-linux-c filt ARM-linux-gcc-6.1.0 ARM-linux-nm ARM-linuxreadelf

ARM-linux-ar ARM-linux-cpp ARM-linux-gccbug ARM-linux-objcopy ARM-linux-size

ARM-linux-as ARM-linux-g ARM-linux-gcov ARM-linux-objdump ARM-linux-strings

ARM-linux-c ARM-linux-gcc ARM-linux-ld ARM-linux-ranlib ARM-linux-strip

为了确保编译的gcc能正常工作,需要对它们进行测试,主要的步骤如下。

(1)编写C语言文件,代码如下。

$ vi hello_c.c

#include<stdio.h>

#include<stdlib.h>

int main()

{

printf("Hello,World~\n");

return 0;

}

(2)编写CPP语言文件,代码如下。

$ vi hello_cpp.cpp

#include<iostream>

using std::cout;

using std::endl;

int main()

{

cout<<"Hello,World!\n"<<endl;

return 0;

}

(3)交叉编译文件,代码如下。

$ ARM-linux-gcc hello_c.c -o hello_c

$ ARM-linux-g -o hello_cpp hello_cpp.cpp

$ file hello_c

hello_c: ELF 32-bit LSB executable, ARM, version 1 (ARM), for GNU/Linux 4.6.0, dynamically linked (uses shared libs), for GNU/Linux 4.6.0, not stripped

$ file hello_cpp

hello_cpp: ELF 32-bit LSB executable, ARM, version 1 (ARM), for GNU/Linux 4.6.0, dynamically linked (uses shared libs), for GNU/Linux 4.6.0, not stripped

没有出现任何错误,说明编译的gcc可以正常工作。

下面编译主机上运行的gdb,这个过程比较简单,指令如下。

$ tar zxvf gdb-7.11.tar.gz

$ mkdir -p BUILD/gdb-7.11-host

$ cd BUILD/gdb-7.11-host

$ export CC=gcc

$ ../../gdb-7.11/configure --target=ARM-linux

$ make

$ file gdb/gdb

gdb/gdb: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 4.6.0, dynamically linked (uses shared libs), for GNU/Linux 4.6.0, not stripped

另外有时需要进行远程调试,因此还需要建立目标平台上运行的gdbserver,指令如下。

$ mkdir -p ../gdbserver-7.11

$ cd ../gdbserver-7.11

$ export CC=/usr/local/ARM/6.1.0/bin/ARM-linux-gcc

$ ../../gdb-7.11/gdb/gdbserver/configure --host=ARM-linux

$ make

$ file gdbserver

gdbserver: ELF 32-bit LSB executable, ARM, version 1 (ARM), for GNU/Linux 4.6.0, dynamically linked (uses shared libs), for GNU/Linux 4.6.0, not stripped

3.工具链的下载

有些常用的工具链并不需要自己从头编译,网上已经有了现成的,只需下载后按指定的目录解压就可以了。工具链的官方下载地址如下所示。

http://www.ARM.linux.org.uk/:

ftp://ftp.ARM.linux.org.uk/pub/ARMlinux/toolchain/cross-2.95.3.tar.bz2:

ftp://ftp.ARM.linux.org.uk/pub/ARMlinux/toolchain/cross-3.0.tar.bz2:

ftp://ftp.handhelds.org/projects/toolchain/ARM-linux-gcc-3.3.2.tar.bz2:

ftp://ftp.handhelds.org/projects/toolchain/ARM-linux-gcc-3.4.1.tar.bz2:

http://ftp.snapgear.org/pub/snapgear/tools/ARM-linux/gcc-3.4.4.tar.bz2: