天天看点

第2章 Linux操作系统应用入门2.1启动Linux系统2.2 Linux文件2.3 Linux 常用命令2.4Linux开发工具的使用2.5 开发环境的建立2.6常用工具的使用

嵌入式系统就是一个专用的计算机系统,其上运行的操作系统一般采用Linux系统,既然如此我们就要学会如何使用Linux操作系统。

2.1启动Linux系统

1.在宿主机上启动虚拟机,点击启动Ubuntu系统。 如下图所示:

第2章 Linux操作系统应用入门2.1启动Linux系统2.2 Linux文件2.3 Linux 常用命令2.4Linux开发工具的使用2.5 开发环境的建立2.6常用工具的使用

2、Ubuntu系统启动以后,出现登录画面,选择用户名,并输入用户密码,登录系统,如下图所示。

第2章 Linux操作系统应用入门2.1启动Linux系统2.2 Linux文件2.3 Linux 常用命令2.4Linux开发工具的使用2.5 开发环境的建立2.6常用工具的使用

3. 进入虚拟机后,打开菜单Applications->Accessories->Terminal,打开终端。

第2章 Linux操作系统应用入门2.1启动Linux系统2.2 Linux文件2.3 Linux 常用命令2.4Linux开发工具的使用2.5 开发环境的建立2.6常用工具的使用

4.进入终端后,你就可以在终端中输入相关的Linux命令了,如下图所示。

第2章 Linux操作系统应用入门2.1启动Linux系统2.2 Linux文件2.3 Linux 常用命令2.4Linux开发工具的使用2.5 开发环境的建立2.6常用工具的使用

我们既可以在图形界面,也可以在字符界面下启动和操作Linux系统,Linux中的操作大部分都可以以图形界面界面的形式操作,普通的用户并不会有太大的不适感。

对于初学者来说,比较习惯与使用图像界面,但是作为科技人员来说,要习惯使用字符界面,图形界面要耗费大量的资源,因而有的时候,系统可能根本不会提供图形化界面,在某些嵌入式系统中甚至只有字符界面。要想充分利用Linux系统的优势,对Linux系统进行更精细化操作或进行的Linux系统下的开发的话,还是必须掌握字符界面有关操作技巧的。

小贴士:

   在Ubuntu中直接按ctrl+Alt+T组合键可以直接打开终端。

2.2 Linux文件

Linux一个非常重要的思想是“一切皆文件”。文件是Linux系统中非常重要的概念。

需要注意的是Linux系统中文件名是区分大小写的,如readme和ReadMe是两个不同的文件,并且在Linux系统中文件名也不存在所谓扩展名,Linux系统也不会根据所谓扩展名来区分文件,这是与Windows系统不同的。同时也需要注意的是当一个文件名以小圆点.开头表示这个文件是隐藏文件。

2.2.1Linux目录

与Windows系统下一样,在Linux中也是通过目录来组织文件的。但不同的是,在 Linux 或 Unix 操作系统中,所有的文件和目录都被组织成以一个根节点开始的倒置的树状结构,而不象Windows那样找不到所谓的C盘、D盘。Linux中文件系统的最顶层是由根目录开始的,系统使用 / 来表示根目录。在根目录之下的既可以是目录,也可以是文件,而每一个目录中又可以包含子目录文件。如此反复就可以构成一个庞大的文件系统。

登录系统后,在当前终端窗口下输入命令:

$ ls /
           

你会看到如下图所示:

bin     dev    home   lost+found    mnt     proc    sbin     srv      tmp    var 

boot    etc    lib    media         opt     root     sys      usr 
           

详细的目录介绍如下表所示:

目录 作用 备注
/boot 存放的启动Linux 时使用的内核文件,包括连接文件以及镜像文件。 系统启动必须
/etc 这个目录用来存放所有的系统管理所需要的配置文件和子目录。
/lib 这个目录里存放着系统最基本的动态连接共享库,其作用类似于Windows里的DLL文件。几乎所有的应用程序都需要用到这些共享库。
/ sys 这是linux2.6内核的一个很大的变化。该目录下安装了2.6内核中新出现的一个文件系统 sysfs,该文件系统直观反映内核设备树。当一个内核对象被创建的时候,对应的文件和目录也在内核对象子系统中被创建。
/bin bin是Binary的缩写, 这个目录存放着最经常使用的命令。 指令集合
/sbin s就是Super User的意思,这里存放的是系统管理员使用的系统管理程序。
/home 用户的主目录,在Linux中,每个用户都有一个自己的主目录,一般该目录名是以用户的账号命名的。 账户
/root 该目录为系统管理员,也称作超级权限者的用户主目录。
/dev dev是Device(设备)的缩写, 该目录下存放的是Linux的外部设备,在Linux中访问设备的方式和访问文件的方式是相同的。 外部文件管理
/media linux系统会自动识别一些设备,例如U盘、光驱等等,当识别后,linux会把识别的设备挂载到这个目录下。
/mnt 系统提供该目录是为了让用户临时挂载别的文件系统的,我们可以将光驱挂载在/mnt/上,然后进入该目录就可以查看光驱里的内容了。
/lost+found 这个目录一般情况下是空的,当系统非法关机后,这里就存放了一些文件。 临时文件
/ tmp 这个目录是用来存放一些临时文件的。
/opt 默认是空的,用户安装的额外软件一般放在这里。 扩展用的
/srv 存放服务启动后需要提取的数据(不用服务器就是空)
/ var  存放经常修改的数据,比如程序运行的日志文件(/var/log 目录下)。 运行过程中要用
/proc 这个目录是一个虚拟的目录,它是系统内存的映射,我们可以通过直接访问这个目录来获取系统信息。
/usr 用户的很多应用程序和文件都放在这个目录下,类似于windows下的program files目录。 用户目录,这是一个非常重要的目录

在Linux文件系统中还有几个特殊的目录,一个用户所在的工作目录,也叫当前目录,可以使用一个点 . 来表示;另一个是当前目录的上一级目录,也叫父目录,可以使用两个点 .. 来表示;用户的主目录,可以用一个点波浪线~表示:

  •  . :代表当前的工作目录,也可以使用 ./ 来表示;
  •  .. :代表当前的工作目录的父目录,也可以 ../ 来代表。
  • ~ :代表用户的主目录,一般位于/home下,以用户名命名。

小贴士:

图形界面下,打开菜单places->Home Folder 将打开一个文件浏览器,如下图所示。对于初学者来说,图形化界面非常容易操作。点击文件图标可以打开文件,右击还可以有更多的操作,与Windows系统基本类似,此处不再详述,读者可自行探索。

第2章 Linux操作系统应用入门2.1启动Linux系统2.2 Linux文件2.3 Linux 常用命令2.4Linux开发工具的使用2.5 开发环境的建立2.6常用工具的使用

2.2.2文件类型

Linux下主要的文件类型可分为4种:普通文件、目录文件、链接文件和设备文件。

  1. 普通文件:用户最常使用的文件,即我们通常意义上所说的文件。它包括文本文件、数据文件、二进制可执行文件等。
  2. 目录文件:在Linux中目录也是文件,其内容包含了文件名和子目录名以及指向文件和子目录的指针。
  3. 链接文件:类似于Windows系统中的快捷方式,但并不完全一样,可分为软链接文件和硬链接文件
  4. 设备文件:在Linux中把设备抽象成文件,然后对设备的操作就像对普通文件一样。Linux中设备相关的维护一般都在“/dev”目录下。

