Top Banner
© 2005 博博博博 BEIJNG UNIVERSAL PIONEERING TECHNOLOGY Co . , LTD 博博博博 博博博博 Linux 博博博博 博博博
69

Linux 开发基础

Jan 24, 2016

Download

Documents

aminia

Linux 开发基础. 乾正光. Linux 程序设计基础 —C 环境. Linux 编程概述 文本编辑器 vi Linux 下函数库 GCC 及其使用 调试工具 gdb GNU make 和 makefile. Linux 编程概述. Linux 软件开发一直在 Internet 环境下讲行。这个环境是全球性的,编程人员来自世界各地。只要能够访问 Web 站点,就可以启动一个以 Linux 为基础的软件项目。 - PowerPoint PPT Presentation
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Linux 开发基础

© 2005 博创科技 北 京 博 创 兴 业 科 技 有 限 公 司

BEIJNG UNIVERSAL PIONEERING TECHNOLOGY Co . , LTD

博创科技 嵌入互动

Linux 开发基础

乾正光

Page 2: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

Linux 程序设计基础— C 环境

Linux 编程概述 文本编辑器 vi Linux 下函数库 GCC 及其使用 调试工具 gdb GNU make 和 makefile

Page 3: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

Linux 编程概述 Linux 软件开发一直在 Internet 环境下讲行。这个环境是全球

性的,编程人员来自世界各地。只要能够访问 Web 站点,就可以启动一个以 Linux 为基础的软件项目。

Linux 开发工作经常是在 Linux 用户决定共同完成一个项目时开始的。当开发工作完成后,该软件就被放到 Internet 站点上,任何用户都可以访问和下载它。由于这个活跃的开发环境,新的以 Linux 为基础的软件功能日益强大,而且呈现爆炸式的增长态势。

大多数 Linux 软件是经过自由软件基金会( Free Software Foundation )提供的 GNU ( GNU 即 GNU’s not UNIX )公开认证授权的,因而通常被称作 GNU 软件。 GNU 软件免费提供给用户使用,并被证明是非常可靠和高效的。许多流行的 Linux 实用程序如 C 编译器、 shell 和编辑器都是 GNU 软件应用程序。

Page 4: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

Linux 程序需要首先转化为低级机器语言即所谓的二进制代码以后,才能被操作系统执行。 例如编程时,先用普通的编程语言生成一系列指令,这些

指令可被翻译为适当的可执行应用程序的二进制代码。这个翻译过程可由解释器一步步来完成,或者也可以立即由编译器明确地完成。

shell 编程语言如 BASH 、 TCSH 、 GAWK 、 Perl 、 Tcl 和Tk 都利用自己的解释器。用这些语言编制的程序尽管是应用程序文件,但可以直接运行。编译器则不同,它将生成一个独立的二进制代码文件然后才可以运行。

Page 5: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

Linux 编程风格

GNU 风格 Linux 内核编程风格

Page 6: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

GNU 风格 (1/2)

函数返回类型说明和函数名分两行放置,函数起始字符和函数开头左花括号放到最左边。

尽量不要让两个不同优先级的操作符出现在相同的对齐方式中,应该附加额外的括号使得代码缩进可以表示出嵌套。

按照如下方式排版 do-while 语句:do

{

}while() 每个程序都应该以一段简短的说明其功能的注释开头。 请为每个函数书写注释,说明函数是做什么的,需要哪些入口参数,参数

可能值的含义和用途。如果用了非常见的、非标准的东西,或者可能导致函数不能工作的任何可能的值,应该进行特殊说明。如果存在重要的返回值,也需要说明。

不要声明多个变量时跨行,每一行都以一个新的声明开头。

Page 7: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

GNU 风格 (2/2)

当一个 if 中嵌套了另一个 if-else 时,应用花括号把 if-else 括起来。 要在同一个声明中同时说明结构标识和变量或者结构标识和类型定义 (typ

edef) 。先定义变量,再使用。 尽量避免在 if 的条件中进行赋值。 请在名字中使用下划线以分割单词,尽量使用小写;把大写字母留给宏和枚举常量,以及根据统一惯例使用的前缀。例如,应该使用类似 ignore_space_change_flag 的名字;不要使用类似 iCantReadThis 的名字。

用于表明一个命令行选项是否给出的变量应该在选项含义的说明之后,而不是选项字符之后被命名。

Page 8: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

Linux 内核编程风格 Linux 内核缩进风格是 8 个字符。 Linux 内核风格采用 K&R标准,将开始的大括号放在一行的最后,而将结束的大括号放在一行的第一位。

命名尽量简洁。 不应该使用诸如 ThisVariableIsATemporaryCounter之类的名字。应

该命名为 tmp ,这样容易书写,也不难理解。 命名全局变量,应该用描述性命名方式,例如应该命名“ count_acti

ve_users()” ,而不是“ cntusr()” 。 本地变量应该避免过长。

函数最好短小精悍,一般来说不要让函数的参数多于 10 个,否则应该尝试分解这个过于复杂的函数。

