第五章:Linux程序开发简介
GNU Compiler Collection(GCC)
GCC是集合了多种编译器的编译程序。
编译过程如下:
- 预处理(CPP)根据源程序中以字符”#”开头的命令,修改源程序,得到另一个源程序,常以.i作为文件扩展名。修改主要包括#include、#define和条件编译三个方面。
gcc-o main.i -E main.c
gcc-o hello.i -E hello.c
- 编译器(CCL)将经过预处理器处理得到的文本文件hello.i和main.i翻译成hello.s与main.s,其中包含了汇编语言程序,汇编语言程序以一种标准的文本格式确切描述一条低级机器语言指令。运行以下命令进行编译:
gcc-S main.i hello.i
- 汇编器(AS)将hello.s和main.s翻译成机器语言指令,并打包成可重定位目标程序,一般以.o为文件扩展名。可重定位目标程序是二进制文件,它的字节编码是机器语言指令而不是字符。运行以下指令可得到重定位目标程序main.o和hello.o:
gcc-c main.s hello.s
用文本编辑器打开main.o和hello.o发现文件是乱码,因为此时已经是二进制文件。
- 链接程序(LD)将main.o和hello.o以及一些其他必要的目标文件组合起来,创建可执行目标文件。
gcc-o hello main.o hello.o
得到可执行程序hello.
GNU make 与 Makefile编写
GNU make是Linux专门为软件编译提供的一种自动化管理工具。允许将一个软件项目的代码分别放在多个源文件中,在改动其中一个文件时,可以只对该文件进行重新编译,然后重新连接所有的目标文件,这对于大型软件项目来说,重新进行编译要需要花费较长的时间,采用这种编译管理方式,能极大的提高工作效率。GNU make通过制定好的编译规则来控制代码的创建过程,这些规则通常定义在一个名为makefile的文件中;makefile告诉make编译哪些文件,怎么编译和何时编译。
makefile的基本规则和常见用法:
#Sample Makefile
myprog:main.o display.o input.o
gcc main.o display.o input,o -o myprog
main.o:main.c common.h
gcc -c main.c
display.o:display.c common.h
gcc -c display.c
input.o:input.c common.h
gcc -c input.c
clean:
rm -f myprog main.o display.o input.o
makefile中的变量可以用来代替一些重复出现的字符串,一来更加方便,二来避免重复输入产生书写错误
例如“CC”代表C编译器名,“OBJS”代表“*.o”对象的集合,“prefix”代表安装根目录,$(变量名)
#Sample Makefile with Varivables
CC = gcc
OBJS = main.o display.o input.o
myprog:$(OBJS)
$(CC) $(OBJS) -o myprog
main.o:main.c common.h
$(CC) -c main.c
display.o:display.c common.h
$(CC) -c display.c
input.o:input.h common.h
$(CC) -c input.c
clean:
rm -f myprog $(OBJS)
make的隐含规则:把*.c文件编译成*.o文件,不需要写出来
make可以根据*.o文件自动搜索同名源文件并列为该目标的隐含依赖文件
PHONY目标(伪目标)
target :
commands
如果makefile 所在目录没有target 同名文件:maketarget 则导致commands 总是被执行。
如果makefile 所在目录下存在target 同名文件:maketarget 则commands 不被执行,认为target 总是最新的。
.PHONY:target
target:
commands
不论makefile 所在目录下存不存在与target 同名文件,maketarget 导致commands 的执行,与上一种写法的区别是引用'.PHONY' 的意义所在。
make中的自动参数:
$@
一条规则中的目标名字
$<
依赖文件中的第一个
$?
依赖文件中所有比目标新
$^
所有的依赖文件中,重复出现的名字只保留一个
$+
所有的依赖文件,保持重复出现的名字不变
#Sample Makefile Using Implicit Rules and PHONY
CC = gcc
OBJS = maio.o display.o input.o
myprog:$(OBJS)
$(CC) $(OBJS) -o $@
.PHONY:clean
clean:
-rm -f $@ $(OBJS)
GDB/Insight 调试器的使用"-g"autoconf 和 automake
autoconf和automake配合可以从源代码自动生成makefile
指令 | 解释 | 示例 |
file <文件名> | 加载被调试的可执行程序文件。 因为一般都在被调试程序所在目录下执行GDB,因而文本名不需要带路径。 | (gdb) file gdb-sample |
r | Run的简写,运行被调试的程序。 如果此前没有下过断点,则执行完整个程序;如果有断点,则程序暂停在第一个可用断点处。 | (gdb) r |
c | Continue的简写,继续执行被调试程序,直至下一个断点或程序结束。 | (gdb) c |
b <行号> b <函数名称> b *<函数名称> b *<代码地址> d [编号] | b: Breakpoint的简写,设置断点。两可以使用“行号”“函数名称”“执行地址”等方式指定断点位置。 其中在函数名称前面加“*”符号表示将断点设置在“由编译器生成的prolog代码处”。如果不了解汇编,可以不予理会此用法。 d: Delete breakpoint的简写,删除指定编号的某个断点,或删除所有断点。断点编号从1开始递增。 | (gdb) b 8 (gdb) b main (gdb) b *main (gdb) b *0x804835c (gdb) d |
s, n | s: 执行一行源程序代码,如果此行代码中有函数调用,则进入该函数; n: 执行一行源程序代码,此行代码中的函数调用也一并执行。 s 相当于其它调试器中的“Step Into (单步跟踪进入)”; n 相当于其它调试器中的“Step Over (单步跟踪)”。 这两个命令必须在有源代码调试信息的情况下才可以使用(GCC编译时使用“-g”参数)。 | (gdb) s (gdb) n |
si, ni | si命令类似于s命令,ni命令类似于n命令。所不同的是,这两个命令(si/ni)所针对的是汇编指令,而s/n针对的是源代码。 | (gdb) si (gdb) ni |
p <变量名称> | Print的简写,显示指定变量(临时变量或全局变量)的值。 | (gdb) p i (gdb) p nGlobalVar |
display ... undisplay <编号> | display,设置程序中断后欲显示的数据及其格式。 例如,如果希望每次程序中断后可以看到即将被执行的下一条汇编指令,可以使用命令 “display /i $pc” 其中 $pc 代表当前汇编指令,/i 表示以十六进行显示。当需要关心汇编代码时,此命令相当有用。 undispaly,取消先前的display设置,编号从1开始递增。 | (gdb) display /i $pc (gdb) undisplay 1 |
i | Info的简写,用于显示各类信息,详情请查阅“help i”。 | (gdb) i r |
q | Quit的简写,退出GDB调试环境。 | (gdb) q |
help [命令名称] | GDB帮助命令,提供对GDB名种命令的解释说明。 如果指定了“命令名称”参数,则显示该命令的详细说明;如果没有指定参数,则分类显示所有GDB命令,供用户进一步浏览和查询。 | (gdb) help display |
开发工具:
Eclipse
Kdevelop