2.2.3文件的绝对路径与相对路径

  • 绝对路径:

    路径的表示方法,由根目录 / 开始写起,例如: /usr/share/doc 这个目录。

  • 相对路径:

    路径的表示方法,不是由 / 写起,而是某个指定位置开始写起,例如当前路径为 /usr/share/doc ,要表示 /usr/share/man ,可以写成 ../man 。

2.2.3文件属性

在linux终端中输入“ls -l”将列出当前目录下的所有文件及目录的相关信息,如

[email protected]:~$ ls -l
total 64
rxwxr-xr-x  1 ada ada   712  2017-11-12 23:15 build
drwxr-xr-x  2 ada ada 4096 2019-06-18 22:11 Desktop
..........
           

在上面的实例中每一行表示某一个文件或目录的信息,共有7组信息:文件类型及权限,文件硬链接数,文件属主名,文件属组名,文件大小,文件时间戳及文件名。

第一列共有 10 个位置,其中第一个字符代表这个文件是目录、文件或链接文件等等。

  • 当为[ d ]则是目录
  • 当为[ - ]则是文件;
  • 若是[ l ]则表示为链接文档(link file);
  • 若是[ b ]则表示为设备文件里面的块设备(可随机存取装置),如硬盘等;
  • 若是[ c ]则表示为设备文件里面的字符设备,例如键盘、鼠标(一次性读取装置)。

从第二个字符开始到第十个 9 个字符,3 个字符一组,分别表示了 3 组用户对文件或者目录的权限。权限字符用横线代表不许可,[ r ]代表可读(read)、[ w ]代表可写(write)、[ x ]代表可执行(execute)。 要注意的是,这三个权限的位置不会改变,如果没有权限,就会出现减号[ - ]。第1-3位确定属主(该文件的所有者)拥有该文件的权限。第4-6位确定属组(所有者的同组用户)拥有该文件的权限,第7-9位确定其他用户拥有该文件的权限。

注意:在Linux文本环境中,对于命令前的“[email protected]:~#”,其中“ada”表示登录用户名,“Ubuntu”表示计算机名,而“~”表示的是用户当前目录,最后的字符为命令提示符。Linux操作系统默认是使用普通账户登录系统的,默认的命令提示符为“$”,如果使用root超级用户账号登录系统后,默认的命令提示符为"#"。

2.3 Linux 常用命令

Linux是一款高可靠性、高性能的操作平台,其优越性在用户直接使用命令行(shell环境)运行时将得到更加充分的体现,嵌入式系统开发者需要掌握一定的Linux命令。Linux命令系统的命令很多,但是对嵌入式系统开发者来说,只要重点掌握20多条即可,其他的需要时可以查询相关资料学习。

Linux命令一般包括文件及文件夹管理命令,用户管理命令,系统管理命令,网络管理命令及其他等

Linux命令格式:

命令 [选项][参数]

Linux命令行风格

linux中有三种约定区分选项和参数的风格:原始的Unix风格、GNU风格和X tookit风格。

Unix风格:以连字符'-'开头的单个字符(System V风格)或没有连字符'-'开头的单个字符(BSD风格)。如果选项后面不带参数,则被称为模式选项,模式选项可以组合在一起使用。如果选项带参数,这些参数要紧接在选项后面(是否以空格分隔可选)。特点是比较简洁,但是选项有可能不够用。

如: gcc -v

GNU风格:使用两个连续的连字符‘--’后接关键字(注意,不是单个字符)。GNU风格的选项不用空格就不能组合使用。选项参数既可以用空格分隔也可以使用单个等号“=”来分隔。特点是容易理解,也容易输入错误或记不住。

如: gcc  --version

X toolkit风格:使用单个连字符‘-’和关键字,并由X toolkit进行解析。比较复杂,最好不用。

注:以下部分内容引用了linux命令

2.3.1文件与目录管理

ls命令

就是 list 的缩写,通过 ls 命令不仅可以查看 linux 文件夹包含的文件,而且可以查看文件权限(包括目录、文件夹、文件权限)查看目录信息等等。

常用参数搭配:

ls -a 列出目录所有文件,包含以.开始的隐藏文件
ls -A 列出除.及..的其它文件
ls -r 反序排列
ls -t 以文件修改时间排序
ls -S 以文件大小排序
ls -h 以易读大小显示
ls -l 除了文件名之外,还将文件的权限、所有者、文件大小等信息详细列出来
           

实例:

(1) 按易读方式按时间反序排序,并显示文件详细信息

ls -lhrt
           

(2) 按大小反序显示文件详细信息

ls -lrS
           

(3)列出当前目录中所有以"t"开头的目录的详细内容

ls -l t*
           

cat 命令

cat 命令用于连接文件并打印到标准输出设备上。

cat 主要有三大功能:

1.一次显示整个文件:

cat filename
           

 2.从键盘创建一个文件:

cat > filename
           

    只能创建新文件,不能编辑已有文件。

3.将几个文件合并为一个文件:

cat file1 file2 > file
           

 cp 命令

将源文件复制至目标文件,或将多个源文件复制至目标目录。

注意:命令行复制,如果目标文件已经存在会提示是否覆盖,而在 shell 脚本中,如果不加 -i 参数,则不会提示,而是直接覆盖!

-i 提示
-r 复制目录及目录内所有项目
-a 复制的文件与原文件时间一样
           

 实例:

(1)复制 a.txt 到 test 目录下,保持原文件时间,如果原文件存在提示是否覆盖。

cp -ai a.txt test
           

 mv 命令

移动文件或修改文件名,根据第二参数类型(如目录,则移动文件;如为文件则重命令该文件)。

当第二个参数为目录时,第一个参数可以是多个以空格分隔的文件或目录,然后移动第一个参数指定的多个文件到第二个参数指定的目录中。

实例:

(1)将文件 test.log 重命名为 test1.txt

mv test.log test1.txt
           

 (2)将文件 log1.txt,log2.txt,log3.txt 移动到根的 test3 目录中

mv llog1.txt log2.txt log3.txt /test3
           

 (3)将文件 file1 改名为 file2,如果 file2 已经存在,则询问是否覆盖

mv -i log1.txt log2.txt
           

(4)移动当前文件夹下的所有文件到上一级目录

mv * ../
           

rm 命令

删除一个目录中的一个或多个文件或目录,如果没有使用 -r 选项,则 rm 不会删除目录。如果使用 rm 来删除文件,通常仍可以将该文件恢复原状。

rm [选项] 文件…
           

   实例:

(1)删除任何 .log 文件,删除前逐一询问确认:

rm -i *.log
           

 (2)删除 test 子目录及子目录中所有档案删除,并且不用一一确认:

rm -rf test
           

(3)删除以 -f 开头的文件

rm -- -f*
           

cd 命令

cd(changeDirectory) 命令语法:

cd [目录名]
           

说明:切换当前目录至 dirName。

实例:

(1)进入根目录

cd /
           

(2)进入主 目录

cd ~
           

(3)进入上一次工作路径