通常情况,注释说明代码的功能,而不是其实现原理。避免把注释插到函数体内,而写到函数前面,说明其功能,如果这个函数的确很复杂,其中需要有部分注释,可以写些简短的注释来说明那些重要的部分,但是不能过多。

Page 9: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

文本编辑器 vi

vi 的模式 vi 的进入 命令模式 插入模式 末行模式

Page 10: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

vi 的模式 Command Mode ( 命令模式 )

这是执行 vi 后的缺省模式 此时键盘输入当作命令 命令有大小写之区分

Input Mode ( 插入模式 )

使用 a 、 i 、 o 、 c 、 r 、 s 进入插入模式 用户输入的任何字符都被 vi 当做文件内容保存起来,并将其显示在屏幕上

按下 ESC 键即可回到 Command Mode

Page 11: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

vi 的模式 Last Mode (末行模式 )

在 Command Line 按下 : 即可进入该模式 用来进行保存文件、打开文档或环境的设定 命令有大小写之分

Page 12: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

Page 13: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

vi 的进入和内容输入 进入: vi 文件名 输入文件内容 (进入插入模式)

新增 (append) a 从光标所在位置后面开始新增内容

A 从光标所在行最后面的地方开始新增内容。 插入 (insert)

i 从光标所在位置前面开始插入内容 I 从光标所在行的第一个非空白字符前面开始插入资料。

开始 (open) o 在光标所在行下新增一行并进入输入模式。 O 在光标所在行上新增一行并进入输入模式。

(命令模式)

Page 14: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

命令模式 1 、光标的移动  h 左移一个字符 l   右移一个字符

j  下移一行 k   上移一行w,W  跳至后一个字的开头 (W忽略标点 )b,B 跳至前一个字的开头( B忽略标点)e   移动到后一个字的末尾

^   至本行第一个非空字符 $   至行尾 0   至行首

H   移动到当前窗口的第一列 M   移动到当前窗口的中间列 L   移动到视窗的最后一列) 光标所在位置到下个句子的第一个字母

( 光标所在位置到该句子的第一个字母  } 光标所在位置到该段落的最后一个字母

