1 / 103

第 6 章 嵌入式 Linux 应用程序开发

第 6 章 嵌入式 Linux 应用程序开发. 本章主要内容. Linux 介绍 Linux 开发工具 Linux 常用命令 Linux 编程. 6.1 Linux 介绍. Linux 定义 Linux 优势 Linux 种类 如何选择 linux 版本. 1. Linux 定义.

anja
Download Presentation

第 6 章 嵌入式 Linux 应用程序开发

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第6章 嵌入式Linux应用程序开发

  2. 本章主要内容 • Linux介绍 • Linux开发工具 • Linux常用命令 • Linux编程

  3. 6.1 Linux介绍 • Linux定义 • Linux优势 • Linux种类 • 如何选择linux版本

  4. 1. Linux定义 • Linux一般是指Linux内核、Linux系统、Li nux发行版。严格意义上说Linux是指由Linus Torvalds维护的并发布的内核。它的代码基只包括内核而不包括其它方面的应用。内核提供系统核心服务,如进程管理,进程的调度,虚拟文件系统,内存的管理等等。 • 嵌入式Linux,一般是指把Linux内核移植到一个专用嵌入式设备的CPU和主板上。现在有很多公司提供嵌入式Linux解决方案。通常包括一个移植的内核和嵌入式Linux的开发工具以及根据应用需要裁减的应用程序,有时还提供实时扩展的内核。就大部分而言,嵌入式Linux和桌面Linux提供的API函数和内核源代码都是相同的。开发工具主要包括源码浏览器、交叉编译器、调试器、项目管理软件等等。这些工具一般都是装在主机上。

  5. 2. 嵌入式Linux种类 • 嵌入式系统的划分一般是根据使用对象进行划分,如消费类电子等等。为了更好的理解所设计的系统,这里按照尺寸,时间约束,网络,用户交互的程度划分。 • 尺寸:小系统,中等系统,大系统 小系统-CPU的性能比较低,ROM<2MB RAM<4MB 中系统-CPU的性能中等,ROM32MB RAM64MB左右 大系统-CPU性能高,存储量大 • 时间约束:实时,非实时 • 网络连接性 • 用户交互

  6. 3. Linux优势 • Linux是免费的 • Linux的费用低 • Linux的所有部分可以充分地定制 • Linux可以运行在低档,便宜的硬件平台 • Linux是强大的 • Linux对源代码质量有一个高标准 • Linux内核非常小,而且紧凑 • Linux与很多常见的操作系统高度兼容 • Linux有很好的支持 • Linux有很多合适的工具

  7. 4. 如何选择Linux的版本 • DIY-自己动手做一个满足需要的Linux版本 • 选择商用Linux版本 • 授权和涉及到的授权 • 是否满足你的需要,是否有合适的开发工具 • 是否能够提供足够的支持 • 信誉 • 文档

  8. 6.2 Linux开发工具 • GCC-GNU Compiler Collection,包含一系列针对不同语言和不同目标平台,以及可运行在不同主机系统上的编译器 • Make-维护文件的依赖关系 • GDB-负责程序调试 • Glibc-标准C库,数学库,以及板级程序库 • 集成开发环境

  9. 1. GCC-程序编译 • GCC支持的前端 GCC支持的语言包括C(gcc),C++(g++), Fortran(g77), Java(GCJ)和Ada(GNAT) • GCC支持的后端 后端的扩展机制使得GCC能够支持多种类型的体系结构,从RISC,CISC到DSP都有支持。 • GCC支持的主机系统 它可以运行在几乎所有操作系统的平台上(GNU/Linux)DOS Windows

  10. GCC程序编译 • hello.c #include <stdio.h>int main(void){printf ("Hello world, Linux programming!\n");return 0;}然后执行下面的命令编译和运行这段程序: # gcc hello.c -o hello# ./helloHello world, Linux programming!

  11. GCC-程序编译

  12. GCC 编译流程

  13. GCC选项 • -g:在可执行文件中输出调试信息,通常是为调试器gdb所用 • -On:代码优化,n随着系统的不同而不同 • -Idir:指定头文件搜索目录 gcc foo.c –I/home/chen/include –o foo • -Ldir:指定在目录中需要搜索的库(动态库.so 和静态库.a) gcc foo.c –L/home/chen/lib –lfoo –o foo • -static:链接时使用静态链接 • -elf2flt:将可执行文件头转换为flt平板格式 • -c:只预处理,编译和汇编生产obj文件

  14. 2. Make-维护文件的依赖关系 • make:使应用程序的编译和连接自动化 • make:使产生可执行文件的时间大为缩短 • Make:可以管理大型项目 • make:按照代码之间的时间依赖关系维护文件 • make规则文件:Makefile,该文件包括目标定义,执行命令,宏定义和make伪指令 • Makefile文件的编写可以手工,也可以自动,使用工具软件可以自动生成Makefile文件 • Make使用的缺省文件为当前目录下的makefile或Makefile,也可以使用命令行参数-f指定文件名 • $make –f newmakefile

  15. Makefile文件 • Makefile文件包含以下内容 • 宏定义 • 源文件之间的相互依赖关系 • 可执行的命令 • Makefile中的宏 宏名称=设定值 如source =test1.c test2.c test3.c • 当要使用宏时,需要用()将宏扩起来 • 依赖关系-两个或多个文件间彼此的关系 目标:依赖文件;命令 如 test:test.c; gcc –o test test.c test和test.c有依赖关系,如果test.c改变,test也随之改变 • 或是把[命令]写在下一行,需有定位字元作为前导,因此可写成 • test:test.c gcc-o test test.c

  16. Makefile文件 • 01 # Makefile for cshow 02 # By Ivor Chen 03 # 08/31/1994 04 CC = gcc 05 OPTIMIZE = -fomit-frame-pointer -O2 -s 06 CFLAGS = $(DEFINES) $(OPTIMIZE) 07 LFLAGS = -N 08 PROGS = cshow 09 PROGS_O = cshow.o 10 LIBS = -lvgagl -lvga 11 all: progs 12 progs: $(PROGS) 13 objs: $(PROGS_O) 14 $(CC) $(CFLAGS) -c -o $*.o $.depend 15 gcc -MM $(patsubst %.o,%.c,$(PROGS_O)) >>.depend 1617 include .depend • 18 clean: • rm *.o

  17. Make指令 • Make [flags] [macro definition] [targets] • flags • -f file 指定file为描述文件 • -I dir 当包含其它makefile文件时,利用该选项搜索 • -h help文档 • marco definition • make “LIBS = -ll -ls” • target指定make要编译的目标,并且允许同时定义编译多个目标,操作时按照从左向右的顺序依次编译target选项中指定的目标文件。如果命令行中没有指定目标,则系统默认target指向描述文件中第一个目标文件。 • make clean

  18. 3. GDB-程序的调试 •  GDB是自由软件基金会(Free Software Foundation,FSF)的软件工具之一。它的作用是协助程序员找到代码中的错误。如果没有GDB的帮助,程序员要想跟踪代码的执行流程,唯一的办法就是添加大量的语句来产生特定的输出。但这一手段本身就可能会引入新的错误,从而也就无法对那些导致程序崩溃的错误代码进行分析。GDB的出现减轻了开发人员的负担,可以在程序运行的时候单步跟踪自己的代码,或者通过断点暂时中止程序的执行。此外,他们还能够随时察看变量和内存的当前状态,并监视关键的数据结构是如何影响代码运行的。

  19. GDB调试方法 • 如果想对程序进行调试,必须先在用GCC编译源代码时加上-g选项,以便产生GDB所需要的调试符号信息。例如,debugme.c是一个存在错误程序,可以使用如下的命令对其进行编译,同时产生调试符号:# gcc -g debugme.c -o debugme • 如果愿意的话,还可以在编译时使用“-ggdb”选项来生成更多的调试信息。由于这些调试信息中的相当一部分是GDB所特有的,所以生成的代码将无法在其它调试器中正常调试。对于大多数情况来说,普通的-g选项就足够了。需要注意的是,GCC虽然允许同时使用-g(调试)和-o(优化)选项,但优化会影响最终生成的代码,导致程序源代码和二进制代码之间的关系变得复杂起来。如果不想为调试制造障碍,建议不要将-g和-o选项一同使用,并且只在程序彻底调试完后才开始进行代码优化。这样调试过程将变得相对轻松和愉快。

  20. 3. GDB-程序的调试 • GDB具有远程调试功能-对嵌入式非常有用 • GDB可以调试各种程序,包括C,C++,JAVA,PASCAL等 • 远程调试可以设置断点,检验内存,同目标交换信息-相当于简易的仿真器 • GDB可以显示其自身和所调试的目标间的远程串行调试信息,也可依将该信息记录到日志文件中去。 • GDB可以求解在控制台中输入的任意C表达式的值,包括包含有远端目标的函数功能调用的表达式 • print fo(sh_sci[current_sci]->smr.brg) • GDB拥有脚本语言,允许对目标自动的设置和检测。 • GDB拥有跟踪点的功能,该功能可以记录某个运行程序的信息,而尽可能的不打断程序收集数据

  21. GDB-程序的调试 • Host > gdb myprogram • Gdb>target remote /dev/ttys0 • Gdb>load //程序运行至main • Gdb >display foo //目标在main()处停止 • gdb> stepi //目标执行一个指令 • Gdb>quit //退出调试

  22. 4. 集成开发环境 • 很多公司提供集成开发环境,一般这些集成开发环境 主要用于本地的开发,也可以通过定制为交叉开发环境。下表列出了几种集成开发环境

  23. 集成开发环境 • 在Linux环境下kdevelo和SourceNavigator比较流行 • 在Windows环境下sourceInsight比较流行 • 最重要是个人的嗜好,偏好于哪个编程环境,可以是图形的,也可以是命令行的。

  24. 5. Glibc • 由于嵌入式系统的尺寸决定了GNU lib有时不太合适,有很多库可以选择,这里给出了uclibc,diet libc,yaffs • uclibc • uclibc是开发嵌入式Linux系统的c库,它比glibc库小,但是基本上glibc支持的应用uclibc都支持,把应用从glibc移植到uclibc只是重新编译源代码就可以了,uclibc库甚至支持共享库和线程。 • 具体请参看 http://www.uclibc.org • diet libc • diet libc和glibc兼容,它和uclibc不同的是它从头写一个嵌入式库。

  25. 6.3 Linux编程 • Hello world • 目录和文件 • 标准IO库 • 进程和线程 • 进程的建立和终止 • 进程间通信 • 多线程编程

  26. Linux编程-hello world • #include <stdio.h> • int main(void) { • printf(“hello world”); • return 0; • } • gcc –o hello.c • ./a.out • $hello world

  27. Linux编程 -目录和文件 • 文件和目录 • 文件属性 • 文件类型 • 文件操作

  28. Linux编程 -目录和文件 • Linux以一种层次的树状结构来管理文件的名字空间。“树”由文件和目录组成,其中所有文件都在“叶子”的位置 • 目录的内容是所有在该目录底下的文件及其它子目录的名字信息 • 文件和目录的名字是由一些除去“/”和空字符的ASCII字符组成 • 根目录通常写为“/” • 文件名字在整个文件系统中不一定唯一,但要求在该文件所在的目录中唯一即可

  29. Linux文件结构 • /根目录 ┃ ┏━━━━┳━━━━━┳━━━━━┳━━━━━╋━━━━━┳━━━━━┳━━━━━┳━━━━━┓ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ bin home dev etc lib sbin tmp usr var ┃ ┃ ┏━┻━┓ ┏━━━━┳━━━┳━━━┳━┻━┳━━━┓ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ rc.d cron.d X11R6 src lib local man bin ┃ ┃ ┃ ┏━━━┳━━━┳━┻━┳━━━━┓ ┃ ┏━━━╋━━━┓ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ init.d rc0.d rc1.d rc2.d …… linux bin lib src • linux采用的是树型结构。最上层是根目录,其他的所有目录都是从根目录出发而生成的。微软的DOS和windows也是采用树型结构,但是在DOS和windows中这样的树型结构的根是磁盘分区的盘符,有几个分区就有几个树型结构,他们之间的关系是并列的。但是在linux中,无论操作系统管理几个磁盘分区,这样的目录树只有一个。从结构上讲,各个磁盘分区上的树型目录不一定是并列的。

  30. 文件结构 • /bin 二进制可执行命令/dev 设备特殊文件/etc 系统管理和配置文件/etc/rc.d 启动的配置文件和脚本/home 用户主目录的基点,比如用户user的主目录就是/home/user,可以用~user表示/lib 标准程序设计库,又叫动态链接共享库,作用类似windows里的.dll文件/sbin 系统管理命令,这里存放的是系统管理员使用的管理程序/tmp 公用的临时文件存储点/root 系统管理员的主目录(呵呵,特权阶级)/mnt 系统提供这个目录是让用户临时挂载其他的文件系统。/lost+found 这个目录平时是空的,系统非正常关机而留下“无家可归”的文件(windows下叫什么.chk)就在这里/proc 虚拟的目录,是系统内存的映射。可直接访问这个目录来获取系统信息。

  31. 文件和目录-文件属性 • 文件类型 • 文件长度 • 文件所有者 • 文件的许可权-读,写,执行 • 文件最后修改时间

  32. Linux编程 -文件类型 • 普通文件 这是种最常见的文件,这种文件包含了某种形式的数据,对普通文件的解释由处理该文件的应用程序进行:如 xxx.c lilo.conf • 目录文件 保护了其它文件的名字以及指向与这些文件有关信息的指针。对一个目录文件具有读许可权的任一进程都可以读该目录的内容,但只有内核可以写目录文件 • 字符特殊文件 用于系统中某些类型的设备 • 块特殊文件 典型用于磁盘管理,系统中的所有设备或者是字符特殊文件,或者是块文件 • FIFO(命名管道) 主要用于进程间通信 • 套接口(socket) 主要用于网络通信 • 符号连接 一个文件指向另一个文件

  33. linux编程-文件属性 位置1 2 3 4 5 6 7 文件属性 文件数 拥有者 所属的group文件大小 建档日期 文件名 drwx------ 2 Guest users 1024 Nov 21 21:05 Mail -rwx--x--x 1 root root 89080 Nov 7 22:41 tar* -rwxr-xr-x 1 root bin 5013 Aug 15 9:32 uname* lrwxrwxrwx 1 root root 4 Nov 24 19:30 zcat->gzip -rwxr-xr-x 1 root bin 308364 Nov 29 7:43 zsh* -rwsr-x--- 1 root bin 9853 Aug 15 5:46 su*

  34. 文件和目录-文件操作 • cd命令 • mkdir,rmdir命令 • cp命令 • 具体用法是: • cp –r 源文件(source)目的文件(target).参数r是指连同元文件中的子目录一同拷贝 • rm命令 • rm –r 目录名 • 这个操作可以连同这个目录下面的子目录都删除,功能上和rmdir相似。 • rm –f 文件名(目录名) • 这个操作可以进行强制删除。

  35. Linux编程-标准IO库 • 标准IO库和DOS/windows基本相同,这里就不在赘述了

  36. Linux编程-进程和线程 • 进程:普通的解释是,进程是程序的一次执行 • 线程:线程可理解为进程中执行的一段程序片断。 • 区别 • 进程间是独立的,这表现在内存空间,上下文环境,而线程运行在进程空间内。一般来讲(不使用特殊技术)进程是无法突破进程边界存取其他进程内的存储空间,而线程由于处于进程空间内,所以同一进程所产生的线程共享同一内存空间。 • 同一进程中的两段代码不能够同时执行,除非引入线程。线程是属于进程的,当进程退出时,该进程所产生的线程都会被强制退出并清除。线程占用的资源要少于进程所占用的资源。 • 进程和线程都可以有优先级。

  37. Linux编程-进程 • 多进程编程的优点 • Linux下进程的结构 • Linux下进程的控制 • Linux下进程间通信

  38. Linux编程-进程 • Linux多进程编程的优点 • 并行化 • 简单有序 • 互补干扰 • 事务化

  39. 堆栈 数据段 代码段 Linux编程-进程的结构 • Linux下一个进程在内存里有三部分的数据:代码段,堆栈段,数据段 • 代码段:存放程序代码的数据,假如机器中有数个进程运行相同的一个程序,那么它们就可以使用相同的代码段 • 堆栈段:存放子程序的返回地址,子程序参数以及程序的局部变量 • 数据段:存放程序的全局变量,常数以及动态数据分配的数据空间

  40. Linux编程-进程控制 • 进程标示 ID-每个进程都有一个非负整型的唯一进程ID。因为进程ID表示符是唯一的,常将其用做其它标识符的一部分,以保证唯一性。 • #include <sys/types.h> • #include<unistd.h> • pid_t getpid(void); //返回:调用进程的进程ID • pid_t getppid(void); //返回:调用进程的父进程ID

  41. Linux编程-进程控制 • fork()函数和vfork()函数 • fork() vfork:创建一个新的进程 • 语法:pid_t fork(); pid_t vfork(); • 说明:本系统调用产生一个新的进程, 叫子进程, 是调用进程的一个复制品. 调用进程叫父进程, 子进程继承了父进程的几乎所有的属性 。但实际上数据却已经分开,相互之间不再有影响了,也就是说,它们之间不再共享任何数据了。它们再要交互信息时,只有通过进程间通信来实现 • void main(){ int i; if ( fork() == 0 ) { /* 子进程程序 */ for ( i = 1; i <1000; i ++ ) printf("This is child process\n"); } else { /* 父进程程序*/ for ( i = 1; i <1000; i ++ ) printf("This is process process\n"); } • }

  42. Linux编程-进程控制 • exec函数族 • 当进程调用一种exec函数时,该进程完全由新程序代换, • 而新程序则从其main()函数开始执行。 • 进程终止 • 正常终止:从main返回,调用exit, _exit • 异常终止:调用abort,由一个信号终止

  43. Linux编程-进程间通信 • 管道和FIFO • 信号量 • 消息队列 • 共享内存

  44. 进程间通信-管道 • 管道是进程之间单向的数据流:一个进程写入管道的所有数据都有内核定向到另一个进程,另一个进程由此可以从管道中读取数据 进程 内核

  45. 进程间通信-管道 • 管道被看作是打开的文件,但是在已经装载的文件系统中没有映象 • 管道是单向的,只提供一个方向的数据流,如果需要双向数据流,必须创建两个管道,每个方向一个 • 一个管道可以被多个进程使用,如果一个管道被多个进程使用,必须使用文件加锁机制

  46. Linux通信-管道的创建和撤销 • 创建管道 • int pipe(int fd[2]); • 该函数返回两个文件描述字:fd[0],fd[1]。前者打开文件读,后者打开文件写。 • 由一个进程创建一个管道后,调用fork派生一个自身的拷贝。 • 从管道中读数据 • read(int fd, void *buff, unsigned nbytes) • 管道描述符fd, 传送数据地址buf,传送字节数nbytes • 向管道中写数据 • write(int fd, void *buff, unsigned nbytes) • popen 建立一个管道 • pclose 删除一个管道

  47. 进程间通信-管道 • int main (void) { • int n, fd [2]; • pid_t pid; • char line [MAXLINE]; • if (pipe (fd) < 0) • err_sys ("pipe error"); • if ( (pid = fork ()) < 0) • err_sys ("fork error"); • else if (pid > 0) { // parent • close (fd [0]); • write (fd [1], "hello world\n", 12); • } else { // child • close (fd [1]); • n = read (fd[0], line, MAXLINE); • write (STDOUT_FILENO, line, n); • } • exit (0); • }

  48. 进程间通信-管道 管道固有的缺陷 • 因为读数据的同时也将数据从管道移去,因此不能用来对多个接受者广播数据 • 管道中的数据被当作字节流,因此无法识别信息的边界。如果写进程发送不同长度的数据对象通过管道,那么读进程不能确定发送了多少个对象,或是它不能确定对象的边界 • 如果一个管道有多个读进程,那么写进程不能发送数据到指定的读进程。同样,如果有多个写进程,那么没有办法来判别是它们中的哪一个发送数据。

  49. 进程间通信-FIFO • 管道的一个主要缺点是:用户无法打开一个现有的管道,除非管道是由一个公共的祖先进程创建的,否则两个任意进程就不能共享同一个管道 • FIFO命名管道,指代先进先出。每个FIFO有一个路径名与之关联,从而允许无亲缘关系的进程访问同一个FIFO • FIFO是半双工的

  50. 进程间通信-FIFO • 创建FIFO • mknod():创建一个命名管道 • 打开FIFO • open():打开命名管道 • 读FIFO • read():从FIFO中读数据 • 写FIFO • write():向FIFO中写数据 • 关闭FIFO • Close():关闭FIFO • 删除FIFO • unlike()减少文件的一个连接数,如果连接数为0,则删除 • remove()删除文件

More Related