cd -
           

pwd 命令

pwd 命令用于查看当前工作目录路径。

实例:

(1)查看当前路径

pwd
           

mkdir 命令

mkdir 命令用于创建文件夹。

可用选项:

  •     -m: 对新建目录设置存取权限,也可以用 chmod 命令设置;
  •     -p: 可以是一个路径名称。此时若路径中的某些目录尚不存在,加上此选项后,系统将自动建立好那些尚不在的目录,即一次可以建立多个目录。

实例:

(1)当前工作目录下创建名为 t的文件夹

mkdir t
           

    (2)在 tmp 目录下创建路径为 test/t1/t 的目录,若不存在,则创建:

mkdir -p /tmp/test/t1/t
           

chmod 命令

Linux/Unix 的文件调用权限分为三级 : 文件拥有者、群组、其他。利用 chmod 可以控制文件如何被他人所调用。

用于改变 linux 系统文件或目录的访问权限。用它控制文件或目录的访问权限。该命令有两种用法。一种是包含字母和操作符表达式的文字设定法;另一种是包含数字的数字设定法。

常用参数:

-c 当发生改变时,报告处理信息
-R 处理指定目录以及其子目录下所有文件
           

 权限范围:

权限设定字串格式如下 :

[ugoa...][[+-=][rwxX]...][,...]
           
u :目录或者文件的当前的用户
g :目录或者文件的当前的群组
o :除了目录或者文件的当前用户或群组之外的用户或者群组
a :所有的用户及群组
           

 权限代号:

r :读权限,用数字4表示
w :写权限,用数字2表示
x :执行权限,用数字1表示
- :删除权限,用数字0表示
s :特殊权限
           

 实例:

(1)增加文件 t.log 所有用户可执行权限

chmod a+x t.log
           

  (2)撤销原来所有的权限,然后使拥有者具有可读权限,并输出处理信息

chmod u=r t.log -c
           

    (3)给 file 的属主分配读、写、执行(7)的权限,给file的所在组分配读、执行(5)的权限,给其他用户分配执行(1)的权限

chmod 751 t.log -c(或者:chmod u=rwx,g=rx,o=x t.log -c)
           

 (4)将 test 目录及其子目录所有文件添加可读权限

chmod u+r,g+r,o+r -R text/ -c
           

此外chmod也可以用数字来表示权限,语法为:

chmod abc file
           

其中a,b,c各为一个数字,分别表示User、Group、及Other的权限。r=4,w=2,x=1

若要rwx属性则4+2+1=7;

若要rw-属性则4+2=6;

若要r-x属性则4+1=5。

实例:

将test/hello.c设为所有人可读可写可执行

chmod 777 test1/hello.c

或chmod a+rwx  test1/hello.c
           

tar命令

用来压缩和解压文件。tar 本身不具有压缩功能,只具有打包功能,有关压缩及解压是调用其它的功能来完成。

弄清两个概念:打包和压缩。打包是指将一大堆文件或目录变成一个总的文件;压缩则是将一个大的文件通过一些压缩算法变成一个小文件

-c:创建新的归档文件
-x:从归档文件中还原文件
-f:指定打包文件或还原的文件名,这个是必选的,代表文件
-v:详细报告tar处理的文件详细
-z:用gzip来压缩或解压
-j:用bzip2来压缩或解压
-J:用xz来压缩或解压
-C:配合选项x,指定解压文件要存储的位置
           

实例:

将arm-linux-gcc-4.4.3.tar.gz  文件解压在/opt下,解压过程中显示解压信息

tar -xzvf arm-linux-gcc-4.4.3.tar.gz  -C  /opt
           

2.3.2系统命令

useradd:添加用户

使用者:管理员

使用方式:useradd [选项]  用户名 

Linux系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后以这个账号的身份进入系统,不同的用户用不同的权限,不同的用户有不同的主目录。其中root用户是系统的超级管理员,为系统的缺省用户,具有最高权限,其主目录为/root,其他用户的主目录一般位于/home下的与用户同名的目录,其权限由root赋予。

useradd命令用于建立用户帐号。帐号建好之后,再用passwd设定帐号的密码.而可用userdel删除帐号。使用useradd指令所建立的帐号,实际上是保存在/etc/passwd文本文件中。

-c comment 指定一段注释性描述。
-d 目录 指定用户主目录,如果此目录不存在,则同时使用-m选项,可以创建主目录。
-g 用户组 指定用户所属的用户组。
-G 用户组,用户组 指定用户所属的附加组。
-s Shell文件 指定用户的登录Shell。
-u 用户号 指定用户的用户号,如果同时有-o选项,则可以重复使用其他用户的标识号。
           

例:创建了一个用户sam,并设定用户主目录为/home/sam,并属于ada用户组。

useradd  -d  /home/ada  -m  -g ada
           

passwd:设置用户密码

使用者:所有使用者

使用方式:passwd  [选项] [用户名]

用户管理的一项重要内容是用户口令的管理。用户账号刚创建时没有口令,但是被系统锁定,无法使用,必须为其指定口令后才可以使用,即使是指定空口令。超级用户可以为自己和其他用户指定口令,普通用户只能用它修改自己的口令。如果默认用户名,则修改当前用户的口令。普通用户修改自己的口令时,passwd命令会先询问原口令,验证后再要求用户输入两遍新口令,如果两次输入的口令一致,则将这个口令指定给用户;而超级用户为用户指定口令时,就不需要知道原口令。

-l 锁定口令,即禁用账号。

-u 口令解锁。

-d 使账号无口令。

-f 强迫用户下次登录时修改口令。

例:给sam用户设定密码

passwd sam 
           

ps:显示进程状态

使用者:所有使用者

使用方式:ps [选项]  

有的时候我们要终止一个进程的执行或者了解该进程的执行情况,我们就可以通过ps命令获得进程的进程号(pid)等信息。ps 的参数非常多,这里直接给出常用的命令:ps aux  该命令将显示系统中所有进程信息。其输出格式 为:

USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND

其中

  • USER: 进程拥有者
  • PID:  进程号
  • %CPU: 占用的 CPU 使用率
  • %MEM: 占用的存储器使用率
  • VSZ: 占用的虚拟存储器大小
  • RSS: 占用的存储器大小
  • TTY: 终端的次要装置号码 (minor device number of tty)
  • STAT: 该进程的状态:

         D: 无法中断的休眠状态 (通常 IO 的进程)

         R: 正在执行中

         S: 静止状态

         T: 暂停执行

        Z: 不存在但暂时无法消除

        W: 没有足够的记忆体分页可分配

        <: 高优先序的行程

        N: 低优先序的进程

        L: 有存储器分页分配并锁在存储器内 (实时系统或捱A I/O)

  • START: 进程开始时间
  • TIME: 执行的时间
  • COMMAND:所执行的指令

kill:终止进程

使用者:所有使用者

使用方式:kill [选项]  进程号 

kill命令用于删除执行中的程序或工作。

kill可将指定的信息送至程序。预设的信息为SIGTERM(15),可将指定程序终止。若仍无法终止该程序,可使用SIGKILL(9)信息尝试强制删除程序。程序或工作的编号可利用ps指令查看。

  • -s <信息名称或编号>  指定要送出的信息。