{  光标所在位置到该段落的第一个字母

Page 15: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

命令模式 1 、光标的移动 (续)

nH 将光标移到屏幕的第 n 行nL 将光标移到屏幕的倒数第 n 行CTRL-d 向下半页CTRL-f 向下一页CTRL-u 向上半页 CTRL-b 向上一页 n-  减号移动到上一行的第一个非空白字符,前面加上数字可以指定移动到以 上 n 行

n+   加号移动到下一行的第一个非空白字符,前面加上数字可以指定移动到以下 n 行

Page 16: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

命令模式 2 、删除  x  删除光标所在字符 X 删除光标前面的字符 s 删除光标所在字符,并进入输入模式 S  删除光标所在的行,并进入输入模式 dd 删除光标所在的行 D 从光标位置开始删除到行尾 d与光标移动命令的组合

Page 17: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

命令模式 3 、修改

r  修改光标所在字符, r 后接着要修改的字符。如, rc 可以用字符“ c ”替换光标所指向的当前字符

R 进入替换状态,新增内容会覆盖原先内容,直到按 [ESC] 回到命令模式下为止

cc 修改光标所在行 C 修改从光标位置到该行末尾的内容 c 与光标移动命令的组合

Page 18: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

命令模式 4 、复制和移动

yy 复制当前行到内存缓冲区nyy 复制 n 行内容到内存缓冲区

y与光标移动的组合p 将缓冲区的内容粘贴到光标的后面P 将缓冲区的内容粘贴到光标的前面

另:在末行模式下实现移动:n1,n2 m n3 : 把 n1 到 n2 行内容搬到第 n3 行后

Page 19: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

5 、搜索字符串/pattern  移至下一个包含pattern 的行?pattern 移至上一个包含pattern 的行/      往下重复查找?      往上重复查找n      在同一方向重复查找N     在相反方向重复查找/pattern/+n 移至下一个 pattern 所在行后的第 n 行?pattern?-n 移至上一个 Pattern 所在行前的第 n 行

6 、其他 u 撤销前一条命令的结果

*. $ ^ [ ] { } \ /包含在查找字符串中,

要用转义字符 (\ )

命令模式

Page 20: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

末行模式 1 、文件的保存和退出

:w 保存:q 退出:w! 强制保存:q! 强制退出:wq 保存退出:wq! 强制保存退出

Page 21: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

末行模式 2 、字符串的替换

:s/str1/str2/ 用字符串 str2 替换行中首次出现的字符串 str1

:s/str1/str2/g 用字符串 str2 替换行中所有出现的字符串 str1

:.,$ s/str1/str2/g 用字符串 str2 替换正文当前行到末尾所有出现的字符串 str1

:1,$ s/str1/str2/g 用字符串 str2 替换正文中所有出现的字符串 str1

:g/str1/s//str2/g 功能同上

Page 22: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

末行模式 其他:

: n 将光标移到第 n 行 编辑多个文件vi file1 file2 …

:n 编辑下一个文件:e filename 编辑指定文件

Page 23: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

Linux 下函数库( 1/3 ) 一个“程序函数库”就是一个文件包含了一些编译好的代码和数据,这些

编译好的代码和数据可以在事后供其他的程序使用。程序函数库可以使整个程序更加模块化,更容易重新编译,而且更方便升级。可分为两种类型: 静态函数库 (static libraries):是一个普通的目标文件的集合,一般

用“ .a” 作为文件的后缀。静态函数库和共享函数库相比有很多的缺点,占用内存空间多。但使用 ELF 格式的静态库函数生成的代码可以比使用共享函数库的程序运行速度上快一些。

可以用 ar 这个程序来创建一个静态函数库文件,或者往一个已经存在地静态函数库文件添加新的目标代码。

例如 , 把 file1.o 和 file2.o 加入到 my_library.a 这个函数库文件: ar rcs my_library.a file1.o file2.o

然后运行 ranlib ,以给库加入一些索引信息

Page 24: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

Linux 下函数库( 2/3 ) 共享函数库 (shared libraries):当一个可执行程序在启动的时候被加载的

函数。每个共享函数库都有个特殊的名字,称作“ soname” 。 soname名字命名必须以“ lib” 作为前缀,然后是函数库的名字,然后是“ .so” ,最后是版本号信息。 优点:多进程使用同一函数库;修改函数库不需重新连编。 安装一个新版本的函数库的时候,要先将这些函数库文件拷贝到一些特定的目录中,运行 ldconfig 就可以。 ldconfig检查已经存在的库文件,然后创建 soname 的符号链接到真正的函数库,同时设置 /etc/ld.so.cache 这个缓冲文件。 例如,创建两个目标文件 (a.o 和 b.o) ,然后创建一个包含 a.o 和b.o 的共享函数库。

gcc -fPIC -g -c -Wall a.cgcc -fPIC -g -c -Wall b.cgcc -shared -Wl,-soname,liblusterstuff.so.1 -o liblusterstuff.so.1.0.1 a.o b.o –lc

注:” -fPIC ” 是位置无关参数, ” -g” 和“-Wall”参数不是必须的。

Page 25: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

Linux 下函数库( 3/3 ) 函数库和头文件的保存位置

a. 函数库 /lib:系统必备共享函数库 /usr/lib:标准共享函数库和静态函数库 /usr/i486-linux-libc5/lib: libc5 兼容性函数库 /usr/X11R6/lib: X11R6 的函数库 /usr/local/lib:本地函数库

b. 头文件 /usr/include:系统头文件 /usr/local/include:本地头文件

c.  共享函数库的相关配置和命令 /etc/ld.so.conf:包含共享库的搜索位置 ldconfig:共享库管理工具,一般在更新了共享库之后要运行该命令 ldd:可查看可执行文件所使用的共享函数库

Page 26: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

使用 GNU cc 开发应用程序 gcc 的简介 可执行文件的格式 gcc 的使用

Page 27: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

gcc 的简介 gcc 是 GNU 的 C 和 C++ 编译器。实际上, gcc 能够编译多种语言:

C 、 C++ 和 Object C等。利用 gcc 命令可同时编译并连接 C 和 C++ 源程序。也可以对几个 C 源文件利用 gcc 编译、连接并生成可执行文件。

gcc 可以使程序员灵活地控制编译过程。编译过程一般可以分为下面四个阶段,每个阶段分别调用不同的工具进行处理

预处理 链接编译 组译源程序 (*.c)

可执行文件

预处理器 编译器 组译器 连接器

Page 28: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

gcc 的四个阶段 命令 gcc 首先调用 cpp 进行预处理,在预处理过程中,对源代码文件中

的文件包含 (include) 、预编译语句 ( 如宏定义 define等 ) 进行分析。 接着调用 cc1 进行编译,这个阶段根据输入文件生成以 .o 为后缀的目标

文件。 汇编过程是针对汇编语言的步骤,调用 as 进行工作,一般来讲, .S 或 .s

为后缀的汇编语言源代码文件汇编之后都生成以 .o 为后缀的目标文件。 当所有的目标文件都生成之后, gcc 就调用 ld 来完成最后的关键性工作,

这个阶段就是连接。在连接阶段,所有的目标文件被安排在可执行程序中的恰当的位置,同时,该程序所调用到的库函数也从各自所在的函数库中连到合适的地方。

Page 29: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

可执行文件格式 Linux 系统中可执行文件有两种格式。

第一种格式是 a.out 格式,这种格式用于早期的 Linux 系统以及 Unix系统的原始格式。 a.out 来自于 Unix C 编译程序默认的可执行文件名。当使用共享库时, a.out 格式就会发生问题。把 a.out 格式调整为共享库是一种非常复杂的操作。

因此,一种新的文件格式被引入 Unix 系统 5 的第四版本和 Solaris 系统中。它被称为可执行和连接的格式( ELF )。这种格式很容易实现共享库。

ELF 格式已经被 Linux 系统作为标准的格式采用。 gcc 编译程序产生的所有的二进制文件都是 ELF 格式的文件(即使可执

行文件的默认名仍然是 a.out )。较旧的 a.out 格式的程序仍然可以运行在支持 ELF 格式的系统上。

Page 30: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

GNU C 的使用 基本语法 gcc [options] [filenames] 说明:

在 gcc 后面可以有多个编译选项,同时进行多个编译操作。很多的 gcc选项包括一个以上的字符。因此你必须为每个选项指定各自的连字符。例如,下面的两个命令是不同的: gcc -p -g test1.c

gcc -pg test1.c 当你不用任何选项编译一个程序时, GCC 将会建立 (假定编译成功 ) 一

个名为 a.out 的可执行文件。

Page 31: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

gcc选项 -o选项 你能用 -o 编译选项来为将产生的可执行文件指定一个文件名来代替 a.out 。 例: gcc –o count count.c -c选项:告诉 GCC仅把源代码编译为目标代码而跳过汇编和连接的步骤。

这个选项使用的非常频繁,因为它使得编译多个 C 程序时速度更快并且更易于管理。缺省时 GCC建立的目标代码文件有一个 .o 的扩展名。

例: gcc –c test2.c -E 只运行 C 预编译器。 -S 编译选项告诉 gcc 在为 C 代码产生了汇编语言文件后停止编译。 -shared 生成共享目标文件。通常用在建立共享库时。 -static 禁止使用共享连接。

Page 32: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

警告选项 在 gcc 中用开关 -Wall 控制警告信息,使用示例命令如下:

gcc –Wall -o test3_1 test3_1.c -w 不生成任何警告信息。

Page 33: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

查找选项

gcc一般使用默认路径查找头文件和库文件。如果文件所用的头文件或库文件不在缺省目录下,则编译时要指定它们的查找路径。 -I选项:指定头文件的搜索目录

例:gcc –I/export/home/st –o test1 test1.c

-L选项:指定库文件的搜索目录例:

gcc –L/usr/X11/R6/lib –o test1 test1.c

Page 34: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

多个源文件生成一个可执行文件

问题:有多个源文件时,如何生成一个可执行文件? 方法 1: gcc –Wall –o mytest test1.c test2.c test3.c 方法 2:

gcc-Wall -c test1.c

gcc-Wall –c test2.c

gcc-Wall –c test3.c

gcc –o mytest test1.o test2.o test3.o

Page 35: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

优化选项 优化选项可以使 GCC 在耗费更多编译时间和牺牲易调试性的基础上产生更小更快的可执行文件。这些选项中最典型的是 -O 和 -O2选项。 -O0 不进行优化处理。 -O选项:告诉 GCC 对源代码进行基本优化。这些优化在大多数情况

下都会使程序执行的更快。 -O2选项:告诉 GCC 产生尽可能小和尽可能快的代码。 -O2选项将

使编译的速度比使用 -O 时慢。但通常产生的代码执行速度会更快。 -O3选项:比 -O2 更进一步优化,包括 inline 函数。

Page 36: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

版本选项 -v选项

用户将会得到自己目前正在使用的 gcc 的版本及与版本相关的一些信息。

gcc -v 将得到如下结果: Reading specs from /usr/lib/gcc-lib/i486-box-linux/2.7.2/specs

gcc version 2.7.2 -V 选项

如果安装了多个版本的 gcc ,并且想强制执行其中的某个版本,可以用命令通知系统用户要使用的版本。

gcc -V2.6.3 -v

Page 37: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

宏定义选项 -D MACRO 以字符串“ 1” 定义 MACRO 宏。 -D MACRO=DEFN 以字符串“ DEFN” 定义 MACRO 宏。 -U MACRO 取消对 MACRO 宏的定义。

Page 38: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

调试和剖析选项 使用调试选项后, gcc 在进行编译的时候,在目标文件( .o )和创建的

可执行文件中插入额外信息,这些额外信息使 gdb 能够判断编译过的代码和源代码之间的关系。

-g选项:告诉 GCC产生能被 GNU 调试器使用的调试信息以便调试你的程序。例: gcc –g –o test3 test3.c

-pg选项:告诉 GCC 在你的程序里加入额外的代码,执行时,产生 gprof用的剖析信息以显示你的程序的耗时情况。

使用 gdb 调试工具,命令行如下: 例: gcc –ggdb3 –o test3 test3.c

Page 39: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

调试工具 gdb

GDB 调试器简介 gdb 的常用命令 gdb 应用实例

Page 40: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

gdb 简介 Linux 系统中包含了 GNU 调试程序 gdb ,它是一个用来调试 C 和 C++

程序的调试器。可以使程序开发者在程序运行时观察程序的内部结构和内存的使用情况。

gdb 所提供的一些功能如下所示: 运行程序,设置所有的能影响程序运行的参数和环境; 控制程序在指定的条件下停止运行; 当程序停止时,可以检查程序的状态; 修改程序的错误,并重新运行程序; 动态监视程序中变量的值; 可以单步逐行执行代码,观察程序的运行状态。 分析崩溃程序的产生的 core 文件

Page 41: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

gdb 的特点 gdb 的功能非常强大

到目前为止, gdb已能够支持Moduls-2 、 Chill 、 Pascal 和 FORTRAN 程序的调试,但是调试这些语言的源程序时有一些功能还不能使用。

例如调试 FORTRAN 程序时还不支持表达式的输入、输出变量或类FORTRAN 的词法。

gdb 程序调试的对象是可执行文件,而不是程序的源代码文件。 然而,并不是所有的可执行文件都可以用 gdb 调试。如果要让产生的可

执行文件可以用来调试,需在执行 gcc 指令编译程序时,加上 -g参数,指定程序在编译时包含调试信息。

调试信息包含程序里的每个变量的类型和在可执行文件里的地址映射以及源代码的行号。

gdb 利用这些信息使源代码和机器码相关联。 gdb 是一个用来调试 C 和C++ 程序的常用调试工具之一。

Page 42: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

gdb 的启动 在命令行上输入 gdb 并按回车键就可以运行 gdb了,如果一切正常的话,

将启动 gdb

gdb [filename]

出现(gdb)

在这里,可以输入调试命令 在可以使用 gdb 调试程序之前,必须使用 -g 选项编译源文件。可在 m

akefile 中如下定义 CFLAGS 变量: CFLAGS = -g 运行

Page 43: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

获取帮助信息 启动 gdb 后,可以在命令行上指定很多的选项。输入:

help

可以获得 gdb 的帮助信息。 如果想要了解某个具体命令(比如 break )的帮助信息,在 gdb 提示符

下输入下面的命令:break

屏幕上会显示关于 break 的帮助信息。从返回的信息可知, break 是用于设置断点的命令。

另一个获得 gdb帮助的方法是浏览 gdb 的手册页。在 Linux Shell 提示符输入:man gdb

可以看到 man 的手册页

Page 44: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

gdb命令的分类 在 gdb 提示符处键入 help ,将列出命令的分类,主要的分类有:

aliases:命令别名 breakpoints:断点定义; data:数据查看; files:指定并查看文件; internals:维护命令; running:程序执行; stack:调用栈查看; statu:状态查看; tracepoints:跟踪程序执行。

后跟命令的分类名,可获得该类命令的详细清单

Page 45: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

基本 gdb命令( 1/2 ) file命令:装入想要调试的可执行文件。 cd命令:改变工作目录。 pwd命令:返回当前工作目录。 run命令:执行当前被调试的程序。 kill命令:停止正在调试的应用程序。 list命令:列出正在调试的应用程序的源代码。 break命令:设置断点。 watch命令:设置监视点,监视表达式的变化。 awatch命令:设置读写监视点。当要监视的表达式被读或写时将应用程

序挂起。它的语法与 watch命令相同。 rwatch命令:设置读监视点,当监视表达式被读时将程序挂起,等侍调

试。此命令的语法与 watch 相同。 next命令:执行下一条源代码,但是不进入函数内部。也就是说,将一条函数调用作为一条语句执行。执行这个命令的前提是已经 run ,开始了代码的执行。

Page 46: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

基本 gdb命令( 2/2 ) step命令:执行下一条源代码,进入函数内部。如果调用了某个函数,

会跳到函数所在的代码中等候一步步执行。执行这个命令的前提是已经用run 开始执行代码。

display命令:在应用程序每次停止运行时显示表达式的值。 info break命令:显示当前断点列表,包括每个断点到达的次数 16 ) info files命令:显示调试文件的信息。 17 ) info func命令:显示所有的函数名。 18 ) info local命令:显示当前函数的所有局部变量的信息。 19 ) info prog命令:显示调试程序的执行状态。 20 ) print命令;显示表达式的值。 21 ) delete命令:删除断点。指定一个断点号码,则删除指定断点。不

