1、交叉编译
由于嵌入式系统资源匮乏,一般不能像 PC 一样安装本地编译器和调试器,不能在本地编写、编译和调试自身运行的程序,而需借助其它系统如 PC 来完成这些工作,这样的系统通常被称为宿主机。
宿主机通常是 Linux 系统,并安装交叉编译器、调试器等工具;宿主机也可以是 Windows系统,安装嵌入式 Linux 集成开发环境。在宿主机上编写和编译代码,通过串口、网口或者硬件调试器将程序下载到目标系统里面运行,系统示意图如图 1.1 所示。
所谓的交叉编译,就是在宿主机平台上使用某种特定的交叉编译器,为某种与宿主机不同平台的目标系统编译程序,得到的程序在目标系统上运行而非在宿主机本地运行。这里的平台包含两层含义:一是核心处理器的架构,二是所运行的系统。这样,交叉编译有 3 种情形:
目标系统与宿主机处理器相同,运行不同的系统;
目标系统与宿主机处理器不同,运行相同的系统;
目标系统与宿主机处理器不同,运行不同的系统。
实际上,在 PC 上进行非 Linux 的嵌入式开发,哪怕使用 IDE 集成环境如 Keil、ADS、Realview,都是交叉编译和调试的过程,只是 IDE 工具隐藏了细节,没有明确提出这个概念而已。
1.1、交叉编译
交叉编译器是在宿主机上运行的编译器,但是编译后得到的二进制程序却不能在宿主机上运行,而只能在目标机上运行。交叉编译器命名方式一般遵循“处理器-系统-gcc”这样的规则,一般通过名称便可以知道交叉编译器的功能。例如下列交叉编译器:
arm-none-eabi-gcc,表示目标处理器是 ARM,不运行操作系统,仅运行前后台程序;
arm-uclinuxeabi-gcc,表示目标处理器是 ARM,运行 uClinux 操作系统;
arm-none-linux-gnueabi-gcc,表示目标处理器是 ARM,运行 Linux 操作系统;
mips-linux-gnu-gcc,表示目标处理器是 MIPS,运行 Linux 操作系统。
进行 ARM Linux 开发,通常选择 arm-linux-gcc 交叉编译器。ARM-Linux 交叉编译器可以自行从源代码编译,也可以从第三方获取。在能从第三方获取交叉编译器的情况下,请尽量采用第三方编译器而不要自行编译,一是编译过程繁琐,不能保证成功,二是就算编译成功,也不能保证交叉编译器的稳定性,编译器的不稳定性会对后续的开发带来无限隐患。而第三方提供的交叉编译器通常都经过比较完善的测试,确认是稳定可靠的。
1.2、安装交叉编译器
文章后面会提供交叉编译工具包gcc-4.4.4-glibc-2.11.1-multilib-1.0.tar.bz2的链接,解压命令
tar xjvf gcc-4.4.4-glibc-2.11.1-multilib-1.0.tar.bz2
tar xjvf gcc-4.4.4-glibc-2.11.1-multilib-1.0.tar.bz2-C /opt/ #指定解压目标目录
1.2.1确定交叉编译器的实际目录
在完成解压后,如果不设置环境变量,如果不指定交叉编译器的完整路径,系统是无法调用交叉编译器的。
假如交叉工具链安装在“/opt/gcc-4.4.4-glibc-2.11.1-multilib-1.0/arm-fsl-linux-gnueabi/bin/”目录下,用 ls 命令可以查看到该目录下的各种文件
有不少初学者不知道自己已经将交叉编译器安装在哪个目录下了,确认方法就是看arm-fsl-linux-gnueabi-*这些文件到底在哪个目录。确定了在哪个目录后,接下去的事情就好办了。
如果不想添加设置交叉编译器的路径到系统环境变量中,则必须在每次使用交叉编译器的地方写明交叉编译器的全路径,例如:export CC=/opt/gcc-4.4.4-glibc-2.11.1-multilib-1.0/arm-fsl-linux-gnueabi/bin/arm-fsl-linux-gnueabi-make CROSS_COMPILE=$CC ARCH=arm uImage如果系统安装了多个不同版本的同名编译器,就可以采用这种方法。不过前提是必须对自己安装的交叉编译器路径有清醒的认识。
1.2.2设置环境变量
如果系统只有一个交叉编译器,还是强烈推荐设置系统环境变量,毕竟每次都设置全路径,稍微显得有点麻烦。设置系统环境变量后,只需在 Linux 终端输入arm-fsl-linux-gnueabi-gcc,就可以调用交叉编译器,简单方便。
设置系统环境变量有 3 种方法,下面分别讲述。
1.临时变量
临时设置系统环境变量,是通过 export 命令,将交叉编译器的路径添加到系统 PATH 环境变量中。用法(多个值之间用冒号隔开):
vmuser@Linux-host: ~$ export PATH=$PATH:/交叉编译器路径
紧接前面这个示例,在添加交叉编译器路径前,先查看系统 PATH 的值:
vmuser@Linux-host:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
添加工具链路径:
vmuser@Linux-host: ~$ export PATH=$PATH:/opt/gcc-4.4.4-glibc-2.11.1-multilib-1.0/arm-fsl-linux-gnueabi/bin/
再次查看 PATH 的值:
vmuser@Linux-host:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/opt/gcc-4.4.4-glibc-2.11.1-multilib-1.0/arm-fsl-linux-gnueabi/bin/
可以看到,交叉编译器的路径已经被添加到系统 PATH 变量中。此时在终端输入arm-fsl-linux-gnueabi-,然后按键盘 TAB 键,可以看到很多 arm-fsl-linux-gnueabi-开头的命令被列了出来,
2.修改全局配置文件
在终端中添加环境变量,需要每次打开终端都设置,也很麻烦。可以考虑将设置的过程添加到系统配置文件中。/etc/profile 是系统全局的配置文件,在该文件中设置交叉编译器的路径,能够让登录本机的全部用户都可以使用这个编译器。
打开终端,输入“sudo vi /etc/profile”命令,打开/etc/profile 文件,在文件末尾添加:
export PATH=$PATH:/opt/gcc-4.4.4-glibc-2.11.1-multilib-1.0/arm-fsl-linux-gnueabi/bin
保存文件并退出,然后在终端输入“. /etc/profile”(点+空格+文件名),执行 profile 文件,使刚才的改动生效。如果没有书写错误,此时打开终端,输入 arm-fsl-linux-gnueabi-,然后按键盘 TAB 键,同样可以看到很多 arm-fsl-linux-gnueabi-开头的命令。
3.修改用户配置文件(推荐)
“/etc/profile”是全局配置文件,会影响登录本机的全部用户。如果不希望影响其他用户,也可以只修改当前用户的配置文件,通常是“~/.bashrc”或者“~/.bash_profile”。
修改方法与修改“/etc/profile”类似,这是无需 sudo,直接 vi 打开即可,在文件末尾增加:
export PATH=$PATH:/opt/gcc-4.4.4-glibc-2.11.1-multilib-1.0/arm-fsl-linux-gnueabi/bin
与执行“/etc/profile”的方式一样,输入“. .bashrc”或者“. .bash_profile”,执行修改过的文件,使修改生效。如果无误,打开终端,输入 arm-fsl-linux-gnueabi-,然后按键盘 TAB键,同样可以看到很多 arm-fsl-linux-gnueabi-开头的命令。
4.测试工具链简单测试。
打开终端,输入交叉编译器命令,如 arm-fsl-linux-gnueabi-gcc,然后回车,能够得到下列类似信息,说明交叉编译器已经能够正常工作了。vmuser@Linux-host:~$ arm-fsl-linux-gnueabi-gcc
arm-fsl-linux-gnueabi-gcc: no input files
进一步测试,可以编写一个简单的 c 文件,用交叉编译器交叉编译,并查看编译结果。在“~”目录下创建 hello.c 文件,然后编写
#include
int main(void)
{
int i;
for (i=0; i<5; i++) {
printf("Hello %d!\n", i);
}
return 0;
}
输入完成后,保存并关闭 hello.c 文件,输入以下命令对 hello.c 进行编译并查看编译后
生成文件的属性:
vmuser@Linux-host: ~$ cd ~ #浏览到程序文件所在目录
vmuser@Linux-host: ~$ arm-fsl-linux-gnueabi-gcc hello.c -o hello #编译 hello.c 文件
vmuser@Linux-host: ~$ file hello #查看编译生成的 hello 文件属性
hello:ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), forGNU/Linux 2.6.26, not stripped
可以看到 hello 程序是 32 位 ARM 指令架构的程序。
5.安装 32 位的兼容库
如果前面的操作都能得到正确现象,那么就该为自己庆祝一下了,因为交叉编译器已经安装完毕,并且能够正确工作了。但是事情总有例外,很有可能在终端输入arm-fsl-linux-gnueabi-gcc 命令后,得到的却是下面的结果:
-bash: ./arm-fsl-linux-gnueabi-gcc: 没有那个文件或目录
此时请确认:
在某个目录下确实存在 arm-fsl-linux-gnueabi-gcc 文件;
在终端输入 arm-fsl-linux-gnueabi-,按 TAB 键,能找到 arm-fsl-linux-gnueabi-*系列命令。
如果这两个条件都确认无误,那么问题就好解决了。这种问题主要发生在 64 位操作系统上,原因在于大多数交叉编译器为了适应性,通常以 32 位发布,而实际系统是 64 位的,存在架构差异,所以不能执行。
解决办法很简单,安装 32 位兼容库就好了。在 Ubuntu 12.04 上的安装命令:
vmuser@Linux-host: ~$ sudo apt-get install ia32-libs
32 兼容库需要从 Ubuntu 的源下载,所以此时主机系统应当能访问互联网。
在 Ubuntu12.04 64 位下安装 32 位库的名字为 ia32-libs,在其它版本的 Ubuntu 名称可能有变。如果不能正确安装兼容库,请读者自行到互联网上寻求解决方案。
安装 32 位兼容库后,再次执行 arm-fsl-linux-gnueabi-gcc 命令,应该得到如下信息:
arm-fsl-linux-gnueabi-gcc: no input files
2、SSH服务器
SSH 是 Secure Shell 的缩写,是建立在应用层和传输层基础上的安全协议,能够有效防止远程管理过程中的信息泄露问题。SSH 实际上是一个 Shell,可以通过网络登录远程系统,当然,前提是远程系统已经开启了 SSH 服务。
使用 SSH 服务,一方面需要在远程系统上安装 SSH 服务,另一方面要在本地系统上安装 SSH 客户端,常见的 SSH 客户端有 putty、SSH Secure Shell Client 等
2.1、安装SSH服务器
在 Linux 主机输入下面命令安装 ssh 服务器:
vmuser@Linux-host:~$ sudo apt-get install openssh-server
2.2、网络设置
ifconfig eth0 192.168.1.10 设置ip
ifconfig eth0 查看ip
udhcpc 动态ip
ifconfig eth0 hw ether 00:11:22:33:44:55 修改MAC地址
ifconfig eth0 netmask 255.255.255.0 修改子网掩码
ifconfig eth0 broadcast 192.168.28.225 设置广播地址
ifconfig eth0 dow 关闭eh0网卡
route add default gw 192.168.191.1 设置网关(del)
route –n 查看网关设置
vim /etc/resolv.conf 设置DNS
可在开机的etc/rc.d/init.d/start_userapp 文件中添加网络配置命令
ssh root@192.168.1.10 通过ssh登录linux系统
3、NFS服务器
在嵌入式 Linux 开发中,需要在 Linux 主机为目标机编写程序代码,然后编译程序,生成的程序是要传输到目标机上才能调试、运行。那么如何更快、更便捷地传输文件,将影响到开发工作的效率。NFS 无疑是最好的选择。通过 NFS 服务,主机可以将自己系统中某个指定目录通过网络共享给目标机(和 Windows 的文件网络共享类似)。目标机可以直接运行存放于 Linux 主机共享目录下的程序。这样调试程序时十分方便。
NFS 即网络文件系统(Network File-System),可以通过网络让不同机器、不同系统之间可以实现文件共享。通过 NFS,可以访问远程共享目录,就像访问本地磁盘一样。NFS只是一种文件系统,本身并没有传输功能,是基于 RPC(远程过程调用)协议实现的,采用 C/S 架构。接下来将介绍如何在 ubuntu 系统中开启 NFS 服务器功能,使得开发套件能共享 ubuntu 系统的指定目录。
3.1、安装 NFS 软件包
在 ubuntu 终端输入下面命令安装 NFS 服务器:
vmuser@Linux-host: ~$ sudo apt-get install nfs-kernel-server #安装 NFS 服务器端
vmuser@Linux-host: ~$ sudo apt-get install nfs-common #安装 NFS 客户端
3.2、添加 NFS 共享目录
安装完 NFS 服务器等相关软件后,需要指定用于共享的 NFS 目录,其方法是在“/etc/exports”文件里面设置对应的目录及相应的访问权限,每一行对应一个设置。
sudo vi /etc/exports
若需要把“/nfsroot”目录设置为 NFS 共享目录,请在该文件末尾添加下面的一行:
/nfsroot *(rw,sync,no_root_squash)
修改完成后,保存并退出“/etc/exports”文件。然后新建“/nfsroot”目录,并为该目录设置最宽松的权限:
vmuser@Linux-host:~$ sudo mkdir /nfsroot
vmuser@Linux-host:~$ sudo chmod -R 777 /nfsroot
vmuser@Linux-host:~$ sudo chown –R nobody /nfsroot
3.3、启动NFS服务
在终端中执行如下命令,可以启动 NFS 服务:
vmuser@Linux-host: ~$ sudo /etc/init.d/nfs-kernel-server start
执行如下命令则可以重新启动 NFS 服务,也可以通过重启 ubuntu 来实现:
vmuser@Linux-host: ~$ sudo /etc/init.d/nfs-kernel-server restart
在 NFS 服务已经启动的情况下,如果修改了“/etc/exports”文件,需要重启 NFS 服务,以刷新 NFS 的共享目录。
当然在下一次启动系统时,NFS 服务是自动启动的。
3.4、测试NFS服务器
NFS 服务启动后,可以在 Linux 主机上进行自测。自测的基本方法为:将已经设定好的NFS 共享目录 mount(挂载)到另外一个目录下,看能否成功。
假定 Linux 主机 IP 为 192.168.12.123,其 NFS 共享目录为/nfsroot,可使用如下命令进行测试:
vmuser@Linux-host:~$ sudo mount -t nfs 192.168.12.123:/nfsroot /mnt -o nolock
如果指令运行没有出错,则 NFS 挂载成功,在主机的/mnt 目录下应该可以看到/nfsroot目录下的内容(即之前创建的 NFS_Test 目录)。
此外,也可以使用开发套件进行挂载测试,此时需要在开发套件上输入如下指令:
root@EasyARM-iMX28x ~# mount –t nfs 192.168.12.123:/nfsroot /mnt –o nolock
若挂载成功,在开发套件的/mnt 目录下也可以看见 NFS_Test 目录。之后,开发套件就可以像操作本地目录一样去操作主机的/nfsroot 目录。
注意,要想成功地挂载 NFS 目录,开发套件必须要先确保与主机之间的网路是畅通的,可以使用 ping 命令进行测试:
root@EasyARM-iMX28x ~# ping 192.168.12.123
此外,在 mount 与 umount(解除挂载)操作时,用户的当前路径不能是操作的目标路径。例如下面两条指令就是错误的,用户当前所处的路径与要 mount(或 umount)的目标路径相同:
root@EasyARM-iMX28x /mnt# mount –t nfs 192.168.12.123:/nfsroot /mnt –o nolock # 错误
root@EasyARM-iMX28x /mnt# umount /mnt # 错误
4、TFTP服务器
TFTP(Trivial File Transfer Protocol,简单文件传输协议),是 TCP/IP 协议族中用来在客户机和服务器之间进行简单文件传输的协议,开销很小。这时候有人可能会纳闷,既然前面已经介绍了功能强大的 SSH 和 NFS 服务,还有必要介绍 TFTP 吗?TFTP 尽管简单,但在很多地方还是不可替代的,正如俗话说的“尺有所短,寸有所长”。
TFTP 通常用于内核调试。在嵌入式 Linux 开发过程中,内核调试是其中一个基础、重要的环节。调试内核通常是与 Bootloader 配合使用,只需在嵌入式系统的 Bootloader 中实现网卡驱动和 TFTP 客户端,就可以使用 TFTP 服务从主机上下载内核。
主机要开启 TFTP 服务,必须要先安装 TFTP 服务器软件,可以在 Linux 下实现,也可以在 Windows 下实现。
4.1、安装配置TFTP软件
用户可以在主机系统联网的情况下,在终端输入下面命令进行安装:
vmuser@Linux-host: ~$ sudo apt-get install tftpd-hpa tftp-hpa
4.2、配置TFTP服务器
TFTP 软件安装后,默认是关闭 TFTP 服务的,需要更改 TFTP 配置文件“/etc/default/tftp-hpa”,可通过终端输入如下命令进行修改:
vmuser@Linux-host: ~$ sudo vi /etc/default/tftpd-hpa
用户需要指定一个目录为 TFTP 根目录。若用户需要把/tftpboot 目录设置为 TFTP 根目录,请在/etc/default/tftp-hpa 文件中的“TFTP_DIRECTORY”变量指定,如下所示:
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/tftpboot"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="-l -c -s"
如果用户的 Linux 系统下尚未创建/tftpboot 目录,需要创建该目录,并需要使用 chmod命令为该目录设置最宽松的权限。目录创建及权限设置命令如下所示:
vmuser@Linux-host: ~$ sudo mkdir /tftpboot
[sudo] password for vmuser:
vmuser@Linux-host: ~$ sudo chmod –R 777 /tftpboot
vmuser@Linux-host: ~$ sudo chown –R nobody /tftpboot
4.3、启动TFTP服务器
TFTP 服务器安装配置完成后,启动 TFTP 服务的终端命令如下:
vmuser@Linux-host:~$ sudo service tftpd-hpa start
tftpd-hpa start/running, process 2389
当然直接重启系统也可以启动 TFTP 服务。
4.4、测试TFTP服务器
在 TFTP 服务器目录/tftpboot 下创建一个测试文件 tftpTestFile:
vmuser@Linux-host: ~$ echo ―Hello,can you see me?‖ > /tftpboot/tftpTestFile
测试文件准备好了之后,打开终端,输入以下测试命令(在 Linux 系统中 localhost 表示本地主机):
vmuser@Linux-host: ~$ tftp localhost
tftp> get tftpTestFile # 如果测试失败会打印出错信息
tftp> q
vmuser@Linux-host: ~$ cat /tftpboot/tftpTestFile
Hello,can you see me? # 文件内容正确,表示 TFTP 服务器配置成功