例:杀死进程12345

kill 12345
           

例:彻底杀死进程12345

kill -9 12345
           

sudo:以系统管理者的身份执行指令

使用者:在 /etc/sudoers 中有出现的使用者。

使用方式:sudo command

export:设置或显示环境变量

使用方式:export [-fnp][变量名称]=[变量设置值]

说明:在shell中执行程序时,shell会提供一组环境变量。export可新增,修改或删除环境变量,供后续执行的程序使用。export的效力仅及于该次登陆操作。

-f  代表[变量名称]中为函数名称。

-n  删除指定的变量。变量实际上并未删除,只是不会输出到后续指令的执行环境中。

-p  列出所有的shell赋予程序的环境变量。

例:列出当前的所有环境变量值

# export -p 
           

例:显示当前的环境变量PATH的值

# export $PATH

例:将/opt/toolschain/arm-linux-gcc/bin加入当前的搜索路径中

 export PATH=PATH:/opt/toolschain/arm-linux-gcc/bin

小知识:

Linux是一个多用户的操作系统,每个用户登录系统时都会有一个专用的运行环境,通常情况下每个用户的默认的环境都是相同的。这个默认环境就是一组环境变量的定义。每个用户都可以通过修改环境变量的方式对自己的运行环境进行配置。

环境变量主要分三种:1是对所有用户有效,并且是“永久的”,其一般保存在/etc/profile文件中,由root添加。2是仅对当前用户有效,并且是“永久的”,其一般保存在用户目录下的.bash_profile或.bashrc文件。3是仅对当前shell (BASH) 有效(临时的),当前对话结束就失效的。在shell的命令行下直接使用[export变量名=变量值]定义变量,该变量只在当前的shell(BASH)或其子shell(BASH)下是有效的,shell关闭了,变量也就失效了,再打开新shell时就没有这个变量,需要使用的话还需要重新定义。

set:设置所使用shell的执行方式

使用方式:set [选项]  

-a  标示已修改的变量,以供输出至环境变量。

-b  使被中止的后台程序立刻回报执行状态。

-C  转向所产生的文件无法覆盖已存在的文件。

-d  Shell预设会用杂凑表记忆使用过的指令,以加速指令的执行。使用-d参数可取消。

-e  若指令传回值不等于0,则立即退出shell。

-f  取消使用通配符。

-h  自动记录函数的所在位置。

-H Shell  可利用"!"加<指令编号

例:显示环境变量

# set
BASH=/bin/bash
BASH_ARGC=()
BASH_ARGV=()
BASH_LINENO=()
BASH_SOURCE=()
.............................
           

2.3.3网络相关命令

ifconfig 命令

  • ifconfig 用于查看和配置 Linux 系统的网络接口。
  • 查看所有网络接口及其状态:

    ifconfig -a

  • 使用 up 和 down 命令启动或停止某个接口:

    ifconfig eth0 up

    ifconfig eth0 down

ping 命令

ping命令用于检测网络功能是否正常。

实例:

ping  www.baidu.com
           

2.3.4其他

命令 说明 格式
clear 清屏 clear
echo 输出字符串到标准输出设备(屏幕) echo [选项] 字符串
mount 挂载文件系统 mount [选项] 设备或结点目标目录
man MANual pages 显示命令帮助 man [领域代号] 命令名

man是Linux的

*man是Linux的在线帮助系统。这些man page通常是放在/usr/share/man中,但是我们可以通过修改它的man page搜索路径来改变这个命令,修改/etc/man.config即可

2.3.5输入输出重定向和管道

重定向就是使用文件代替标准输入、标准输出和标准错误输出。

重定向有5种方式,分别是: 输出重定向、输入重定向、错误重定向、追加重定向以及同时实现输出和错误的重定向。

标准输入 (stdin)      :代码为 0 ,使用 < 或 << ;

标准输出 (stdout)    :代码为 1 ,使用 > 或 >> ;

标准错误输出(stderr):代码为 2 ,使用 2> 或 2>> ;

其中,有一个箭头的表示以覆盖的方式重定向,而有两个箭头的表示以追加的方式重定向。

可以将不需要的标准输出以及标准错误输出重定向到 /dev/null ,相当于扔进垃圾箱。

如果需要将标准输出以及标准错误输出同时重定向到一个文件,需要将某个输出转换为另一个输出,例如 2>&1 表示将标准错误输出转换为标准输出。

注:以下部分内容摘自《嵌入式Linux应用开发完成手册》,韦东山,人民邮电出版社,2008.8 ISBN978-7-115-18262-3

2.4Linux开发工具的使用

源文件需要经过编译才能生成可执行文件。在windows下进行开发时,只需要单击节几个按键即可编译,集成开发环境已经将各种编译工具的使用封装好了。Linux下一般更多的时候是直接使用编译工具。目前Linux下最常用的C语言编译器是GCC(GNU Compiler Collection),主要涉及的工具有gcc、ld、objcopy、objdump等。不管是生成主机端的程序,还是目标端的程序,gcc的用法是类似的,一般主机端开发工具使用gcc,而目标端使用arm-linux-gcc等。

2.4.1GCC编译器的使用选项

一个C/C++文件要经过预处理(preprocessing)、编译(compilation)、汇编(assembly)和连接(linking)等4个步骤才能变成可执行文件。在日常交流中通常使用“编译”通称这4个步骤,如果不特定指明这4个步骤中的某一个,一般以惯例。

第2章 Linux操作系统应用入门2.1启动Linux系统2.2 Linux文件2.3 Linux 常用命令2.4Linux开发工具的使用2.5 开发环境的建立2.6常用工具的使用

(1)预处理

C/C++源文件中,以“#”开头的命令被称为预处理命令,如包含命令“#include”、宏定义命令“#define”等。预处理就是将要包含(include)的文件插入原文件中,将宏定义展开、根据条件编译命令选择要使用的代码,最后将这些代码输入到一个“.i”文件中等待进一步处理。预处理将要用到cpp工具。

(2)编译

编译就是把C/C++代码(比如上述的“.i”文件)“翻译”成汇编代码,所用到的工具为cc1。

(3)汇编

汇编就是将第二步输出的汇编代码翻译成符合一定格式的机器代码,在Linux系统上一般变形为ELF格式目标文件(obj),用到的工具为as。

(4)连接

连接就是将上步生成的OBJ文件和系统库的OBJ文件、库文件连接起来,最终生成可以在特定平台运行的可执行文件,用到的工具为ld。

一般各个阶段的工具不需要指定,由gcc自动调用。在编译过程中,除非使用了“-c","-S"或“-E”选项(或者编译错误阻止了位置的过程),否则最后的步骤总是连接。

以一个简单的“hello world”为例,代码如下:

/*hello.c*/
#include<stdio.h>
int main(int argc,char **arv){
    printf("hello world!\n");
    return 0;
}
           

 使用gcc,只需要一个命令就可以生成可执行文件hello,它包含了上述4个步骤

$gcc -o hello hello.c
           

加上“-v”选项,即使用“gcc -v -o hello hello.c”命令可以观看编译的细节,下面摘抄关键部分:

cc1 hello.c -o /temp/cctETob7.s
as -o /temp/ccve2KbL.o /temp/cctEtob7.s
collect2 -o hello crt1.o,crti.o crtbegin.o /temp/ccve2KbL.o crtend.o crtn.o
           

 以上3个命令分别对应于编译步骤的预处理+编译、汇编和连接,ld被collect2调用来连接程序。预处理和编译被放在了一个命令(cc1)中进行,可以把它再次拆分为以下两步:

ccp -o hello.i hello.c
cc1 hello.i -o /temp/cctETob7.s
           

 可以通过各种控制选项来控制gcc的动作,下面介绍一些常用的选项。

1.总体选项

(1) -c

预处理、编译和汇编源文件,但是不做连接,编译器根据源文件生成OBJ文件。默认情况下,GCC通过用“.o”替换源文件名的后缀“.c”等,产生OBJ文件。可以使用“-o“选项选择其他名字。

(2)-o file

指定输出文件为file。无论是预处理、编译、汇编还是连接,这个选项都可以使用。如果没有使用“-o”选项,默认的输出结果是:可执行文件为“a.out”;若输入文件的名称是“source.suffix”,则它的OBJ文件是“source.o”,汇编文件是“source.s”,而预处理后的代码送往标准输出。

(3)-v

显示制造GCC根据自身时的配置命令;同时显示编译器驱动程序、预处理器、编译器的版本号。

以一个程序为例,它包含2个文件。代码如下:

/*main.c*/
#include<stdio.h>
extern int add(int x,int y);
int main(int argc,char **arv){
    int i;
    printf("the result=%d!\n",add(3,4));
    return 0;
}
           
/*add.c*/
int add(int x,int y){
   return x+y;
}
           

 使用上面介绍的选项进行编译,命令如下:

$ gcc -c -o main.o main.c
$ gcc -c -o add.o add.c
$ gcc -o test main.o add.o
           

 其中,main.o、add.o是经过了预处理、编译、汇编后生成的OBJ文件,他们还没有被连接成可执行文件;最后一步将他们连接成可执行文件test,可以直接运行以下命令:

$ ./test
the result=7
           

 以上编译过程也可以简写为:

$ gcc -o test main.c add.c
           

(4)-g

要求编译器在编译的时候提供以后对程序进行调试的信息。

2.警告选项

“-Wall”选项基本打开了所有需要注意的警告信息,比如没有指定类型的声明、在声明之前就使用的函数、局部变量除了声明之外就没再使用等。

上面的main.c文件中,第5行定义的变量i没有被使用,但是使用 “gcc -c -o main.o main.c"进行编译时并没有出现提示。可以加上“-Wall”选项,如下:

$ gcc -Wall -c main.c
           

执行上述命令后,得到如下警告信息:

main.c: in function 'main':
main.c:5:warning: unused variable 'i'
           

 3.调试选项

-g:产生调试信息,只有加入该选项,GDB才能使用调试信息。

4.连接器选项

用于连接OBJ文件,输出可执行文件或库文件

(1)object-file-name

如果某些文件没有特别明确的后缀,GCC就认为他们是OBJ文件或库文件(根据文件内容,连接器能够区分OBJ文件和库文件)。如果GCC执行连接器操作,这些OBJ文件将成为连接器的输入文件。比如上面的"gcc -o test main.o add.o"中,main.o、sub.o就是输入文件。

(2)-llibrary

连接名为library的库文件。

连接器再标准搜索目录中寻找这个库文件,库文件的真正名字是“liblibrary.a”。搜素目录除了一些系统标准目录外,还包括用户以“-L”选项指定的路径。一般说来用这个方法找到的文件是库文件-即由OBJ文件组成的归档文件(archieve file)。连接器处理归档文件的方法是:扫描归档文件,寻找某些成员,这些成员的符号目前已被引用,不过还没有被定义。但是如果连接器找到普通的OBJ文件,而不是库文件,就把这个OBJ文件按照平方式连接起来。指定“-l”选项和指定目录名的唯一区别是,“-l”选项用“lib”和“.a"把library包裹起来,而且搜索一些目录。

5.目录选项

目录选项用于查找头文件、库文件或编译器的某些成员。

(1)-Idir

在头文件的搜索路径列表中添加dir目录。

头文件的搜索方法为:如果以”#include<>“包含文件,则只在标准目录开始搜索(包括使用-Idir定义的目录);如果以”#include“包含文件,则先从用户的工作目录开始搜索,在搜索标准库目录。

(2)-I-

任何在”-I“前面用”-I“选项指定的搜索路径只适用于“#include"file"“这种情况;它们不能搜索”#include<>“包含的头文件。如果用”-I“选项指定的搜索路径位于”-I“选项后面,就可以在这些路径中搜索所有的”#include“指令(一般来说”-I“就是这么用)。

(3)-Ldir

在”-I“选项的搜索路径列表中添加dir目录。

2.4.2 ld选项

ld用于将多个目标文件、库文件连接成可执行文件,它的大多数选项和GCC相同。本节主要介绍”-T“选项,该选项可以直接用来指定代码段、数据段、bss段的起始地址,也可以用来指定一个连接脚本在连接脚本中进行更复杂的地址设置。

”-T“选项只用于连接没有底层软件支持的软件(如内核,bootloader等);连接运行于操作系统之上的应用程序时,无需指定,它们使用默认的方式进行连接。

注:查看缺省ld脚本方法

ld --verbose
           

1.直接指定代码段、数据段、bss段的起始地址

格式如下:

-Ttext startaddr
-Tdata startaddr
-Tbss  startaddr
           

 其中的"startaddr"分别表示代码段、数据段和bss段的起始地址,它是一个16进制数。如:

ld -Ttext 0x00000000 -g led_on.o -o led_on_elf
           

它表示代码段的运行地址为0x00000000,由于没有定义数据段、bss段的起始地址,它们被依次放在代码段的后面。

2.使用连接脚本设置地址

如下例:

ld -Ttimer.lds -o timer_elf head.o init.o interrupt.o main.o
           

它使用连接脚本timer.lds来设置可执行文件timer_lef的地址信息,timer_elf文件内容如下:

SECTIONS{
    .=0x30000000;
    .text:{*(.text)}
    .rodata ALIGN(4):{*(.rodata)}
    .data ALIGN(4):{*(.data)}
    .bss ALIGN(4):{*(.bss) *(COMMON)}
}
           

 解析timer_elf文件之前,先讲解连接脚本的格式。连接脚本的基本命令是SECTIONS命令,它描述了输出问哪的“映射图”:输出文件中各段、各文件怎么放置。一个SECTIONS命令内部包含一个或多个段,段(Section)是连接脚本的基本单元,它表示输入文件中的某部分怎么放置。

完整的连接脚本格式如下,它的核心部分是段(Section):

SECTIONS{
...
    secname start ALIGN(align) (NOLOAD): AT(ldadr)
    {contents}>region:phdr=fill
...
}
           

secname和contents是必需的,前者用来命名这个段,后者用来确定代码中的什么部分放在这个段中。

start是这个段重定位地址,也称为运行地址。如果代码中有位置无关的指令,程序在运行时,这个段必须放在这个地址上。

ALIGN(align):虽然start指定了运行地址,但是仍可以使用BLOCK(align)来指定对齐的要求-这个对齐的地址才是真正的运行地址。