指定参数则删除所有的断点。 22 ) Shell命令:执行 Linux Shell命令。 23 ) make命令:不退出 gdb 而重新编译生成可执行文件。 24 ) Quit命令:退出 gdb 。

Page 47: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

gdb 使用实例( 1/2 ) /* 一个有错误的 C 源程序 */

#include <stdio.h>

#include <stdlib.h>

static char buff [256];

static char* string;

int main ()

{ printf ("Please input a string: ");

gets (string);

printf ("\nYour string is: %s\n", string); } 上面这个程序非常简单,其目的是接受用户的输入,然后将用户的输入打印出来。该程序使用了 一个未经过初始化的字符串地址 string ,因此,编译并运行之后,将出现 Segment Fault 错误:

$ gcc -o test -g test.c

$ ./test Please input a string: asfd Segmentation fault (core dumped)

Page 48: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

gdb 使用实例( 2/2 ) 为了查找该程序中出现的问题,我们利用 gdb ,并按如下的步骤进行:

1.运行 gdb bugging 命令,装入 bugging 可执行文件; 2.执行装入的 bugging 命令; 3.使用 where 命令查看程序出错的地方; 4.利用 list 命令查看调用 gets 函数附近的代码; 5.唯一能够导致 gets 函数出错的因素就是变量 string 。用 print 命令查看 string 的值;

6.在 gdb 中,我们可以直接修改变量的值,只要将 string 取一个合法的指针值就可以了,为 此,我们在第 11 行处设置断点;

7.程序重新运行到第 11 行处停止,这时,我们可以用 set variable 命令修改 string 的取值;

8.然后继续运行,将看到正确的程序运行结果。

Page 49: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

GNU make 和 makefile

GNU make 概述 Makefile 的基本结构 Makefile 中的变量 GNU make 的主要预定义变量 Makefile 的隐含规则 make命令行选项 使用 automake 和 autoconf产生 Makefile

Page 50: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

GNU make 概述 在大型的开发项目中,人们通常利用 make 工具来自动完成编译工作。

这些工作包括: 如果仅修改了某几个源文件,则只重新编译这几个源文件; 如果某个头文件被修改了,则重新编译所有包含该头文件的源文件。 利用这种自动编译可大大简化开发工作,避免不必要的重新编译。

实际上, make 工具通过一个称为 makefile 的文件来完成并自动维护编译工作。 makefile 需要按照某种语法进行编写,其中说明了如何编译各个源文件并连接生成可执行文件,并定义了源文件之间的依赖关系。 当修改了其中某个源文件时,如果其他源文件依赖于该文件,则也要重新编译所有依赖该文件的源文件。