(NOLOAD):告诉加载器,在运行时不用加载这个段。这个段只有在有操作系统的情况下才有意义。

>region:通过使用>region把一个节赋给前面已经定义的一个内存区域比如下面的这个例子:

MEMORY { rom : ORIGIN = 0x1000, LENGTH = 0x1000 }

SECTIONS {

ROM : { *(.text) } >rom

}
           

:phdr:通过使用`:PHDR'把一个节赋给前面已定义的一个程序段。如果一个节被赋给一个或多个段,那后来分配的节都会被赋给这些段,除非它们显式使用了':PHDR'修饰符。你可以使用':NONE'来告诉连接器不要把节放到任何一个段中。看下面的例子:

PHDRS { text PT_LOAD ; }

SECTIONS {

.text : { *(.text) } :text

}
           

fill:你可以通过使用'=FILLEXP'为整个节设置填充样式。FILLEXP是一个表达式。任何没有指定的输出段内的内存区域(比如,因为输入段的对齐要求而产生的裂缝)会被填入这个值。如果填充表达式是一个简单的十六进制值,比如,一个以'0x'开始的十六进制数字组成的字符串,并且尾部不是'k'或'M',那一个任意的十六进制数字长序列可以被用来指定填充样式;前导零也变为样式的一部分。对于所有其他的情况,包含一个附加的括号或一元操作符'+',那填充样式是表达式的最低四字节的值。在所有的情况下,数值是big-endian.你还可以通过在输出节命令中使用'FILL'命令来改变填充值。

现在可以解析前面的连接脚本timer.lds的含义了。

第2行表示设置“当前运行地址”为0x30000000

第3行定义了一个名为“.text”的段,它的内容为“*(.text)”表示所有输入文件的代码段。这些代码段被集合在一起,起始运行地址为0x30000000

第4行定义了一个名为".rodata"的段,在输入文件timer_elf中,它紧挨着“.text"段存放。其中的“ALIGN(4)”表示起始运行地址为4字节对齐。

第5、6行的含义类似。

完整版的官网Gnulinkerscript

2.4.3 objcopy选项

objcopy被用来复制一个目标文件的内容到另外一个文件中,可以使用不同于源文件的格式来输出目的文件,即可以进行格式转换。在linux系统中,一般用于将ELF格式的可执行文件转换为二进制文件。

使用格式如下:

objcopy [选项][参数] 源文件  目标文件
           

(1)-I bfdname

用来指明源文件的格式,bfdname指的是源文件的标准格式名。如果不指定源文件格式名,objcopy会自己去分析元文件的格式。

(2)-O bfdname

用来指定输入文件的格式

(3)-S

不从源文件中复制重定位信息和符号信息到目标文件中。

(4)-g

不从源文件中复杂调试符号到目标文件中去。

在编译bootloader、内核时,常用arm-linux-objcopy命令将ELF格式的生成结果转换为二进制文件,比如:

$ arm-linux-objcopy -O binary -S elf_file bin_file
           

2.4.4 objdump选项

objdump用于显示二进制文件信息,常用于查看反汇编代码。

格式如下:

objdump [选项][参数] 源文件
           

(1) -b bfdname

指定目标码格式。这不是必须的,objdump能自动识别许多格式。可以使用“objdump -i"命令查看支持的目标码格式列表。

(2)-d

反汇编可执行段

(3)-i

显示支持的目标格式和CPU架构

4.-m

指定反汇编目标文件时的架构

将ELF格式文件转换为反汇编文件:

arm-linux-objdump -D elf_file>dis_file
           

将二进制文件转换为反汇编文件:

arm-linux-objdump -D -b binary -m arm bin_file>dis_file
           

2.4.5 GDB调试器

无论多么优秀的程序员,必须经常面对的一个问题就是调试。当程序编译完成后,它可能无法正常运行;或许程序会崩溃;或许只是不能正常地运行某些功能;或许它的输出会被挂起;或许不会提示要求正常的输入。无论在何种情况下,跟踪这些问题,特别是在大的工程中,将是开发中最困难的部分。

linux系统中包含了GNU调试程序GDB,这是一个用来调试C/C++程序的调试器,可以使程序开发者在程序运行时观察程序的内部结构和内存的使用情况。

GDB程序调试的对象时可执行文件,而不是程序的源代码文件。然而,并不是所有的可执行文件都可以用GDB调试。如果要对可执行文件进行调试,需要在执行GCC指令编译程序时,加上-g参数,指定程序在编译时包含调试信息。调试信息宝航程序里的每个变量的类型和在可执行文件里的地址映射以及源代码的行号。GDB利用这些信息时源代码和机器码相关联。

1.GDB的启动

在终端窗口中,有两种方法运行GDB,即在终端窗口的命令行中直接输入gdb命令或gdb filename命令启动GDB。

方法1-启动GBD后执行file filename 命令,即

gdb
file filename
           

执行上述两条命令就可以启动GDB,并装入可执行的程序filename

方法2-启动的同时装入可执行的程序,即

gdb  filename
           

启动GDB以后,就可以使用GDB的命令调试程序。

2.GDB的常用命令

GDB中的命令主要分为工作环境相关命令,设置断点与恢复命令、源代码查看目录,查看运行数据相关命令即修改运行参数命令等。GDB可以通过查找命令所属的种类(class),可以从相关class中找到相应命令。

 (1) help :此命令可列出目录的种类

(2)help [command]:若用户已知命令名,可以直接键入来查看命令

(3) info  b: 查看所设断点

(4) break 行号或函数名:设置断点

(5)delete[断点号]:删除指定断点号,其断点号为info b中的第一栏。若为默认断点号则删除所有断点。

(6)disable[断点号]:停止指定断点,使用info b 仍然能查看此断点

(7)enable[断点号]:激活指定断点

(8)step:单步恢复程序运行,且进入函数调用

(9)next:单步恢复程序运行,但进入函不数调用

(10)finshi:运行程序,直到当前函数完成返回

(11)continue:继续执行函数,直到函数结束或遇到新的断点

(12)list<行号>|<函数名>:查看指定位置代码

  (13) file[文件名]:加载指定文件

(14)print 表达式|变量:查看程序运行时对应表达式和变量的值

  (15) x<n/f/u>:查看内存变量例如。其中n为整数表示显示内存的长度,f表示显示的格式,u表示从当前地址往后请求的字节长度。

(16)display 表达式:设定在单步运行或其他情况中,自动显示的表达式的内容。

(17)run:执行当前被调试的程序

(18)kill:停止正在调试的程序

(19)set 变量=设定值:单步执行时,修改运行时的参数,并使该变量按照用户当前输入的值继续运行。

(20)quit:退出GDB

要注意,在不引起歧义的情况下,输入完整的命令和输入命令的首字母效果是一样的。

2.4.6GNU make命令和Makefile文件

使用GCC的命令行进行程序编译在单个文件下是比较方便的,当工程中的文件逐渐增多,甚至变得十分庞大时,使用GCC命令行编译机会渐渐变得力不从心。Linux中得make工具提供了一种管理工程的能力,可以方便地进行程序的编译,对更新的文件进行重新编译。

GNU make的主要功能时读入一个文本文件Makefile,并根据Makefile的内容执行一系列的工作。Makefile的默认文件名为GNU makefile、makefile或makefile,也可以在make的命令行中指定别的文件名。多数Linux程序员使用第三种文件名,即Makefile。因为第一个字母是大写,通常被列在一个目录的文件列表的最前面。

Makefile文件包含一些规则,这些规则主要是描述哪些文件(称为target目标文件,注意,不是指编译时产生的目标文件)是从哪些别的文件(称为dependency依赖文件)中产生的,以及用什么命令(command)来执行这个过程。

依靠这些信息,make会对磁盘上的文件执行检查,如果目标文件的生成或被改动的时间(称为时间戳)至少比它的一个依赖文件还旧的话,make就执行相应的命令,以更新目标文件。目标文件不一定是最后的可执行文件,可以是任何一个中间文件,并可以作为其他目标文件的依赖文件。

最简单的Makefile文件如下:

hello:hello.c
    gcc -o hello hello.c
clean:
    rm -f hello
           

将上述4行存入Makefile文件(注意必须以Tab键缩进第2、4行,不能以空格缩进),保存经当前工作目录,然后直接执行make命令即可编译程序,执行“make clean”即可清除编译出来的结构。

一个简单的Makefile文件包含一系列的“规则”,规则一般是用来解释怎样和 何时重建目标,其样式如下:

目标(target)...:依赖(prerequiries)...
<tab>命令(command)
           

目标(target)通常是要生成的文件的名称,可以是可执行文件或OBJ文件,也可以是一个执行的动作名称,诸如“clean”。

依赖是用来产生目标的材料(比如源文件),一个目标通常有几个依赖。

命令是产生目标是执行的动作,一个给i则可以含有几个命令,每个命令占一行。

注意:每个命令行前面必须是一个Tab字符,即命令行第一个字符是Tab,这是容易出错的地方。

要想完整地了解Makefile的规则请参考《GNU Make 使用手册》,也下面仅可以参看《跟我一起写makefile》链接:https://pan.baidu.com/s/1VZUmMHwia6x0F1X--qybfQ 提取码:r3a7

给出一个Makefile的模板,一般的中小型工程可照此改写。

# Project: pattern
CC        = gcc 
Target    = pattern
SRC_DIRS  = ./source ./com ./include ./westWorldWithWoman


SRC_FILE  = $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.c))
OBJ       = $(patsubst %.c,%.o,$(subst /,\,$(SRC_FILE))) 
LINKOBJ=$(OBJ)

LIBS     = -L"D:\MinGW64\lib" -L"D:\MinGW64\x86_64-w64-mingw32\lib" -static-libgcc -g3
INCS     = -I"D:\MinGW64\include" -I"D:\MinGW64\x86_64-w64-mingw32\include"  -I"C:\MinGW64\lib\gcc\x86_64-w64-mingw32\4.9.2\include"

CFLAGS   = $(INCS) -g3 -D__DEBUG__ 
RM       = rm -f
 
 
.PHONY: all all-before all-after clean clean-custom exam
 
all: all-before $(BIN) all-after
 
clean: clean-custom
	${RM} $(Target) $(OBJ) 
 
$(Target): $(OBJ)
	$(CC) $(LINKOBJ) -o $(Target) $(LIBS)
$(OBJ):%.o:%.c
	$(CC) -c $< -o [email protected] $(CFLAGS)
           

第2行表示编译的工具为gcc

第3行表示编译出的可执行文件名

第4行表示源文件所在的目录

第7行利用make定义的函数,从原文件中搜索出所有的源文件

第8行利用make定义的函数,从源文件中列出所有的OBJ文件

第9行表示需要连接的目标文件

第11行定义了编译时连接的库文件

第12行添加头文件了的搜索路径列表

第14行定义声明了了编译选项:包含的头文件,关闭了优化选项,定义了宏DEBUG

第15行定义一个了变量

第18行声明了伪目标

第20行定义了all的规则

第22-23行定义clean目标规则:清除所有的OBJ文件及编译出的可执行文件

第25-26行定义了可执行文件的生成规则

第27-28行定义了OBJ文件的生成规则

一般我们只需要改3、4量行。

2.5 开发环境的建立

2.5.1主机与目标板结合的交叉开发模式

开发PC机上的软件时时,可以直接在PC机上编辑、编译、调试软件,最终发布的软件也在PC机上运行。对于嵌入式开发,最初的嵌入式设备是一个空白的系统,需要通过主机为它构建基本的软件系统,并烧写到设备中;另外,嵌入式设备的资源一般并不足以开发软件,所以需要用到交叉开发模式:在主机上编辑、编译软件,然后再目标板上运行、验证程序。

主机指PC机,目标板指嵌入式设备。

注意:目前市面上的卡片机,如树莓派等已经可以看成是一个完整的计算机系统,软件可以直接再目标板上开发,可以不用交叉开发模式。

进行嵌入式Linux开发时一般可分为以下4个步骤:

(1)在主机编译bootloader,让后通过JATG烧写如设备。

通过JTAG接口烧写程序的效率非常低,它适用于烧写空白设备。为方便开发,通常选用具有串口传输、网络传输、烧写Flash功能的Bootloader(如uboot),它可以快速地从主机获取可执行代码,然后烧入单板,或直接运行。

(2)在主机上编译嵌入式Linux内核,通过Bootloader烧入设备,或直接运行。

一个可以在单板上运行的嵌入式Linux内核是继续后续开发的基础,为方便调试,内核应该支持网络文件系统(NFS),即将应用程序放在主机上,单板启动嵌入式Linux内核后,通过网络来获取程序,然后运行。

(3)在主机上制作嵌入式根Linux文件系统,通过Bootloader烧入设备,或直接运行。

对于操作系统来说,文件时至关重要的。内核启动的最后步骤是挂载根文件系统,包含init进程、shell、文件系统、网络系统等的工具集、系统配置文件和连接库等。在嵌入式系统中,文件存储的媒介通常时Flash(闪存)。如何在flash上建立高速、可靠、稳定、易于维护、可长期使用的文件系统一直是嵌入式系统的一个热门话题。按照不同类型的Flash的特点,出现了很多专门正对Flash的文件系统,如jffs,yaffs,cramfs等。这些文件系统需要烧写单板,在开发阶段一般采用NFS文件系统以避免频繁烧写。

另外嵌入式系统资源受限,其工具集一般采用BusyBox来生成,以减少自己的体积。

(4)在主机上编译各类应用程序,并加入文件系统,经验证后烧入设备。

在开发阶段,主机上编译的应用程序一般是嵌入式设备启动内核以后通过NFS运行它们,得到验证以后,将其加入根文件系统,然后随文件系统一起烧入设备。若嵌入式设备的文件系统不采用NFS,则应用程序可以通过网络、串口,甚至是U盘等,拷贝到设备上(前提是根文件系统采用可读写文件系统),也可以通过网络,以NFS形式将应用程序挂载到嵌入式设备上。

另外有时嵌入式系统需要一个图形用户界面,如Qtopia、MiniGUI等,这时也需要在这一步进行移植和配置。

以上的4个步骤是相对独立的,每一步都可以相对独立开发和烧写。目前市面上的主流开发板,其前3个步骤一般已经做好,第4步的GUI也有可能做好了,一般的开发者可以跳过,若不满足要求,开发者可以重新构建和烧写。

另外有部分芯片,比如支持从SD卡等方式启动,可以将uboot、内核、文件系统等烧写进SD卡中,制成“启动盘”,开发完成后将SD卡内容在烧写入设备,其本质和上述过程实际上一致的,这种方式以samsung系列芯片为代表。

2.5.2软件环境的构建

一般说来,不管是开发主机应用程序,还是嵌入式应用程序,我们采用的工具都是GCC,使用的方法都是一样的,只是生成的机器码不一样,主机是针对x86系统的,而嵌入式设备一般针对的是诸如ARM,powerpc等。主机上一般已经安装了gcc工具,我们还需要安装另一套针对目标板的gcc工具(有时也称为工具链),包括gcc, gdb, ld, as, objcopy,objdump及有关库等,这些可在工具在主机上运行,但生成目标机格式的机器代码。

刚开始学习时,建议使用已经做好的工具链,当对系统很熟悉后,或系统资源受限,用户也可以自己制作、编译自己的工具链。

使用制作好的工具链

使用以下的命令解压到

tar -xjf arm-linux-gcc-3.4.5-glibc-2.3.6.tar.bz
           

2.6常用工具的使用

2.6.1超级终端

基于Linux的嵌入式系统需要一个控制终端,这个终端通常是串口终端,一般我们在PC机上通过一个终端软件通过串口与目标板相连。尽管很多的教材推荐使用的终端软件为minicom(Linux系统下的串口终端),secureCRT等串口终端,我还是推荐大家使用windows下的超级终端,原因就是超级终端使用简单,而我们大家大部分习惯使用的主机系统还是windows系统。很遗憾的是在win7以前超级终端是系统自带的小工具,之后就要大家下载了。https://pan.baidu.com/s/17z3HGx2lJPhYaD5oYa_tVQ 提取码:cz1h

需要注意的是串口通讯的参数一般波特率为115200 ,格式为8N1,无数据流控制。

2.6.2tftp服务器

tftp用于通过网络下载和上传文件链接:https://pan.baidu.com/s/1TgFfrQRyXxYkBWo6LVKuKw 提取码:xvzz

需要注意tftp和开发板应该在同一个子网内。在windows查询本机的ip地址方法为:

ipconfig
           

开发板可以通过网线直连到PC机上,也可以PC机和开发板都连接到同一个路由器上,建议采用第二种方式,不过要注意地址冲突,尤其是在实验室,多个人同时需要设置时。

开发板的ip地址根据不同的阶段有不同的设置方式,在uboot下载模式下的方式可参考下一节环境参数设置内容,linux启动以后使用ifconfig命令进行设置。

2.6.3U-boot的使用

内核和文件系统的更新、烧写,启动参数的配置等都要借助bootloader来进行,一般市面购买的开发板其中的bootlaoder已经烧写,这给开发人员以极大的便利。一些简单程序,尤其是裸机程序,通过JTAG进行烧写运行太复杂了,我们这时就可以借助uboot功能进行学习,这对于初学者非常有利。

将开发板通过串口连接到主机,启动主机的串口终端(如超级终端,secureCRT等),设置好通讯参数 (一般波特率为115200 ,格式为8N1)上电,按任意键,即进入U-boot控制界面,可以运行各种命令,比如下载文件到内存,擦除、读写Flash,运行内存、Nor Flash、Nand Flash中的程序,查看、修改、比较内存在的数据等。U-boot接收的数据都是16进制,输入时可以省略前缀0x,0X。

(1)帮助命令help

运行help命令可以看到U-boot中所有命令的作用,如果要查看某个命令的使用方法,运行“help 命令名”,比如“help boot m"。可以使用”?“来代替help,比如直接输入”?“、”?bootm“。

(2)环境变量命令

printenv :命令打印区别环境变量

printenv name1 name2...:打印名字为name1、name2、...的环境变量

setenv name  value :设置名字为name的环境变量的值为value

setenv  name :删除名字为name的环境变量

saveenv :上面的设置、删除操作只是在内存中进行,saveenv将更改后的所有环境变量写入Flash中

常用环境变量列表

bootdelay 执行自动启动(bootcmd中的命令)的等候秒数 

baudrate 串口控制台的波特率 

bootfile 默认的下载文件名 

bootargs 传递给Linux内核的启动参数 

bootcmd 自动启动时执行命令 

stdin 标准输入设备,  一般是串口  

stdout 标准输出,  一般是串口,也可是LCD(VGA)

stderr   标准出错,一般是串口,也可是LCD(VGA)

serverip TFTP服务器端的IP地址 

ipaddr 本地的IP地址  

ethaddr 以太网的MAC地址 

netmask 以太网的网络掩码                                                                                                                                                 gatewayip 以太网的网关

(3)启动命令

不带参数的boot 、bootm命令都是执行环境变量bootcmd所指定的目录

bootm[addr [arg...]]命令启动存放在地址addr处的U-boot格式的映像文件(使用u-boot目录tools下的mkimage工具制作得到)

go addr [arg...]与bootm命令类似,启动存放在地址addr处的二进制文件,[arg...]表示参数

(4)串口下载命令

loads [ off ] 通过串口,下载S-Record格式文件到off位置

loadb [ off ] [ baud ]通过串口,以baud速率,下载binary到off位置(即:kermit protocol)。loadb命令可以通过串口线下载二进制格式文件。

loady [load address] [baud rate]支持Ymodem协议

(5)网络命令

tftp addr filename 将文件下载到addr位置 //pc端需配置好tftp服务器

nfs addr pc端IP:/带路径的文件名   //pc端需配置好nfs服务器

ping     ip  //检测网络是否通

实例:使用u-boot来执行程序

使用JTAG烧写程序过程非常缓慢,如果用uboot来烧写Flash效率会高很多,我们可以烧写二进制文件到Flash中,或直接下载到内存中,然后使用go命令执行它,不需要将二进制文件制作成u-boot格式(bootm启动uboot格式程序)。假设有一个程序的二进制可执行文件test.bin,连接地址为0x30000000.

1)使用网络下载

首先将它放在主机的tftp或nfs目录下,确保已经开启tftp或nfs服务;然乎将它下载到内存0x30000000处,最后使用go命令执行它,如下所示:

tftp 0x30000000 test.bin 或nfs 0x30000000 192.168.1.55:/work/nfs_root/test.bin
go 0x30000000
           

2)使用串口下载

loady 0x30000000 test.bin
go 0x30000000
           

实例:设定内核启动参数

控制终端为串口,波特率为115200,文件系统为jffs2

set bootargs 'console=ttyS0,115200 root=/dev/mtdblock2 rootfstype=jffs2'
saveenv
           

表示控制台为ttys0,波特率为115200,根文件系统的节点为/dev/mtblock2 类型为jfffs2

setenv bootargs 'console=ttyS0 root=/dev/nfs rw nfsroot=192.168.1.22:/nfsroot/rootfs ip=192.168.1.55 '
saveenv
           

表示控制台为ttys0,根文件系统的节点为/dev/nfs nfs文件系统,可读可写,该文件系统位于主机192.168.1.22  的/nfsroot/rootfs文件夹,目标板的ip地址为192.168.1.55

继续阅读