默认情况下, GNU make 工具在当前工作目录按如下顺序搜索 makefile: GNUmakefile makefile Makefile

Page 51: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

makefile举例 在 UNIX 中,习惯使用 makefile 作为 makfile 文件。 Linux 程序员使用第三种文件名 Makefile 。因为第一个字母是大写,通常

被列在一个目录的文件列表的最前面。 如果要使用其他文件作为 makefile ,则可利用类 似下面的 make 命令选

项指定 makefile 文件: $ make -f Makefile.debug

例 1:一个简单的 makefile

prog:prog1.o prog2.o gcc prog1.o prog2.o -o prog prog1.o:prog1.c lib.h gcc -c -I. -o prog1.o prog1.c prog2.o:prog2.c gcc -c prog2.c

Page 52: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

Makefile 的基本结构( 1/2 ) Makefile 是一个文本形式的数据库文件,其中包含一些规则来告诉make处理哪些文件以及如何处理这些文件。

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

依靠这些信息, make 会对磁盘上的文件进行检查,如果目标文件的生成或被改动时的时间(称为该文件时间戳)至少比它的一个依赖文件还旧的话, make 就执行相应的命令,以更新目标文件。

目标文件不一定是最后的可执行文件,可以是任何一个中间文件并可以作为其他目标文件的依赖文件。

Page 53: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

Makefile 的基本结构( 2/2 ) Makefile规则的一般形式如下:

target: dependency dependency

(tab)<command> 一个 Makefile 文件主要含有一系列的规则,每条规则包含以下内容。

一个目标( target ),即 make 最终需要创建的文件,如可执行文件和目标文件;目标也可以是要执行的动作,如“ clean” 。

一个或多个依赖文件( dependency )列表,通常是编译目标文件所需要的其他文件。

一系列命今 (command) ,是 make 执行的动作,通常是把指定的相关文件编译成目标文件的编译命令,每个命令占一行,且每个命令行的起始字符必须为 TAB 字符。

除非特别指定,否则 make 的工作目录就是当前目录。 target 是需要创建的二进制文件或目标文件, dependency 是在创建 target 时需要用到的一个或多个文件的列表,命令序列是创建 target 文件所需要执行的步骤,比如编译命令。

Page 54: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

Makefile 实例( 1/3 )

# 以 # 开头的为注释行test: prog.o code.o

gcc –o test prog.o code.o

 prog.o: prog.c prog.h code.h

gcc –c prog.c –o prog.o

 code.o: code.c code.h

gcc –c code.c –o code.o

 clean:rm –f *.o

上面的 Makefile 文件中共定义了四个目标: test 、 prog.o 、 code.o 和 clean 。 目标从每行的最左边开始写,后面跟一个冒号(:),如果有与这个目标有依赖性的其他目标或文件,把它们列在冒号后面,并以空格隔开。然后另起一行开始写实现这个目标的一组命令。

在 Makefile 中,可使用续行号( \ )将一个单独的命令行延续成几行。但要注意在续行号( \ )后面不能跟任何字符(包括空格和键)

Page 55: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

Makefile 实例( 2/3 ) 一般情况下,调用 make命令可输入:

# make target target 是 Makefile 文件中定义的目标之一,如果省略 target , make

就将生成 Makefile 文件中定义的第一个目标。 对于上面Makefile 的例子,单独的一个“make”命令等价于:

# make test 因为 test 是 Makefile 文件中定义的第一个目标, make 首先将其读

入,然后从第一行开始执行,把第一个目标 test 作为它的最终目标,所有后面的目标的更新都会影响到 test 的更新。

第一条规则说明只要文件 test 的时间戳比文件 prog.o 或 code.o 中的任何一个旧,下一行的编译命令将会被执行。

Page 56: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

Makefile 实例( 3/3 ) 但是,在检查文件 prog.o 和 code.o 的时间戳之前, make 会在下面的行

中寻找以 prog.o 和 code.o 为目标的规则,在第三行中找到了关于 prog.o的规则,该文件的依赖文件是 prog.c 、 prog.h 和 code.h 。同样, make会在后面的规则行中继续查找这些依赖文件的规则,如果找不到,则开始检查这些依赖文件的时间戳,如果这些文件中任何一个的时间戳比 prog.o的新, make 将执行“ gcc –c prog.c –o prog.o”命令,更新 prog.o 文件。

以同样的方法,接下来对文件 code.o做类似的检查,依赖文件是 code.c和 code.h 。当 make 执行完所有这些套嵌的规则后, make 将处理最顶层的 test规则。如果关于 prog.o 和 code.o 的两个规则中的任何一个被执行,至少其中一个 .o 目标文件就会比 test 新,那么就要执行 test规则中的命令,因此make去执行 gcc命令将 prog.o 和 code.o连接成目标文件test 。

在上面Makefile 的例子中,还定义了一个目标 clean ,它是 Makefile 中常用的一种专用目标,即删除所有的目标模块

Page 57: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

make 的工作过程 现在来看一下 make做的工作:

首先 make按顺序读取makefile 中的规则, 然后检查该规则中的依赖文件与目标文件的时间戳哪个更新

如果目标文件的时问戳比依赖文件还早,就按规则中定义的命令更新目标文件。

如果该规则中的依赖文件又是其他规则中的目标文件,那么依照规则链不断执行这个过程,直到 Makefile 文件的结束,至少可以找到一个不是规则生成的最终依赖文件,获得此文件的时间戳

然后从下到上依照规则链执行目标文件的时间戳比此文件时间戳旧的规则,直到最顶层的规则

通过以上的分析过程,可以看到 make 的优点,因为 .o 目标文件依赖 .c源文件,源码文件里一个简单改变都会造成那个文件被重新编译,并根据规则链依次由下到上执行编译过程,直到最终的可执行文件被重新连接。 例如,当改变一个头文件的时候,由于所有的依赖关系都在 Makefile里,因此不再需要记住依赖此头文件的所有源码文件, make 可以自动的重新编译所有那些因依赖这个头文件而改变了的源码文件,如果需要,再进行重新连接

Page 58: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

Makefile 中的变量 Makefile里的变量就像一个环境变量。事实上,环境变量在 make 中也被

解释成 make 的变量。这些变量对大小写敏感,一般使用大写宇母。几乎可以从任何地方引用定义的变量,变量的主要作用如下: 保存文件名列表。在前面的例子里,作为依赖文件的一些目标文件名

出现在可执行文件的规则中,而在这个规则的命令行里同样包含这些文件并传递给 gcc做为命令参数。如果使用一个变量来保存所有的目标文件名,则可以方便地加入新的目标文件而且不易出错。

保存可执行命令名,如编译器。在不同的 Linux 系统中存在着很多相似的编译器系统,这些系统在某些地方会有细微的差别,如果项目被用在一个非 gcc 的系统里,则必须将所有出现编译器名的地方改成用新的编译器名。但是如果使用一个变量来代替编译器名,那么只需要改变该变量的值。其他所有地方的命令名就都改变了。

保存编译器的参数。在很多源代码编译时, gcc 需要很长的参数选项,在很多情况下,所有的编译命令使用一组相同的选项,如果把这组选项使用一个变量代表,那么可以把这个变量放在所有引用编译器的地方。当要改变选项的时候,只需改变一次这个变量的内容即可。

Page 59: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

变量的定义和使用 Makefile 中的变量是用一个文本串在 Makefile 中定义的,这个文本串就

是变量的值。只要在一行的开始写下这个变量的名字,后面跟一个“=”号,以及要设定这个变量的值即可定义变量,下面是定义变量的语法:

VARNAME=string 使用时,把变量用括号括起来,并在前面加上 $ 符号,就可以引用变量的值:

${VARNAME} make 解释规则时, VARNAME 在等式右端展开为定义它的字符串。 变量一般都在 Makefile 的头部定义。按照惯例,所有的 Makefile变量都

应该是大写。如果变量的值发生变化,就只需要在一个地方修改,从而简化了Makefile 的维护。

Page 60: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

Makefile变量举例 现在利用变量把前面的 Makefile重写一遍:

OBJS=prog.o code.o

CC=gcc

 test: ${ OBJS }

${ CC } –o test ${ OBJS }

 prog.o: prog.c prog.h code.h

${ CC } –c prog.c –o prog.o

 code.o: code.c code.h

${ CC } –c code.c –o code.o

 clean:rm –f *.o

Page 61: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

变量的类型 除用户自定义的变量外, make还允许使用

环境变量 使用环境变量的方法很简单,在 make 启动时, make读取系统当前已

定义的环境变量,并且创建与之同名同值的变量,因此用户可以像在 shell 中一样在 Makefile 中方便的引用环境变量。

需要注意的是,如果用户在 Makefile 中定义了同名的变量,用户自定义变量将覆盖同名的环境变量

自动变量 预定义变量

Page 62: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

GNU make 的主要预定义变量( 1/2 ) $* 不包含扩展名的目标文件名称。 $+ 所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件。

$< 第一个依赖文件的名称。 $? 所有的依赖文件,以空格分开,这些依赖文件的修改日期比目标

的创建日期晚。 $@ 目标的完整名称。 $^ 所有的依赖文件,以空格分开,不包含重复的依赖文件。 $% 如果目标是归档成员,则该变量表示目标的归档成员名称。例如,

如果目标名称 为 mytarget.so(image.o) ,则 $@ 为 mytarget.so ,而 $% 为 image.o 。

AR 归档维护程序的名称,默认值为 ar 。 ARFLAGS 归档维护程序的选项。 AS 汇编程序的名称,默认值为 as 。 ASFLAGS 汇编程序的选项。

Page 63: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

GNU make 的主要预定义变量( 2/2 ) CC C 编译器的名称,默认值为 cc 。 CFLAGS C 编译器的选项。 CPP C 预编译器的名称,默认值为 $(CC) -E 。 CPPFLAGS C 预编译的选项。 CXX C++ 编译器的名称,默认值为

g++ 。 CXXFLAGS C++ 编译器的选项。 FC FORTRAN 编译器的名称,默认值为 f77 。 FFLAGS FORTRAN 编译器的选项。

Page 64: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

Makefile 的隐含规则 在上面的例子中,几个产生目标文件的命令都是从“ .c” 的 C 语言源文件

和相关文件通过编译产生“ .o” 目标文件,这也是一般的步骤。实际上,make 可以使工作更加自动化,也就是说, make知道一些默认的动作,它有一些称作隐含规则的内置的规则,这些规则告诉make 当用户没有完整地给出某些命令的时候,应该怎样执行。

例如,把生成 prog.o 和 code.o 的命令从规则中删除, make 将会查找隐含规则,然后会找到并执行一个适当的命令。由于这些命令会使用一些变量,因此可以通过改变这些变量来定制 make 。象在前面的例子中所定义的那样, make 使用变量 CC 来定义编译器,并且传递变量 CFLAGS(编译器参数)、 CPPFLAGS ( C 语言预处理器参数)、 TARGET_ARCH (目标机器的结构定义)给编译器,然后加上参数 -c ,后面跟变量$< (第一个依赖文件名),然后是参数 -o 加变量 $@ (目标文件名)。

综上所述,一个 C 编译的具体命令将会是:$ {CC} $ {CFLAGS} $ {CPPFLAGS} $ {TARGET_ARCH} –c $< -o $@

Page 65: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

隐含规则举例 在上面的例子中,利用隐含规则,可以简化为:

OBJS=prog.o code.o CC=gcc test: ${ OBJS } ${ CC } –o $@ $^  prog.o: prog.c prog.h code.h code.o: code.c code.h  clean: rm –f *.o

Page 66: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

make命令行选项 直接在 make 命令的后面键入目标名可建立指定的目标,如果直接运行 m

ake ,则建立第一个目标。还可以用 make -f mymakefile 这样的命令指定 make 使用特定的 makefile ,而不是 默认的 GNUmakefile 、 makefile 或 Makefile 。

GNU make 命令还有一些其他选项,下面是 GNU make 命令的常用命令行选项命令行选项含义: -C DIR 在读取 makefile 之前改变到指定的目录 DIR 。 -f FILE 以指定的 FILE 文件作为 makefile 。 -h 显示所有的 make 选项。 -i 忽略所有的命令执行错误。 -I DIR 当包含其他 makefile 文件时,可利用该选项指定搜索目录。

-n 只打印要执行的命令,但不执行这些命令。 -p 显示 make 变量数据库和隐含规则。 -s 在执行命令时不显示命令。 -w 在处理 makefile 之前和之后,显示工作目录。 -W FILE 假定文件 FILE 已经被修改。

Page 67: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

使用 automake 和 autoconf产生 Makefile

在开始使用 Automake 和 autoconf之前,请先确认系统已经安装以下的软件: GNU Automake GNU Autoconf GNU m4 Perl GNU Libtool ( 如果你需要产生 shared library)

Automake 所产生的 Makefile 除了可以做到程序的编译和连接,也已经把如何产生程序文件的操作,以及把安装程序都考虑进去了,所以源程序所存放的目录架构最好符合 GNU 的标准惯例,下面用 hello.c 来作为例子进行说明。

Page 68: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

生成一个源程序 在工作目录下建立一个新的子目录 devel ,再在 devel 下建立一个 hello

的子目录,这个目录将作为存放 hello 这个程序及其相关文件的地方: 用编辑器写个 hello.c 文件:

#include <stdio.h> int main(int argc, char** argv) { printf("Hello, GNU!\n"); return 0; }

Page 69: Linux 开发基础

博创科技 嵌入互动

© 2006 博创科技

使用 Autoconf 及 Automake 来产生 Makefile 文件的步骤

autoscan 产生一个 configure.in 的模板,执行 autoscan 后会产生一个 configure.scan 的文件,可以用它做为 configure.in 文件的模板:

编辑 configure.scan 文件,如下所示,并且把文件名改成 configure.in 执行 aclocal 和 autoconf ,分别会产生 aclocal.m4 及 configure 两个文

件: 编辑 Makefile.am 文件,内容如下: 执行 automake --add-missing , Automake 会根据 Makefile.am产生一

些文件,包含最重要的 Makefile.in: 最后执行 ./configure